// try to limit the voluminous output a little static std::set<MyFuncInfo> definitionSet; static std::unordered_set<std::string> overridingSet; static std::unordered_set<std::string> nonEmptySet;
class UnnecessaryVirtual: public RecursiveASTVisitor<UnnecessaryVirtual>, public loplugin::Plugin
{ public: explicit UnnecessaryVirtual(loplugin::InstantiationData const & data):
Plugin(data) {}
std::string niceName(const CXXMethodDecl* cxxMethodDecl)
{ while (cxxMethodDecl->getTemplateInstantiationPattern())
cxxMethodDecl = dyn_cast<CXXMethodDecl>(cxxMethodDecl->getTemplateInstantiationPattern()); while (cxxMethodDecl->getInstantiatedFromMemberFunction())
cxxMethodDecl = dyn_cast<CXXMethodDecl>(cxxMethodDecl->getInstantiatedFromMemberFunction());
std::string s = cxxMethodDecl->getReturnType().getCanonicalType().getAsString()
+ " " + cxxMethodDecl->getQualifiedNameAsString() + "("; for (const ParmVarDecl *pParmVarDecl : cxxMethodDecl->parameters()) {
s += pParmVarDecl->getType().getCanonicalType().getAsString();
s += ",";
}
s += ")"; if (cxxMethodDecl->isConst()) {
s += "const";
} return s;
}
bool UnnecessaryVirtual::VisitCXXMethodDecl( const CXXMethodDecl* methodDecl )
{ if (!methodDecl->isVirtual() || methodDecl->isDeleted()) { returntrue;
} // ignore stuff that forms part of the stable URE interface if (isInUnoIncludeFile(methodDecl->getCanonicalDecl())) { returntrue;
}
auto body = methodDecl->getBody(); if (body) { auto compoundStmt = dyn_cast<CompoundStmt>(body); if (!compoundStmt)
MarkRootOverridesNonEmpty(methodDecl->getCanonicalDecl()); elseif (compoundStmt->size() > 0)
MarkRootOverridesNonEmpty(methodDecl->getCanonicalDecl());
}
if (!methodDecl->isThisDeclarationADefinition()) returntrue;
methodDecl = methodDecl->getCanonicalDecl(); if (!methodDecl) returntrue;
std::string aNiceName = niceName(methodDecl);
// for destructors, we need to check if any of the superclass' destructors are virtual if (isa<CXXDestructorDecl>(methodDecl)) { const CXXRecordDecl* cxxRecordDecl = methodDecl->getParent(); if (cxxRecordDecl->getNumBases() == 0) {
definitionSet.insert( { aNiceName, toString( methodDecl->getLocation() ) } ); returntrue;
} for(auto baseSpecifier = cxxRecordDecl->bases_begin();
baseSpecifier != cxxRecordDecl->bases_end(); ++baseSpecifier)
{ if (baseSpecifier->getType()->isRecordType())
{ const CXXRecordDecl* superclassCXXRecordDecl = baseSpecifier->getType()->getAsCXXRecordDecl(); if (superclassCXXRecordDecl->getDestructor())
{
std::string aOverriddenNiceName = niceName(superclassCXXRecordDecl->getDestructor());
overridingSet.insert(aOverriddenNiceName);
}
}
} returntrue;
}
if (methodDecl->size_overridden_methods() == 0) {
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 (compat::isPureVirtual(overriddenMethod)
|| overriddenMethod->size_overridden_methods() == 0)
{
std::string aOverriddenNiceName = niceName(overriddenMethod);
overridingSet.insert(aOverriddenNiceName);
}
}
} returntrue;
}
void UnnecessaryVirtual::MarkRootOverridesNonEmpty( const CXXMethodDecl* methodDecl )
{ if (!methodDecl) return; if (methodDecl->size_overridden_methods() == 0) {
nonEmptySet.insert(niceName(methodDecl)); return;
} for (auto iter = methodDecl->begin_overridden_methods();
iter != methodDecl->end_overridden_methods(); ++iter)
{
MarkRootOverridesNonEmpty(*iter);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.