summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/unnecessaryvirtual.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/unnecessaryvirtual.cxx')
-rw-r--r--compilerplugins/clang/unnecessaryvirtual.cxx136
1 files changed, 58 insertions, 78 deletions
diff --git a/compilerplugins/clang/unnecessaryvirtual.cxx b/compilerplugins/clang/unnecessaryvirtual.cxx
index 1ecc47114a0b..82f91c71f1a7 100644
--- a/compilerplugins/clang/unnecessaryvirtual.cxx
+++ b/compilerplugins/clang/unnecessaryvirtual.cxx
@@ -34,8 +34,19 @@ TODO does not find destructors that don't need to be virtual
namespace {
+struct MyFuncInfo
+{
+ std::string name;
+ std::string sourceLocation;
+
+};
+bool operator < (const MyFuncInfo &lhs, const MyFuncInfo &rhs)
+{
+ return lhs.name < rhs.name;
+}
+
// try to limit the voluminous output a little
-static std::set<std::string> definitionSet;
+static std::set<MyFuncInfo> definitionSet;
static std::set<std::string> overridingSet;
class UnnecessaryVirtual:
@@ -51,8 +62,8 @@ public:
// dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
// writing to the same logfile
std::string output;
- for (const std::string & s : definitionSet)
- output += "definition:\t" + s + "\n";
+ for (const MyFuncInfo & s : definitionSet)
+ output += "definition:\t" + s.name + "\t" + s.sourceLocation + "\n";
for (const std::string & s : overridingSet)
output += "overriding:\t" + s + "\n";
ofstream myfile;
@@ -61,11 +72,12 @@ public:
myfile.close();
}
bool shouldVisitTemplateInstantiations () const { return true; }
+ bool shouldVisitImplicitCode() const { return true; }
bool VisitCXXMethodDecl( const CXXMethodDecl* decl );
- bool VisitCallExpr(CallExpr* );
private:
std::string fullyQualifiedName(const FunctionDecl* functionDecl);
+ std::string toString(SourceLocation loc);
};
std::string niceName(const CXXMethodDecl* functionDecl)
@@ -87,6 +99,16 @@ std::string niceName(const CXXMethodDecl* functionDecl)
std::string UnnecessaryVirtual::fullyQualifiedName(const FunctionDecl* functionDecl)
{
+ if (functionDecl->getInstantiatedFromMemberFunction())
+ functionDecl = functionDecl->getInstantiatedFromMemberFunction();
+ else if (functionDecl->getClassScopeSpecializationPattern())
+ functionDecl = functionDecl->getClassScopeSpecializationPattern();
+// workaround clang-3.5 issue
+#if CLANG_VERSION >= 30600
+ else if (functionDecl->getTemplateInstantiationPattern())
+ functionDecl = functionDecl->getTemplateInstantiationPattern();
+#endif
+
std::string ret = compat::getReturnType(*functionDecl).getCanonicalType().getAsString();
ret += " ";
if (isa<CXXMethodDecl>(functionDecl)) {
@@ -113,110 +135,68 @@ std::string UnnecessaryVirtual::fullyQualifiedName(const FunctionDecl* functionD
bool UnnecessaryVirtual::VisitCXXMethodDecl( const CXXMethodDecl* methodDecl )
{
+ if (ignoreLocation(methodDecl)) {
+ return true;
+ }
+ if (!methodDecl->isThisDeclarationADefinition() ||
+ !methodDecl->isVirtual() ||
+ methodDecl->isDeleted())
+ {
+ return true;
+ }
methodDecl = methodDecl->getCanonicalDecl();
+ // ignore stuff that forms part of the stable URE interface
+ if (isInUnoIncludeFile(methodDecl)) {
+ return true;
+ }
std::string aNiceName = niceName(methodDecl);
// for destructors, we need to check if any of the superclass' destructors are virtual
if (isa<CXXDestructorDecl>(methodDecl)) {
- /* TODO I need to check if the base class has any virtual functions, since overriding
- classes will simply get a compiler-provided virtual destructor by default.
-
- if (!methodDecl->isVirtual() && !methodDecl->isPure()) {
- return true;
+ const CXXRecordDecl* cxxRecordDecl = methodDecl->getParent();
+ if (cxxRecordDecl->getNumBases() == 0) {
+ definitionSet.insert( { aNiceName, toString( methodDecl->getLocation() ) } );
+ return true;
}
- std::set<std::string> overriddenSet;
- const CXXRecordDecl *pRecordDecl = methodDecl->getParent();
- for(auto baseSpecifier = pRecordDecl->bases_begin();
- baseSpecifier != pRecordDecl->bases_end(); ++baseSpecifier)
+ for(auto baseSpecifier = cxxRecordDecl->bases_begin();
+ baseSpecifier != cxxRecordDecl->bases_end(); ++baseSpecifier)
{
if (baseSpecifier->getType()->isRecordType())
{
- const CXXRecordDecl *pSuperclassCXXRecordDecl = baseSpecifier->getType()->getAsCXXRecordDecl();
- if (pSuperclassCXXRecordDecl->getDestructor())
- {
- std::string aOverriddenNiceName = niceName(pSuperclassCXXRecordDecl->getDestructor());
- overriddenSet.insert(aOverriddenNiceName);
- }
+ const CXXRecordDecl* superclassCXXRecordDecl = baseSpecifier->getType()->getAsCXXRecordDecl();
+ std::string aOverriddenNiceName = niceName(superclassCXXRecordDecl->getDestructor());
+ overridingSet.insert(aOverriddenNiceName);
}
}
- if (overriddenSet.empty()) {
- cout << "definition:\t" << aNiceName << endl;
- } else {
- for(std::string s : overriddenSet)
- cout << "overriding:\t" << s << endl;
- }*/
return true;
}
- if (!methodDecl->isVirtual()) {
- return true;
- }
if (methodDecl->size_overridden_methods() == 0) {
- // ignore stuff that forms part of the stable URE interface
- if (isInUnoIncludeFile(methodDecl)) {
- return true;
- }
- // ignore templates and template instantiations,
- // I just cannot get clang to give me decent overriding method data out of them
- if (methodDecl->getParent()->getDescribedClassTemplate()
- || methodDecl->getParent()->getTemplateInstantiationPattern())
- return true;
- if (aNiceName.find("processOpCode2") != std::string::npos)
- {
- methodDecl->dump();
- cout << "definition " << aNiceName << endl;
- }
- definitionSet.insert(aNiceName);
+ definitionSet.insert( { aNiceName, toString( methodDecl->getLocation() ) } );
} else {
for (auto iter = methodDecl->begin_overridden_methods();
iter != methodDecl->end_overridden_methods(); ++iter)
{
const CXXMethodDecl *overriddenMethod = *iter;
// we only care about the first level override to establish that a virtual qualifier was useful.
- if (overriddenMethod->isPure() || overriddenMethod->size_overridden_methods() == 0) {
+ if (overriddenMethod->isPure() || overriddenMethod->size_overridden_methods() == 0)
+ {
std::string aOverriddenNiceName = niceName(overriddenMethod);
overridingSet.insert(aOverriddenNiceName);
- if (aNiceName.find("processOpCode2") != std::string::npos)
- {
- methodDecl->dump();
- cout << "overriding " << aNiceName << endl;
- }
}
- }
+ }
}
return true;
}
-// prevent recursive templates from blowing up the stack
-static std::set<std::string> traversedFunctionSet;
-
-bool UnnecessaryVirtual::VisitCallExpr(CallExpr* expr)
+std::string UnnecessaryVirtual::toString(SourceLocation loc)
{
- // Note that I don't ignore ANYTHING here, because I want to get calls to my code that result
- // from template instantiation deep inside the STL and other external code
-
- FunctionDecl* calleeFunctionDecl = expr->getDirectCallee();
- if (calleeFunctionDecl == nullptr) {
- Expr* callee = expr->getCallee()->IgnoreParenImpCasts();
- DeclRefExpr* dr = dyn_cast<DeclRefExpr>(callee);
- if (dr) {
- calleeFunctionDecl = dyn_cast<FunctionDecl>(dr->getDecl());
- if (calleeFunctionDecl)
- goto gotfunc;
- }
- return true;
- }
-
-gotfunc:
- // if we see a call to a function, it may effectively create new code,
- // if the function is templated. However, if we are inside a template function,
- // calling another function on the same template, the same problem occurs.
- // Rather than tracking all of that, just traverse anything we have not already traversed.
- if (traversedFunctionSet.insert(fullyQualifiedName(calleeFunctionDecl)).second)
- TraverseFunctionDecl(calleeFunctionDecl);
-
- return true;
+ SourceLocation expansionLoc = compiler.getSourceManager().getExpansionLoc( loc );
+ StringRef name = compiler.getSourceManager().getFilename(expansionLoc);
+ std::string sourceLocation = std::string(name.substr(strlen(SRCDIR)+1)) + ":" + std::to_string(compiler.getSourceManager().getSpellingLineNumber(expansionLoc));
+ normalizeDotDotInFilePath(sourceLocation);
+ return sourceLocation;
}