// try to limit the voluminous output a little static std::set<MyFieldInfo> definitionSet; static std::set<MyFieldInfo> writeSet; static std::set<MyFieldInfo> readSet;
class UnusedEnumConstants: public loplugin::FilteringPlugin<UnusedEnumConstants>
{ public: explicit UnusedEnumConstants(loplugin::InstantiationData const & data): FilteringPlugin(data) {}
aInfo.parentClass = enumConstantDecl->getType().getAsString();
aInfo.fieldName = enumConstantDecl->getNameAsString(); // sometimes the name (if it's anonymous thing) contains the full path of the build folder, which we don't need
size_t idx = aInfo.fieldName.find(SRCDIR); if (idx != std::string::npos) {
aInfo.fieldName = aInfo.fieldName.replace(idx, strlen(SRCDIR), "");
}
bool UnusedEnumConstants::VisitEnumConstantDecl( const EnumConstantDecl* enumConstantDecl )
{
enumConstantDecl = enumConstantDecl->getCanonicalDecl(); if (ignoreLocation( enumConstantDecl )) { returntrue;
} // ignore stuff that forms part of the stable URE interface if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(enumConstantDecl->getLocation()))) { returntrue;
}
bool UnusedEnumConstants::VisitDeclRefExpr( const DeclRefExpr* declRefExpr )
{ auto enumConstantDecl = dyn_cast<EnumConstantDecl>(declRefExpr->getDecl()); if (!enumConstantDecl) { returntrue;
}
enumConstantDecl = enumConstantDecl->getCanonicalDecl(); if (ignoreLocation(enumConstantDecl)) { returntrue;
} // ignore stuff that forms part of the stable URE interface if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(enumConstantDecl->getLocation()))) { returntrue;
}
walk_up:
child = parent;
parent = getParentStmt(parent); bool bWrite = false; bool bRead = false; bool bDump = false; if (!parent)
{ // Could probably do better here. // Sometimes this is a constructor-initialiser-expression, so just make a pessimistic assumption.
bWrite = true;
} elseif (const CXXOperatorCallExpr * operatorCall = dyn_cast<CXXOperatorCallExpr>(parent))
{ auto oo = operatorCall->getOperator(); if (oo == OO_AmpEqual)
{ // Ignore a common pattern that does not introduce any new information, merely removes // information: foo &= ~Enum6::Top bool found = false; if (auto innerOperatorCall = dyn_cast<CXXOperatorCallExpr>(operatorCall->getArg(1)->IgnoreImplicit()->IgnoreParens()->IgnoreImplicit()))
{
found = innerOperatorCall->getOperator() == OO_Tilde;
} if (!found)
bWrite = true;
} // if assignment op elseif (oo == OO_Equal || oo == OO_StarEqual || oo == OO_SlashEqual || oo == OO_PercentEqual
|| oo == OO_PlusEqual || oo == OO_MinusEqual || oo == OO_LessLessEqual
|| oo == OO_CaretEqual || oo == OO_PipeEqual)
bWrite = true; // else if comparison op elseif (oo == OO_AmpAmp || oo == OO_PipePipe || oo == OO_Subscript
|| oo == OO_Less || oo == OO_Greater || oo == OO_LessEqual || oo == OO_GreaterEqual || oo == OO_EqualEqual || oo == OO_ExclaimEqual)
bRead = true; else goto walk_up;
} elseif (const CXXMemberCallExpr * memberCall = dyn_cast<CXXMemberCallExpr>(parent))
{ // happens a lot with o3tl::typed_flags if (*memberCall->child_begin() == child)
{ if (auto conversionDecl = dyn_cast<CXXConversionDecl>(memberCall->getMethodDecl()))
{ if (conversionDecl->getConversionType()->isSpecificBuiltinType(clang::BuiltinType::Bool))
bRead = true; else goto walk_up;
} else goto walk_up;
} else
bWrite = true;
} elseif (isa<CallExpr>(parent) || isa<InitListExpr>(parent) || isa<ArraySubscriptExpr>(parent)
|| isa<ReturnStmt>(parent) || isa<DeclStmt>(parent)
|| isa<CXXConstructExpr>(parent)
|| isa<CXXThrowExpr>(parent))
{
bWrite = true;
} elseif (isa<CaseStmt>(parent) || isa<SwitchStmt>(parent) || isa<IfStmt>(parent)
|| isa<WhileStmt>(parent) || isa<DoStmt>(parent) || isa<ForStmt>(parent) || isa<DefaultStmt>(parent))
{
bRead = true;
} elseif (const BinaryOperator * binaryOp = dyn_cast<BinaryOperator>(parent))
{ if (BinaryOperator::isAssignmentOp(binaryOp->getOpcode())) {
bWrite = true;
} elseif (BinaryOperator::isComparisonOp(binaryOp->getOpcode())) {
bRead = true;
} else { goto walk_up;
}
} elseif (isa<ConditionalOperator>(parent))
{ goto walk_up;
} elseif (isa<CastExpr>(parent) || isa<UnaryOperator>(parent)
|| isa<ParenExpr>(parent)
|| isa<MaterializeTemporaryExpr>(parent)
|| isa<ExprWithCleanups>(parent)
|| isa<ConstantExpr>(parent)
|| isa<CXXBindTemporaryExpr>(parent))
{ goto walk_up;
} elseif (isa<CXXDefaultArgExpr>(parent))
{ // TODO this could be improved
bWrite = true;
} elseif (isa<DeclRefExpr>(parent))
{ // slightly weird case I saw in basegfx where the enum is being used as a template param
bWrite = true;
} elseif (isa<MemberExpr>(parent))
{ goto walk_up;
} elseif (isa<ParenListExpr>(parent))
{ goto walk_up;
} elseif (isa<CXXDefaultInitExpr>(parent))
{ goto walk_up;
} elseif (isa<UnresolvedLookupExpr>(parent)
|| isa<CompoundStmt>(parent))
{
bRead = true;
bWrite = true;
} else
{
bDump = true;
}
// to let me know if I missed something if (bDump) {
parent->dump();
declRefExpr->dump();
report( DiagnosticsEngine::Warning, "unhandled clang AST node type",
parent->getBeginLoc());
}
if (bWrite) {
writeSet.insert(niceName(enumConstantDecl));
} if (bRead) {
readSet.insert(niceName(enumConstantDecl));
} returntrue;
}
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.