summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2016-10-22 10:04:52 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2016-10-28 12:56:17 +0000
commit8a22bc93e0988188a87c0a787a9b32a7f74da84d (patch)
tree5b0c9bd79ee88be0754687fe552729e8470f5db2 /compilerplugins
parent99fbcffa3d85c00770977e205626493ec2be1883 (diff)
update unnecessaryoverride plugin to find pure forwarding methods
which can be replaced with using declarations. Is there a more efficient way to code the search? Seems to slow the build down a little. Change-Id: I08cda21fa70dce6572e1acc71bf5e6df36bb951f Reviewed-on: https://gerrit.libreoffice.org/30157 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/unnecessaryoverride.cxx93
1 files changed, 86 insertions, 7 deletions
diff --git a/compilerplugins/clang/unnecessaryoverride.cxx b/compilerplugins/clang/unnecessaryoverride.cxx
index b031c50b7b87..7136cc632739 100644
--- a/compilerplugins/clang/unnecessaryoverride.cxx
+++ b/compilerplugins/clang/unnecessaryoverride.cxx
@@ -13,6 +13,7 @@
#include <fstream>
#include <set>
+#include <clang/AST/CXXInheritance.h>
#include "compat.hxx"
#include "plugin.hxx"
@@ -57,6 +58,15 @@ public:
}
bool VisitCXXMethodDecl(const CXXMethodDecl *);
+
+private:
+ const CXXMethodDecl * findOverriddenOrSimilarMethodInSuperclasses(const CXXMethodDecl *);
+ bool BaseCheckCallback(
+ const CXXRecordDecl *BaseDefinition
+ #if CLANG_VERSION < 30800
+ , void *
+ #endif
+ );
};
bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
@@ -64,11 +74,18 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
if (ignoreLocation(methodDecl->getCanonicalDecl()) || !methodDecl->doesThisDeclarationHaveABody()) {
return true;
}
- // if we are overriding more than one method, then this is a disambiguating override
- if (!methodDecl->isVirtual() || methodDecl->size_overridden_methods() != 1
- || (*methodDecl->begin_overridden_methods())->isPure()) {
+ if (isa<CXXConstructorDecl>(methodDecl) || isa<CXXDestructorDecl>(methodDecl)) {
return true;
}
+
+ // if we are overriding more than one method, then this is a disambiguating override
+ if (methodDecl->isVirtual()) {
+ if (methodDecl->size_overridden_methods() != 1
+ || (*methodDecl->begin_overridden_methods())->isPure())
+ {
+ return true;
+ }
+ }
if (dyn_cast<CXXDestructorDecl>(methodDecl)) {
return true;
}
@@ -90,15 +107,16 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
return true;
- const CXXMethodDecl* overriddenMethodDecl = *methodDecl->begin_overridden_methods();
+ const CXXMethodDecl* overriddenMethodDecl = findOverriddenOrSimilarMethodInSuperclasses(methodDecl);
+ if (!overriddenMethodDecl) {
+ return true;
+ }
if (compat::getReturnType(*methodDecl).getCanonicalType()
!= compat::getReturnType(*overriddenMethodDecl).getCanonicalType())
{
return true;
}
- if (methodDecl->getAccess() == AS_public && overriddenMethodDecl->getAccess() == AS_protected)
- return true;
//TODO: check for identical exception specifications
@@ -179,9 +197,10 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
}
report(
- DiagnosticsEngine::Warning, "%0 virtual function just calls %1 parent",
+ DiagnosticsEngine::Warning, "%0%1 function just calls %2 parent",
methodDecl->getSourceRange().getBegin())
<< methodDecl->getAccess()
+ << (methodDecl->isVirtual() ? " virtual" : "")
<< overriddenMethodDecl->getAccess()
<< methodDecl->getSourceRange();
if (methodDecl->getCanonicalDecl()->getLocation() != methodDecl->getLocation()) {
@@ -195,6 +214,66 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
return true;
}
+const CXXMethodDecl* UnnecessaryOverride::findOverriddenOrSimilarMethodInSuperclasses(const CXXMethodDecl* methodDecl)
+{
+ if (methodDecl->isVirtual()) {
+ return *methodDecl->begin_overridden_methods();
+ }
+ if (!methodDecl->getDeclName().isIdentifier()) {
+ return nullptr;
+ }
+
+ std::vector<const CXXMethodDecl*> maSimilarMethods;
+
+ auto BaseMatchesCallback = [&](const CXXBaseSpecifier *cxxBaseSpecifier, CXXBasePath& )
+ {
+ if (cxxBaseSpecifier->getAccessSpecifier() != AS_public && cxxBaseSpecifier->getAccessSpecifier() != AS_protected)
+ return false;
+ if (!cxxBaseSpecifier->getType().getTypePtr())
+ return false;
+ const CXXRecordDecl* baseCXXRecordDecl = cxxBaseSpecifier->getType()->getAsCXXRecordDecl();
+ if (!baseCXXRecordDecl)
+ return false;
+ if (baseCXXRecordDecl->isInvalidDecl())
+ return false;
+ for (const CXXMethodDecl* baseMethod : baseCXXRecordDecl->methods())
+ {
+ if (!baseMethod->getDeclName().isIdentifier() || methodDecl->getName() != baseMethod->getName()) {
+ continue;
+ }
+ if (compat::getReturnType(*methodDecl).getCanonicalType()
+ != compat::getReturnType(*baseMethod).getCanonicalType())
+ {
+ continue;
+ }
+ if (methodDecl->param_size() != baseMethod->param_size())
+ continue;
+ if (methodDecl->getNumParams() != baseMethod->getNumParams())
+ continue;
+ bool bParamsMatch = true;
+ for (unsigned i=0; i<methodDecl->param_size(); ++i)
+ {
+ if (methodDecl->parameters()[i]->getType() != baseMethod->parameters()[i]->getType())
+ {
+ bParamsMatch = false;
+ break;
+ }
+ }
+ if (bParamsMatch)
+ maSimilarMethods.push_back(baseMethod);
+ }
+ return false;
+ };
+
+ CXXBasePaths aPaths;
+ methodDecl->getParent()->lookupInBases(BaseMatchesCallback, aPaths);
+
+ if (maSimilarMethods.size() == 1) {
+ return maSimilarMethods[0];
+ }
+ return nullptr;
+}
+
loplugin::Plugin::Registration< UnnecessaryOverride > X("unnecessaryoverride", true);