diff --git a/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp @@ -21,17 +21,19 @@ cxxConstructorDecl(hasAnyConstructorInitializer(anything())); Finder->addMatcher( - expr(anyOf(cxxFunctionalCastExpr(), cxxBindTemporaryExpr(), - cxxTemporaryObjectExpr()), - hasType(cxxRecordDecl( - isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION")))), - unless(anyOf(hasAncestor(stmt( - anyOf(cxxThrowExpr(), callExpr(), returnStmt()))), - hasAncestor(varDecl()), - allOf(hasAncestor(CtorInitializerList), - unless(hasAncestor(cxxCatchStmt())))))) - .bind("temporary-exception-not-thrown"), - this); + traverse( + TK_AsIs, + expr(anyOf(cxxFunctionalCastExpr(), cxxBindTemporaryExpr(), + cxxTemporaryObjectExpr()), + hasType(cxxRecordDecl( + isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION")))), + unless(anyOf(hasAncestor(stmt(anyOf(cxxThrowExpr(), callExpr(), + returnStmt()))), + hasAncestor(varDecl()), + allOf(hasAncestor(CtorInitializerList), + unless(hasAncestor(cxxCatchStmt())))))) + .bind("temporary-exception-not-thrown")), + this); } void ThrowKeywordMissingCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp @@ -77,7 +77,8 @@ // find the first TypeLoc in the children of E, which always points to the // written type. auto Matches = - match(expr(hasDescendant(typeLoc().bind("t"))), *E, *Result.Context); + match(traverse(TK_AsIs, expr(hasDescendant(typeLoc().bind("t")))), *E, + *Result.Context); const auto *TL = selectFirst("t", Matches); D << FixItHint::CreateInsertion( Lexer::getLocForEndOfToken(TL->getEndLoc(), 0, *Result.SourceManager, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2987,13 +2987,20 @@ auto SR = E->getSourceRange(); + if (auto *Cast = dyn_cast(E)) { + auto *SE = Cast->getSubExpr(); + if (SE->getSourceRange() == SR) + return Cast->getSubExpr(); + } + if (auto *C = dyn_cast(E)) { auto NumArgs = C->getNumArgs(); if (NumArgs == 1 || (NumArgs > 1 && isa(C->getArg(1)))) { Expr *A = C->getArg(0); - if (A->getSourceRange() == SR || !isa(C)) + if (A->getSourceRange() == SR || C->isElidable()) { E = A; + } } } diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -154,8 +154,13 @@ auto SR = Child->getSourceRange(); + if (auto *C = dyn_cast(E)) { + if (C->getSourceRange() == SR) + return true; + } + if (const auto *C = dyn_cast(E)) { - if (C->getSourceRange() == SR || !isa(C)) + if (C->getSourceRange() == SR || C->isElidable()) return true; } diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp --- a/clang/unittests/AST/ASTTraverserTest.cpp +++ b/clang/unittests/AST/ASTTraverserTest.cpp @@ -298,6 +298,34 @@ void actual_template_test() { template_test<4>(); } + +struct OneParamCtor { + explicit OneParamCtor(int); +}; +struct TwoParamCtor { + explicit TwoParamCtor(int, int); +}; + +void varDeclCtors() { + { + auto var1 = OneParamCtor(5); + auto var2 = TwoParamCtor(6, 7); + } + { + OneParamCtor var3(5); + TwoParamCtor var4(6, 7); + } + int i = 0; + { + auto var5 = OneParamCtor(i); + auto var6 = TwoParamCtor(i, 7); + } + { + OneParamCtor var7(i); + TwoParamCtor var8(i, 7); + } +} + )cpp"); { @@ -442,6 +470,145 @@ `-StringLiteral )cpp"); } + + auto varChecker = [&AST](StringRef varName, StringRef SemanticDump, + StringRef SyntacticDump) { + auto FN = ast_matchers::match( + functionDecl( + hasName("varDeclCtors"), + forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))), + AST->getASTContext()); + EXPECT_EQ(FN.size(), 1u); + + EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs("varDeclCtor")), + SemanticDump); + + EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, + FN[0].getNodeAs("varDeclCtor")), + SyntacticDump); + }; + + varChecker("var1", + R"cpp( +VarDecl 'var1' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXFunctionalCastExpr + `-CXXConstructExpr + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var1' +`-CXXConstructExpr + `-IntegerLiteral +)cpp"); + + varChecker("var2", + R"cpp( +VarDecl 'var2' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXTemporaryObjectExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var2' +`-CXXTemporaryObjectExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp"); + + varChecker("var3", + R"cpp( +VarDecl 'var3' +`-CXXConstructExpr + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var3' +`-CXXConstructExpr + `-IntegerLiteral +)cpp"); + + varChecker("var4", + R"cpp( +VarDecl 'var4' +`-CXXConstructExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var4' +`-CXXConstructExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp"); + + varChecker("var5", + R"cpp( +VarDecl 'var5' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXFunctionalCastExpr + `-CXXConstructExpr + `-ImplicitCastExpr + `-DeclRefExpr 'i' +)cpp", + R"cpp( +VarDecl 'var5' +`-CXXConstructExpr + `-DeclRefExpr 'i' +)cpp"); + + varChecker("var6", + R"cpp( +VarDecl 'var6' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXTemporaryObjectExpr + |-ImplicitCastExpr + | `-DeclRefExpr 'i' + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var6' +`-CXXTemporaryObjectExpr + |-DeclRefExpr 'i' + `-IntegerLiteral +)cpp"); + + varChecker("var7", + R"cpp( +VarDecl 'var7' +`-CXXConstructExpr + `-ImplicitCastExpr + `-DeclRefExpr 'i' +)cpp", + R"cpp( +VarDecl 'var7' +`-CXXConstructExpr + `-DeclRefExpr 'i' +)cpp"); + + varChecker("var8", + R"cpp( +VarDecl 'var8' +`-CXXConstructExpr + |-ImplicitCastExpr + | `-DeclRefExpr 'i' + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var8' +`-CXXConstructExpr + |-DeclRefExpr 'i' + `-IntegerLiteral +)cpp"); } TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) { @@ -645,7 +812,7 @@ FunctionDecl 'func3' `-CompoundStmt `-ReturnStmt - `-CXXFunctionalCastExpr + `-CXXConstructExpr `-IntegerLiteral )cpp"; EXPECT_EQ( diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -965,7 +965,7 @@ TEST(FunctionalCast, MatchesSimpleCase) { StringRef foo_class = "class Foo { public: Foo(const char*); };"; EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }", - cxxFunctionalCastExpr())); + traverse(TK_AsIs, cxxFunctionalCastExpr()))); } TEST(FunctionalCast, DoesNotMatchOtherCasts) { diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1891,6 +1891,98 @@ EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, staticAssertDecl(has(integerLiteral()))))); + + Code = R"cpp( + +struct OneParamCtor { + explicit OneParamCtor(int); +}; +struct TwoParamCtor { + explicit TwoParamCtor(int, int); +}; + +void varDeclCtors() { + { + auto var1 = OneParamCtor(5); + auto var2 = TwoParamCtor(6, 7); + } + { + OneParamCtor var3(5); + TwoParamCtor var4(6, 7); + } + int i = 0; + { + auto var5 = OneParamCtor(i); + auto var6 = TwoParamCtor(i, 7); + } + { + OneParamCtor var7(i); + TwoParamCtor var8(i, 7); + } +} + +)cpp"; + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var1"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var2"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var3"), + hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var4"), + hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var5"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var6"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var7"), + hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var8"), + hasInitializer(cxxConstructExpr()))))); + + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var1"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var2"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var3"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var4"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var5"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var6"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var7"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var8"), hasInitializer(cxxConstructExpr()))))); } template @@ -2096,21 +2188,20 @@ forFunction(functionDecl(hasName("func2"))))))))), langCxx20OrLater())); - EXPECT_TRUE(matches( - Code, - traverse( - TK_IgnoreUnlessSpelledInSource, - returnStmt(forFunction(functionDecl(hasName("func3"))), - hasReturnValue(cxxFunctionalCastExpr( - hasSourceExpression(integerLiteral(equals(42))))))), - langCxx20OrLater())); + EXPECT_TRUE( + matches(Code, + traverse(TK_IgnoreUnlessSpelledInSource, + returnStmt(forFunction(functionDecl(hasName("func3"))), + hasReturnValue(cxxConstructExpr(hasArgument( + 0, integerLiteral(equals(42))))))), + langCxx20OrLater())); EXPECT_TRUE(matches( Code, traverse( TK_IgnoreUnlessSpelledInSource, integerLiteral(equals(42), - hasParent(cxxFunctionalCastExpr(hasParent(returnStmt( + hasParent(cxxConstructExpr(hasParent(returnStmt( forFunction(functionDecl(hasName("func3"))))))))), langCxx20OrLater()));