teach refcounting clang plugin about uno::Reference

uno::Reference is only allowed to used with classes that have a
::static_type member.
So convert all those places to rtl::Reference.

Maybe we need some LIBO_INTERNAL_ONLY constructors on rtl::Reference and
uno::Reference to make this a little smoother?

Change-Id: Icdcb35d71ca40a87b1dc474096776412adbfc7e3
Reviewed-on: https://gerrit.libreoffice.org/25516
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
This commit is contained in:
Noel Grandin
2016-05-26 16:02:39 +02:00
committed by Noel Grandin
parent 88c03cd07a
commit 0b23eec200
77 changed files with 327 additions and 242 deletions

View File

@@ -12,6 +12,7 @@
#include "plugin.hxx"
#include "compat.hxx"
#include "typecheck.hxx"
#include "clang/AST/CXXInheritance.h"
/**
@@ -50,6 +51,7 @@ public:
bool VisitFieldDecl(const FieldDecl *);
bool VisitVarDecl(const VarDecl *);
bool VisitFunctionDecl(const FunctionDecl *);
bool WalkUpFromObjCIvarDecl(ObjCIvarDecl * decl) {
// Don't recurse into WalkUpFromFieldDecl, as VisitFieldDecl calls
@@ -58,6 +60,9 @@ public:
// ObjCIvarDecl.
return VisitObjCIvarDecl(decl);
}
private:
void checkUnoReference(QualType qt, const Decl* decl,
const std::string& rParentName, const std::string& rDeclName);
};
bool BaseCheckNotSubclass(const CXXRecordDecl *BaseDefinition, void *p) {
@@ -287,6 +292,39 @@ bool containsSalhelperReferenceObjectSubclass(const Type* pType0) {
}
}
static bool containsStaticTypeMethod(const CXXRecordDecl* x)
{
for (auto it = x->method_begin(); it != x->method_end(); ++it) {
auto i = *it;
if ( !i->isStatic() )
continue;
auto ident = i->getIdentifier();
if ( ident && ident->isStr("static_type") ) {
return true;
}
}
return false;
}
void RefCounting::checkUnoReference(QualType qt, const Decl* decl, const std::string& rParentName, const std::string& rDeclName)
{
if (loplugin::TypeCheck(qt).Class("Reference").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace()) {
const CXXRecordDecl* pRecordDecl = qt->getAsCXXRecordDecl();
const ClassTemplateSpecializationDecl* pTemplate = dyn_cast<ClassTemplateSpecializationDecl>(pRecordDecl);
const TemplateArgument& rArg = pTemplate->getTemplateArgs()[0];
const CXXRecordDecl* templateParam = rArg.getAsType()->getAsCXXRecordDecl()->getDefinition();
if (templateParam && !containsStaticTypeMethod(templateParam)) {
report(
DiagnosticsEngine::Warning,
"uno::Reference " + rDeclName + " with template parameter that does not contain ::static_type() "
+ qt.getAsString()
+ ", parent is " + rParentName,
decl->getLocation())
<< decl->getSourceRange();
}
}
}
bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) {
if (ignoreLocation(fieldDecl)) {
return true;
@@ -334,6 +372,9 @@ bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) {
fieldDecl->getLocation())
<< fieldDecl->getSourceRange();
}
checkUnoReference(fieldDecl->getType(), fieldDecl, aParentName, "field");
return true;
}
@@ -342,37 +383,51 @@ bool RefCounting::VisitVarDecl(const VarDecl * varDecl) {
if (ignoreLocation(varDecl)) {
return true;
}
if (isa<ParmVarDecl>(varDecl)) {
if (!isa<ParmVarDecl>(varDecl)) {
if (containsSvRefBaseSubclass(varDecl->getType().getTypePtr())) {
report(
DiagnosticsEngine::Warning,
"SvRefBase subclass being directly stack managed, should be managed via tools::SvRef, "
+ varDecl->getType().getAsString(),
varDecl->getLocation())
<< varDecl->getSourceRange();
}
if (containsSalhelperReferenceObjectSubclass(varDecl->getType().getTypePtr())) {
StringRef name { compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(varDecl->getLocation())) };
// this is playing games that it believes is safe
if (name == SRCDIR "/stoc/source/security/permissions.cxx")
return true;
report(
DiagnosticsEngine::Warning,
"salhelper::SimpleReferenceObject subclass being directly stack managed, should be managed via rtl::Reference, "
+ varDecl->getType().getAsString(),
varDecl->getLocation())
<< varDecl->getSourceRange();
}
if (containsXInterfaceSubclass(varDecl->getType())) {
report(
DiagnosticsEngine::Warning,
"XInterface subclass being directly stack managed, should be managed via uno::Reference, "
+ varDecl->getType().getAsString(),
varDecl->getLocation())
<< varDecl->getSourceRange();
}
}
checkUnoReference(varDecl->getType(), varDecl, "", "var");
return true;
}
bool RefCounting::VisitFunctionDecl(const FunctionDecl * functionDecl) {
if (ignoreLocation(functionDecl)) {
return true;
}
if (containsSvRefBaseSubclass(varDecl->getType().getTypePtr())) {
report(
DiagnosticsEngine::Warning,
"SvRefBase subclass being directly stack managed, should be managed via tools::SvRef, "
+ varDecl->getType().getAsString(),
varDecl->getLocation())
<< varDecl->getSourceRange();
}
if (containsSalhelperReferenceObjectSubclass(varDecl->getType().getTypePtr())) {
StringRef name { compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(varDecl->getLocation())) };
// this is playing games that it believes is safe
if (name == SRCDIR "/stoc/source/security/permissions.cxx")
// only consider base declarations, not overriden ones, or we warn on methods that
// are overriding stuff from external libraries
const CXXMethodDecl * methodDecl = dyn_cast<CXXMethodDecl>(functionDecl);
if (methodDecl && methodDecl->size_overridden_methods() > 0) {
return true;
report(
DiagnosticsEngine::Warning,
"salhelper::SimpleReferenceObject subclass being directly stack managed, should be managed via rtl::Reference, "
+ varDecl->getType().getAsString(),
varDecl->getLocation())
<< varDecl->getSourceRange();
}
if (containsXInterfaceSubclass(varDecl->getType())) {
report(
DiagnosticsEngine::Warning,
"XInterface subclass being directly stack managed, should be managed via uno::Reference, "
+ varDecl->getType().getAsString(),
varDecl->getLocation())
<< varDecl->getSourceRange();
}
checkUnoReference(functionDecl->getReturnType(), functionDecl, "", "return");
return true;
}