void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) { // FIXME: Support continue, break and throw. Finder->addMatcher( ifStmt( hasThen(stmt(anyOf(returnStmt(), compoundStmt(has(returnStmt()))))), hasElse(stmt().bind("else"))).bind("if"), this); }
void UnconventionalAssignOperatorCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType( pointee(unless(isConstQualified()), anyOf(autoType(), hasDeclaration(equalsBoundNode("class"))))))); const auto IsSelf = qualType( anyOf(hasDeclaration(equalsBoundNode("class")), referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); const auto IsAssign = cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), hasName("operator="), ofClass(recordDecl().bind("class"))) .bind("method"); const auto IsSelfAssign = cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf)))) .bind("method"); Finder->addMatcher( cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"), this); const auto BadSelf = referenceType( anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), rValueReferenceType(pointee(isConstQualified())))); Finder->addMatcher( cxxMethodDecl(IsSelfAssign, hasParameter(0, parmVarDecl(hasType(BadSelf)))) .bind("ArgumentType"), this); Finder->addMatcher( cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"), this); const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts( anyOf(unaryOperator(hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())), cxxOperatorCallExpr(argumentCountIs(1), callee(unresolvedLookupExpr()), hasArgument(0, cxxThisExpr()))))))); const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType); Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign)) .bind("returnStmt"), this); }
TEST_F(OneSubOptimizerTests, EqOpAndXorOpSecOpOfXorIsTenNotOptimized) { // return (a == b) ^ 10; // // Not optimized. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16, true))); ShPtr<Variable> varB(Variable::create("b", IntType::create(16, true))); ShPtr<ConstInt> constInt(ConstInt::create(10, 64)); ShPtr<EqOpExpr> eqOpExpr( EqOpExpr::create( varA, varB )); ShPtr<BitXorOpExpr> returnExpr( BitXorOpExpr::create( eqOpExpr, constInt )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); ShPtr<BitXorOpExpr> outBitXorOpExpr(cast<BitXorOpExpr>(returnStmt->getRetVal())); ASSERT_TRUE(outBitXorOpExpr) << "expected `BitXorOpExpr`, " "got `" << returnStmt->getRetVal() << "`"; ShPtr<EqOpExpr> outEqOpExpr(cast<EqOpExpr>(outBitXorOpExpr->getFirstOperand())); ASSERT_TRUE(outEqOpExpr) << "expected `EqOpExpr`, " "got `" << outBitXorOpExpr->getFirstOperand() << "`"; ShPtr<Variable> outOp1(cast<Variable>(outEqOpExpr->getFirstOperand())); ASSERT_TRUE(outOp1) << "expected `Variable`, " "got `" << outEqOpExpr->getFirstOperand() << "`"; EXPECT_EQ(varA, outOp1) << "expected `" << varA << "`, " "got `" << outOp1 << "`"; ShPtr<Variable> outOp2(cast<Variable>(outEqOpExpr->getSecondOperand())); ASSERT_TRUE(outOp2) << "expected `Variable`, " "got `" << outEqOpExpr->getSecondOperand() << "`"; EXPECT_EQ(varB, outOp2) << "expected `" << varB << "`, " "got `" << outOp2 << "`"; ShPtr<ConstInt> outConstInt(cast<ConstInt>(outBitXorOpExpr->getSecondOperand())); ASSERT_TRUE(outConstInt) << "expected `ConstInt`, " "got `" << outBitXorOpExpr->getSecondOperand() << "`"; EXPECT_EQ(constInt, outConstInt) << "expected `" << constInt << "`, " "got `" << outConstInt << "`"; }
void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) { const auto ControlFlowInterruptorMatcher = stmt(anyOf(returnStmt().bind("return"), continueStmt().bind("continue"), breakStmt().bind("break"), cxxThrowExpr().bind("throw"))); Finder->addMatcher( stmt(forEach( ifStmt(hasThen(stmt( anyOf(ControlFlowInterruptorMatcher, compoundStmt(has(ControlFlowInterruptorMatcher))))), hasElse(stmt().bind("else"))) .bind("if"))), this); }
TEST_F(OneSubOptimizerTests, EqOpWithCastsAndXorOpSecOpOfXorIsOneOptimized) { // return IntToPtr(IntToPtr((a == b))) ^ 1; // // Optimized to retun a != b. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16, true))); ShPtr<Variable> varB(Variable::create("b", IntType::create(16, true))); ShPtr<EqOpExpr> eqOpExpr( EqOpExpr::create( varA, varB )); ShPtr<IntToPtrCastExpr> intToPtrCastExprInner( IntToPtrCastExpr::create( eqOpExpr, IntType::create(16) )); ShPtr<IntToPtrCastExpr> intToPtrCastExprOuter( IntToPtrCastExpr::create( intToPtrCastExprInner, IntType::create(16) )); ShPtr<BitXorOpExpr> returnExpr( BitXorOpExpr::create( intToPtrCastExprOuter, ConstInt::create(1, 64) )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); ShPtr<NeqOpExpr> outNeqOpExpr(cast<NeqOpExpr>(returnStmt->getRetVal())); ASSERT_TRUE(outNeqOpExpr) << "expected `NegOpExpr`, " "got `" << returnStmt->getRetVal() << "`"; ShPtr<Variable> outOp1(cast<Variable>(outNeqOpExpr->getFirstOperand())); ASSERT_TRUE(outOp1) << "expected `Variable`, " "got `" << outNeqOpExpr->getFirstOperand() << "`"; EXPECT_EQ(varA, outOp1) << "expected `" << varA << "`, " "got `" << outOp1 << "`"; ShPtr<Variable> outOp2(cast<Variable>(outNeqOpExpr->getSecondOperand())); ASSERT_TRUE(outOp2) << "expected `Variable`, " "got `" << outNeqOpExpr->getSecondOperand() << "`"; EXPECT_EQ(varB, outOp2) << "expected `" << varB << "`, " "got `" << outOp2 << "`"; }
TEST_F(OneSubOptimizerTests, FirstOpIsOneConstFloatMulOptimized) { // return 1.0 * a; // // Optimized to return a. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16))); ShPtr<MulOpExpr> returnExpr( MulOpExpr::create( ConstFloat::create(llvm::APFloat(1.0)), varA )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); EXPECT_EQ(varA, returnStmt->getRetVal()) << "expected `" << varA << "`, " "got `" << returnStmt << "`"; }
TEST_F(OneSubOptimizerTests, SecOpIsOneConstIntMulOptimized) { // return a * 1; // // Optimized to return a. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16))); ShPtr<MulOpExpr> returnExpr( MulOpExpr::create( varA, ConstInt::create(1, 64) )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); EXPECT_EQ(varA, returnStmt->getRetVal()) << "expected `" << varA << "`, " "got `" << returnStmt << "`"; }
void NonConstParameterCheck::registerMatchers(MatchFinder *Finder) { // Add parameters to Parameters. Finder->addMatcher(parmVarDecl(unless(isInstantiated())).bind("Parm"), this); // C++ constructor. Finder->addMatcher(cxxConstructorDecl().bind("Ctor"), this); // Track unused parameters, there is Wunused-parameter about unused // parameters. Finder->addMatcher(declRefExpr().bind("Ref"), this); // Analyse parameter usage in function. Finder->addMatcher(stmt(anyOf(unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--"))), binaryOperator(), callExpr(), returnStmt(), cxxConstructExpr())) .bind("Mark"), this); Finder->addMatcher(varDecl(hasInitializer(anything())).bind("Mark"), this); }
void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++. if (!getLangOpts().CPlusPlus11) return; // Skip list initialization and constructors with an initializer list. auto ConstructExpr = cxxConstructExpr( unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())), isListInitialization(), hasDescendant(initListExpr()), isInTemplateInstantiation()))) .bind("ctor"); auto CtorAsArgument = materializeTemporaryExpr(anyOf( has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr))))); Finder->addMatcher( functionDecl(isDefinition(), // Declarations don't have return statements. returns(unless(anyOf(builtinType(), autoType()))), hasDescendant(returnStmt(hasReturnValue( has(cxxConstructExpr(has(CtorAsArgument))))))) .bind("fn"), this); }
void MisplacedWideningCastCheck::registerMatchers(MatchFinder *Finder) { const auto Calc = expr(anyOf(binaryOperator( anyOf(hasOperatorName("+"), hasOperatorName("-"), hasOperatorName("*"), hasOperatorName("<<"))), unaryOperator(hasOperatorName("~"))), hasType(isInteger())) .bind("Calc"); const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()), has(ignoringParenImpCasts(Calc))); const auto ImplicitCast = implicitCastExpr(hasImplicitDestinationType(isInteger()), has(ignoringParenImpCasts(Calc))); const auto Cast = expr(anyOf(ExplicitCast, ImplicitCast)).bind("Cast"); Finder->addMatcher(varDecl(hasInitializer(Cast)), this); Finder->addMatcher(returnStmt(hasReturnValue(Cast)), this); Finder->addMatcher(callExpr(hasAnyArgument(Cast)), this); Finder->addMatcher(binaryOperator(hasOperatorName("="), hasRHS(Cast)), this); Finder->addMatcher( binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(Cast)), this); }
#include "ASTUtility.h" StatementMatcher FuncStmtMatcher = compoundStmt( hasParent(functionDecl(returns(pointerType())).bind("functiondecl")), hasDescendant(returnStmt( hasDescendant(declRefExpr().bind("decl")))) ).bind("funcstmt"); class ReturnChecker : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result) { clang::ASTContext *Context = Result.Context; const clang::CompoundStmt *cs = Result.Nodes.getNodeAs<clang::CompoundStmt>("funcstmt"); const clang::FunctionDecl *fd = Result.Nodes.getNodeAs<clang::FunctionDecl>("functiondecl"); const clang::DeclRefExpr *decl = Result.Nodes.getNodeAs<clang::DeclRefExpr>("decl"); if(!cs || !fd || !decl || ASTUtility::IsStmtInSTDFile(cs, Context)) return; if (!clang::VarDecl::classof(decl -> getDecl())) return; const clang::VarDecl *var = static_cast<const clang::VarDecl*>(decl -> getDecl()); if (var -> hasLocalStorage()) ASTUtility::Print(decl, Context, "Rule65"); } }; //@TestNeed static llvm::cl::OptionCategory MyToolCategory("options");