void MisleadingIndentationCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(ifStmt(hasElse(stmt())).bind("if"), this); Finder->addMatcher( compoundStmt(has(stmt(anyOf(ifStmt(), forStmt(), whileStmt())))) .bind("compound"), this); }
void MustUseChecker::registerMatchers(MatchFinder *AstMatcher) { AstMatcher->addMatcher(switchCase().bind("switchcase"), this); AstMatcher->addMatcher(compoundStmt().bind("compound"), this); AstMatcher->addMatcher(ifStmt().bind("if"), this); AstMatcher->addMatcher(whileStmt().bind("while"), this); AstMatcher->addMatcher(doStmt().bind("do"), this); AstMatcher->addMatcher(forStmt().bind("for"), this); AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"), this); }
TEST_F(TestIRStmt, TestForStmtWithTwoCondStmts) { IRTypes types; IRValue* condVar = new IRLocalVar("cond", types.GetBoolTy(), kIRUniform, NULL); IRStmt* condStmt = MakeBlock(&types, true); IRStmt* iterateStmt = new IRSeq(); IRStmt* body = MakeBlock(&types, true); IRForLoop forStmt(condStmt, condVar, iterateStmt, body, IRPos()); std::cout << forStmt; }
void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; // TODO: This check does not recognize `IndirectGotoStmt` which is a // GNU extension. These must be matched separately and an AST matcher // is currently missing for them. // Check if the 'goto' is used for control flow other than jumping // out of a nested loop. auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt())); auto NestedLoop = stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)), whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop)))); Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)), unless(isForwardJumping()))) .bind("goto"), this); }
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 InefficientStringConcatenationCheck::registerMatchers( MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; const auto BasicStringType = hasType(qualType(hasUnqualifiedDesugaredType(recordType( hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))))); const auto BasicStringPlusOperator = cxxOperatorCallExpr( hasOverloadedOperatorName("+"), hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType)))); const auto PlusOperator = cxxOperatorCallExpr( hasOverloadedOperatorName("+"), hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))), hasDescendant(BasicStringPlusOperator)) .bind("plusOperator"); const auto AssignOperator = cxxOperatorCallExpr( hasOverloadedOperatorName("="), hasArgument(0, declRefExpr(BasicStringType, hasDeclaration(decl().bind("lhsStrT"))) .bind("lhsStr")), hasArgument(1, stmt(hasDescendant(declRefExpr( hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))), hasDescendant(BasicStringPlusOperator)); if (StrictMode) { Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)), this); } else { Finder->addMatcher( cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator), hasAncestor(stmt(anyOf(cxxForRangeStmt(), whileStmt(), forStmt())))), this); } }
TEST_F(TestIRStmt, TestForStmtWithComplexIterStmt) { IRTypes types; IRValue* ifVar = new IRLocalVar("p", types.GetBoolTy(), kIRUniform, NULL); IRStmt* thenStmt = MakeBlock(&types); IRStmt* elseStmt = new IRSeq(); IRIfStmt* ifStmt = new IRIfStmt(ifVar, thenStmt, elseStmt, IRPos()); IRStmts* stmts = new IRStmts; stmts->push_back(ifStmt); stmts->push_back(MakeBlock(&types, true)); IRStmt* seq = new IRSeq(stmts); IRValue* loopVar = new IRLocalVar("cond", types.GetBoolTy(), kIRUniform, NULL); IRStmt* condStmt = new IRSeq(); IRStmt* iterateStmt = seq; IRStmt* body = MakeBlock(&types); IRForLoop forStmt(condStmt, loopVar, iterateStmt, body, IRPos()); std::cout << forStmt; }
StatementMatcher LoopMatcher = forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl( hasInitializer(integerLiteral(equals(0)))))))).bind("forLoop"); class LoopPrinter : public MatchFinder::MatchCallback { public : virtual void run(const MatchFinder::MatchResult &Result) { if (const ForStmt *FS = Result.Nodes.getNodeAs<clang::ForStmt>("forLoop")) FS->dump(); } };
void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) { // Match relational operators. const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!")); const auto ComparisonBinaryOperator = binaryOperator(matchers::isComparisonOperator()); const auto ComparisonOperator = expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator)); // Add the list of known string compare-like functions and add user-defined // functions. std::vector<std::string> FunctionNames = utils::options::parseStringList( (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions) .str()); // Match a call to a string compare functions. const auto FunctionCompareDecl = functionDecl(hasAnyName(std::vector<StringRef>(FunctionNames.begin(), FunctionNames.end()))) .bind("decl"); const auto DirectStringCompareCallExpr = callExpr(hasDeclaration(FunctionCompareDecl)).bind("call"); const auto MacroStringCompareCallExpr = conditionalOperator(anyOf( hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)), hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)))); // The implicit cast is not present in C. const auto StringCompareCallExpr = ignoringParenImpCasts( anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr)); if (WarnOnImplicitComparison) { // Detect suspicious calls to string compare: // 'if (strcmp())' -> 'if (strcmp() != 0)' Finder->addMatcher( stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)), whileStmt(hasCondition(StringCompareCallExpr)), doStmt(hasCondition(StringCompareCallExpr)), forStmt(hasCondition(StringCompareCallExpr)), binaryOperator( anyOf(hasOperatorName("&&"), hasOperatorName("||")), hasEitherOperand(StringCompareCallExpr)))) .bind("missing-comparison"), this); } if (WarnOnLogicalNotComparison) { // Detect suspicious calls to string compared with '!' operator: // 'if (!strcmp())' -> 'if (strcmp() == 0)' Finder->addMatcher(unaryOperator(hasOperatorName("!"), hasUnaryOperand(ignoringParenImpCasts( StringCompareCallExpr))) .bind("logical-not-comparison"), this); } // Detect suspicious cast to an inconsistant type (i.e. not integer type). Finder->addMatcher( implicitCastExpr(unless(hasType(isInteger())), hasSourceExpression(StringCompareCallExpr)) .bind("invalid-conversion"), this); // Detect suspicious operator with string compare function as operand. Finder->addMatcher( binaryOperator( unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"), hasOperatorName("||"), hasOperatorName("="))), hasEitherOperand(StringCompareCallExpr)) .bind("suspicious-operator"), this); // Detect comparison to invalid constant: 'strcmp() == -1'. const auto InvalidLiteral = ignoringParenImpCasts( anyOf(integerLiteral(unless(equals(0))), unaryOperator( hasOperatorName("-"), has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))), characterLiteral(), cxxBoolLiteral())); Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(StringCompareCallExpr), hasEitherOperand(InvalidLiteral)) .bind("invalid-comparison"), this); }
void FloatLoopCounter::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( forStmt(hasIncrement(expr(hasType(realFloatingPointType())))).bind("for"), this); }