diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -3896,8 +3896,8 @@ return false; } -/// Matches if the type location of the declarator decl's type matches -/// the inner matcher. +/// Matches if the type location of the declarator decl, temporary object +/// expression, or functional cast expression matches the inner matcher. /// /// Given /// \code @@ -3905,11 +3905,30 @@ /// \endcode /// declaratorDecl(hasTypeLoc(loc(asString("int")))) /// matches int x -AST_MATCHER_P(DeclaratorDecl, hasTypeLoc, internal::Matcher, Inner) { - if (!Node.getTypeSourceInfo()) +/// +/// \code +/// auto x = int(3); +/// \code +/// cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int")))) +/// matches int(3) +/// +/// \code +/// struct Foo { Foo(int, int); }; +/// auto x = Foo(1, 2); +/// \code +/// cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo")))) +/// matches Foo(1, 2) +AST_POLYMORPHIC_MATCHER_P( + hasTypeLoc, + AST_POLYMORPHIC_SUPPORTED_TYPES(DeclaratorDecl, CXXTemporaryObjectExpr, + CXXFunctionalCastExpr), + internal::Matcher, Inner) { + TypeSourceInfo *source = internal::GetTypeSourceInfo(Node); + if (source == nullptr) { // This happens for example for implicit destructors. return false; - return Inner.matches(Node.getTypeSourceInfo()->getTypeLoc(), Finder, Builder); + } + return Inner.matches(source->getTypeLoc(), Finder, Builder); } /// Matches if the matched type is represented by the given string. diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -135,6 +135,17 @@ return Node.getType(); } +/// Unifies obtaining a `TypeSourceInfo` from different node types. +inline TypeSourceInfo *GetTypeSourceInfo(const DeclaratorDecl &Node) { + return Node.getTypeSourceInfo(); +} +inline TypeSourceInfo *GetTypeSourceInfo(const CXXTemporaryObjectExpr &Node) { + return Node.getTypeSourceInfo(); +} +inline TypeSourceInfo *GetTypeSourceInfo(const CXXFunctionalCastExpr &Node) { + return Node.getTypeInfoAsWritten(); +} + /// Unifies obtaining the FunctionProtoType pointer from both /// FunctionProtoType and FunctionDecl nodes.. inline const FunctionProtoType * 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 @@ -378,12 +378,27 @@ TEST(HasTypeLoc, MatchesDeclaratorDecls) { EXPECT_TRUE(matches("int x;", varDecl(hasName("x"), hasTypeLoc(loc(asString("int")))))); + EXPECT_TRUE(matches("int x(3);", + varDecl(hasName("x"), hasTypeLoc(loc(asString("int")))))); + EXPECT_TRUE( + matches("struct Foo { Foo(int, int); }; Foo x(1, 2);", + varDecl(hasName("x"), hasTypeLoc(loc(asString("struct Foo")))))); // Make sure we don't crash on implicit constructors. EXPECT_TRUE(notMatches("class X {}; X x;", declaratorDecl(hasTypeLoc(loc(asString("int")))))); } +TEST(HasTypeLoc, MatchesCXXFunctionCastExpr) { + EXPECT_TRUE(matches("auto x = int(3);", + cxxFunctionalCastExpr(hasTypeLoc(loc(asString("int")))))); +} + +TEST(HasTypeLoc, MatchesCXXTemporaryObjectExprs) { + EXPECT_TRUE( + matches("struct Foo { Foo(int, int); }; auto x = Foo(1, 2);", + cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("struct Foo")))))); +} TEST(Callee, MatchesDeclarations) { StatementMatcher CallMethodX = callExpr(callee(cxxMethodDecl(hasName("x"))));