void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus17) return; std::string MatchText = "::std::uncaught_exception"; // Using declaration: warning and fix-it. Finder->addMatcher( usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(hasName(MatchText)))) .bind("using_decl"), this); // DeclRefExpr: warning, no fix-it. Finder->addMatcher(declRefExpr(allOf(to(functionDecl(hasName(MatchText))), unless(callExpr()))) .bind("decl_ref_expr"), this); // CallExpr: warning, fix-it. Finder->addMatcher( callExpr(allOf(hasDeclaration(functionDecl(hasName(MatchText))), unless(hasAncestor(initListExpr())))) .bind("call_expr"), this); // CallExpr in initialisation list: warning, fix-it with avoiding narrowing // conversions. Finder->addMatcher( callExpr(allOf(hasAncestor(initListExpr()), hasDeclaration(functionDecl(hasName(MatchText))))) .bind("init_call_expr"), this); }
TEST(InitListExpr, VectorLiteralInitListParens) { RangeVerifier<InitListExpr> Verifier; Verifier.expectRange(2, 26, 2, 31); EXPECT_TRUE(Verifier.match( "typedef int int2 __attribute__((ext_vector_type(2)));\n" "constant int2 i2 = (int2)(1, 2);", initListExpr(), Lang_OpenCL)); }
TEST(InitListExpr, VectorLiteralListBraceRange) { RangeVerifier<InitListExpr> Verifier; Verifier.expectRange(2, 17, 2, 22); EXPECT_TRUE(Verifier.match( "typedef int int2 __attribute__((ext_vector_type(2)));\n" "int2 i2 = (int2){1, 2};", initListExpr())); }
void SuspiciousMissingCommaCheck::registerMatchers(MatchFinder *Finder) { const auto ConcatenatedStringLiteral = stringLiteral(isConcatenatedLiteral(MaxConcatenatedTokens)).bind("str"); const auto StringsInitializerList = initListExpr(hasType(constantArrayType()), has(ignoringParenImpCasts(expr(ConcatenatedStringLiteral)))); Finder->addMatcher(StringsInitializerList.bind("list"), this); }
void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus11) return; // FIXME: Bunch of functionality that could be easily added: // + add handling of `push_front` for std::forward_list, std::list // and std::deque. // + add handling of `push` for std::stack, std::queue, std::priority_queue // + add handling of `insert` for stl associative container, but be careful // because this requires special treatment (it could cause performance // regression) // + match for emplace calls that should be replaced with insertion // + match for make_pair calls. auto callPushBack = cxxMemberCallExpr( hasDeclaration(functionDecl(hasName("push_back"))), on(hasType(cxxRecordDecl(hasAnyName("std::vector", "llvm::SmallVector", "std::list", "std::deque"))))); // We can't replace push_backs of smart pointer because // if emplacement fails (f.e. bad_alloc in vector) we will have leak of // passed pointer because smart pointer won't be constructed // (and destructed) as in push_back case. auto isCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl( ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr", "std::auto_ptr", "std::weak_ptr")))); // Bitfields binds only to consts and emplace_back take it by universal ref. auto bitFieldAsArgument = hasAnyArgument(ignoringParenImpCasts( memberExpr(hasDeclaration(fieldDecl(matchers::isBitfield()))))); // We could have leak of resource. auto newExprAsArgument = hasAnyArgument(ignoringParenImpCasts(cxxNewExpr())); auto constructingDerived = hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase))); auto hasInitList = has(ignoringParenImpCasts(initListExpr())); auto soughtConstructExpr = cxxConstructExpr( unless(anyOf(isCtorOfSmartPtr, hasInitList, bitFieldAsArgument, newExprAsArgument, constructingDerived, has(materializeTemporaryExpr(hasInitList))))) .bind("ctor"); auto hasConstructExpr = has(ignoringParenImpCasts(soughtConstructExpr)); auto ctorAsArgument = materializeTemporaryExpr( anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr)))); Finder->addMatcher( cxxMemberCallExpr(callPushBack, has(ctorAsArgument)).bind("call"), 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); }
/// Returns `true` if `Node` is a value which evaluates to a literal `0`. bool IsLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node) { auto ZeroMatcher = anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0))); // Check to see if we're using a zero directly. if (selectFirst<const clang::Expr>( "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node, *Result.Context)) != nullptr) return true; // Now check to see if we're using a functional cast with a scalar // initializer expression, e.g. `int{0}`. if (selectFirst<const clang::Expr>( "val", match(cxxFunctionalCastExpr( hasDestinationType( anyOf(isInteger(), realFloatingPointType())), hasSourceExpression(initListExpr( hasInit(0, ignoringParenImpCasts(ZeroMatcher))))) .bind("val"), Node, *Result.Context)) != nullptr) return true; return false; }
void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus11) return; // FIXME: Bunch of functionality that could be easily added: // + add handling of `push_front` for std::forward_list, std::list // and std::deque. // + add handling of `push` for std::stack, std::queue, std::priority_queue // + add handling of `insert` for stl associative container, but be careful // because this requires special treatment (it could cause performance // regression) // + match for emplace calls that should be replaced with insertion // + match for make_pair calls. auto callPushBack = cxxMemberCallExpr( hasDeclaration(functionDecl(hasName("push_back"))), on(hasType(cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>( ContainersWithPushBack.begin(), ContainersWithPushBack.end())))))); // We can't replace push_backs of smart pointer because // if emplacement fails (f.e. bad_alloc in vector) we will have leak of // passed pointer because smart pointer won't be constructed // (and destructed) as in push_back case. auto isCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName( SmallVector<StringRef, 5>(SmartPointers.begin(), SmartPointers.end()))))); // Bitfields binds only to consts and emplace_back take it by universal ref. auto bitFieldAsArgument = hasAnyArgument( ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField()))))); // Initializer list can't be passed to universal reference. auto initializerListAsArgument = hasAnyArgument( ignoringImplicit(cxxConstructExpr(isListInitialization()))); // We could have leak of resource. auto newExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr())); // We would call another constructor. auto constructingDerived = hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase))); // emplace_back can't access private constructor. auto isPrivateCtor = hasDeclaration(cxxConstructorDecl(isPrivate())); auto hasInitList = has(ignoringImplicit(initListExpr())); // FIXME: Discard 0/NULL (as nullptr), static inline const data members, // overloaded functions and template names. auto soughtConstructExpr = cxxConstructExpr( unless(anyOf(isCtorOfSmartPtr, hasInitList, bitFieldAsArgument, initializerListAsArgument, newExprAsArgument, constructingDerived, isPrivateCtor))) .bind("ctor"); auto hasConstructExpr = has(ignoringImplicit(soughtConstructExpr)); auto ctorAsArgument = materializeTemporaryExpr( anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr)))); Finder->addMatcher(cxxMemberCallExpr(callPushBack, has(ctorAsArgument), unless(isInTemplateInstantiation())) .bind("call"), this); }