RelationConstructionVisitor::RelationConstructionVisitor( SymbolsMapType &symbols) : mSymbols(symbols) { Matcher.addMatcher( functionDecl( forEachDescendant( declRefExpr().bind("declRefExpr"))).bind("functionDecl"), &gDeclRefExprHandler); }
void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( functionDecl( unless(isInstantiated()), forEachDescendant( stmt(unless(compoundStmt()), hasParent(stmt(anyOf(compoundStmt(), ifStmt(), anyOf(whileStmt(), doStmt(), forRangeStmt(), forStmt()))))) .bind("stmt"))).bind("func"), this); }
void UnusedParametersCheck::warnOnUnusedParameter( const MatchFinder::MatchResult &Result, const FunctionDecl *Function, unsigned ParamIndex) { const auto *Param = Function->getParamDecl(ParamIndex); auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused") << Param->getName(); auto UsedByRef = [&] { return !ast_matchers::match( decl(hasDescendant( declRefExpr(to(equalsNode(Function)), unless(hasAncestor( callExpr(callee(equalsNode(Function)))))))), *Result.Context->getTranslationUnitDecl(), *Result.Context) .empty(); }; // Comment out parameter name for non-local functions. if (Function->isExternallyVisible() || !Result.SourceManager->isInMainFile(Function->getLocation()) || UsedByRef()) { SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd()); // Note: We always add a space before the '/*' to not accidentally create a // '*/*' for pointer types, which doesn't start a comment. clang-format will // clean this up afterwards. MyDiag << FixItHint::CreateReplacement( RemovalRange, (Twine(" /*") + Param->getName() + "*/").str()); return; } // Fix all redeclarations. for (const FunctionDecl *FD : Function->redecls()) if (FD->param_size()) MyDiag << removeParameter(FD, ParamIndex); // Fix all call sites. auto CallMatches = ast_matchers::match( decl(forEachDescendant( callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))), *Result.Context->getTranslationUnitDecl(), *Result.Context); for (const auto &Match : CallMatches) MyDiag << removeArgument(Match.getNodeAs<CallExpr>("x"), ParamIndex); }
void UnusedParametersCheck::warnOnUnusedParameter( const MatchFinder::MatchResult &Result, const FunctionDecl *Function, unsigned ParamIndex) { const auto *Param = Function->getParamDecl(ParamIndex); auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused") << Param->getName(); auto UsedByRef = [&] { return !ast_matchers::match( decl(hasDescendant( declRefExpr(to(equalsNode(Function)), unless(hasAncestor( callExpr(callee(equalsNode(Function)))))))), *Result.Context->getTranslationUnitDecl(), *Result.Context) .empty(); }; // Comment out parameter name for non-local functions. if ((Function->isExternallyVisible() && Function->getStorageClass() != StorageClass::SC_Static) || UsedByRef()) { SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd()); MyDiag << FixItHint::CreateReplacement( RemovalRange, (Twine(" /*") + Param->getName() + "*/").str()); return; } // Fix all redeclarations. for (const FunctionDecl *FD : Function->redecls()) MyDiag << removeParameter(FD, ParamIndex); // Fix all call sites. auto CallMatches = ast_matchers::match( decl(forEachDescendant( callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))), *Result.Context->getTranslationUnitDecl(), *Result.Context); for (const auto &Match : CallMatches) MyDiag << removeArgument(Match.getNodeAs<CallExpr>("x"), ParamIndex); }