[PATCH] D101572: Make `hasTypeLoc` matcher support nodes of type `CXXFunctionalCastExpr` and `CXXTemporaryObjectExpr`.
SilensAngelusNex created this revision. SilensAngelusNex requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D101572 Files: clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ 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"; Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h === --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ 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 * Index: clang/include/clang/ASTMatchers/ASTMatchers.h === --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ 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. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D101572: Make `hasTypeLoc` matcher support nodes of type `CXXFunctionalCastExpr` and `CXXTemporaryObjectExpr`.
SilensAngelusNex added a comment. Yes, the motivation for adding these is so I can use clang-transformer to refactor a bunch of constructor calls to call a static factory method instead. // Before ns::Foo x(1); auto y = ns::Foo(1, 2); // After auto x = ns::Foo::Make(1); auto y = ns::Foo::Make(1, 2); That refactor only needs `hasTypeInfo` to work on these three node types, but for consistency's sake I'd be happy to add overloads for others as well. I looked at the types in the results of the `grep` you posted; I think it would make sense for `hasTypeInfo` to be able to handle the classes in the first and third groups; do you think that would be reasonable? Pretty sure these should work with `hasTypeInfo`. - TypedefNameDecl (`getTypeSourceInfo`) - CXXBaseSpecifier (`getTypeSourceInfo`) - CXXCtorInitializer (`getTypeSourceInfo`) - ObjCPropertyDecl (`getTypeSourceInfo`) - ClassTemplateSpecializationDecl (`getTypeAsWritten`) - CompoundLiteralExpr (`getTypeSourceInfo`) - ExplicitCastExpr (`getTypeInfoAsWritten`) - CXXTemporaryObjectExpr (`getTypeSourceInfo`) - CXXUnresolvedConstructExpr (`getTypeSourceInfo`) - TemplateArgumentLoc (`getTypeSourceInfo`) These could make sense, but no other matchers exist for nodes of these types: - VarTemplateSpecializationDecl (`getTypeAsWritten`) - OffsetOfExpr (`getTypeSourceInfo`) - ConvertVectorExpr (`getTypeSourceInfo`) - VAArgExpr (`getWrittenTypeInfo`) - CXXScalarValueInitExpr (`getTypeSourceInfo`) These nodes have a method with a different name, but probably still make sense to use with `hasTypeLoc`. - BlockDecl (`getSignatureAsWritten`) - CXXNewExpr (`getAllocatedTypeSourceInfo`) These all have a method that returns a `TypeSourceInfo*`, but seem like they're expressing something different and shouldn't work with `hasTypeInfo`. - EnumDecl (`getIntegerTypeSourceInfo`) - CXXRecordDecl (`getLambdaTypeInfo`) fails if not a lambda - FriendDecl (`getFriendType`) - ObjCMethodDecl (`getReturnTypeSourceInfo`) - ObjCInterfaceDecl (`getSuperClassTInfo`) - UnaryExprOrTypeTraitExpr (`getArgumentTypeInfo`) fails when arg is expr instead of type Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D101572: Make `hasTypeLoc` matcher support more node types.
SilensAngelusNex updated this revision to Diff 342790. SilensAngelusNex retitled this revision from "Make `hasTypeLoc` matcher support nodes of type `CXXFunctionalCastExpr` and `CXXTemporaryObjectExpr`." to "Make `hasTypeLoc` matcher support more node types.". SilensAngelusNex added a comment. Added support for node types in groups #1 and #3. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 Files: clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -11,6 +11,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" #include "gtest/gtest.h" @@ -375,15 +376,104 @@ typedefNameDecl(hasType(asString("foo")), hasName("bar"; } -TEST(HasTypeLoc, MatchesDeclaratorDecls) { +TEST(HasTypeLoc, MatchesBlockDecl) { + EXPECT_TRUE(matchesConditionally( + "auto x = ^int (int a, int b) { return a + b; };", + blockDecl(hasTypeLoc(loc(asString("int (int, int)", true, + {"-fblocks"})); +} + +TEST(HasTypeLoc, MatchesCXXBaseSpecifierAndCtorInitializer) { + llvm::StringRef code = R"cpp( + class Foo {}; + class Bar : public Foo { +Bar() : Foo() {} + }; + )cpp"; + + EXPECT_TRUE(matches( + code, cxxRecordDecl(hasAnyBase(hasTypeLoc(loc(asString("class Foo"))); + EXPECT_TRUE(matches( + code, cxxCtorInitializer(hasTypeLoc(loc(asString("class Foo")); +} + +TEST(HasTypeLoc, MatchesCXXFunctionalCastExpr) { + EXPECT_TRUE(matches("auto x = int(3);", + cxxFunctionalCastExpr(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesCXXNewExpr) { + EXPECT_TRUE(matches("auto* x = new int(3);", + cxxNewExpr(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("class Foo{}; auto* x = new Foo();", + cxxNewExpr(hasTypeLoc(loc(asString("class Foo")); +} + +TEST(HasTypeLoc, MatchesCXXTemporaryObjectExpr) { + EXPECT_TRUE( + matches("struct Foo { Foo(int, int); }; auto x = Foo(1, 2);", + cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("struct Foo")); +} + +TEST(HasTypeLoc, MatchesCXXUnresolvedConstructExpr) { + EXPECT_TRUE( + matches("template T make() { return T(); }", + cxxUnresolvedConstructExpr(hasTypeLoc(loc(asString("T")); +} + +TEST(HasTypeLoc, MatchesClassTemplateSpecializationDecl) { + EXPECT_TRUE(matches( + "template class Foo; template <> class Foo {};", + classTemplateSpecializationDecl(hasTypeLoc(loc(asString("Foo")); +} + +TEST(HasTypeLoc, MatchesCompoundLiteralExpr) { + EXPECT_TRUE( + matches("int* x = (int [2]) { 0, 1 };", + compoundLiteralExpr(hasTypeLoc(loc(asString("int [2]")); +} + +TEST(HasTypeLoc, MatchesDeclaratorDecl) { 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, MatchesExplicitCastExpr) { + EXPECT_TRUE(matches("auto x = (int) 3;", + explicitCastExpr(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("auto x = static_cast(3);", + explicitCastExpr(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesObjCPropertyDecl) { + EXPECT_TRUE(matchesObjC(R"objc( + @interface Foo + @property int enabled; + @end +)objc", + objcPropertyDecl(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesTemplateArgumentLoc) { + EXPECT_TRUE(matches("template class Foo {}; Foo x;", + templateArgumentLoc(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesTypedefNameDecl) { + EXPECT_TRUE(matches("typedef int X;", + typedefNameDecl(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("using X = int;", + typedefNameDecl(hasTypeLoc(loc(asString("int")); +} TEST(Callee, MatchesDeclarations) { StatementMatcher CallMethodX = callExpr(
[PATCH] D101572: Make `hasTypeLoc` matcher support more node types.
SilensAngelusNex added inline comments. Comment at: clang/include/clang/ASTMatchers/ASTMatchersInternal.h:138-150 +template struct disjunction; +template struct disjunction : public T {}; +template struct disjunction { + using type = + typename std::conditional>::type; + static constexpr bool value = type::value; +}; Is there a better way to express this? I was originally using ``` template struct is_one_of { template static constexpr bool value = (std::is_base_of_v || ...); }; ``` but that didn't compile because `is_base_of_v` and fold expressions are C++17 features. Maybe it would be better to just explicitly write out an overload of `GetTypeSourceInfo` for each type? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D101572: Make `hasTypeLoc` matcher support more node types.
SilensAngelusNex updated this revision to Diff 343106. SilensAngelusNex added a comment. Rebase Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 Files: clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -11,6 +11,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" #include "gtest/gtest.h" @@ -375,15 +376,104 @@ typedefNameDecl(hasType(asString("foo")), hasName("bar"; } -TEST(HasTypeLoc, MatchesDeclaratorDecls) { +TEST(HasTypeLoc, MatchesBlockDecl) { + EXPECT_TRUE(matchesConditionally( + "auto x = ^int (int a, int b) { return a + b; };", + blockDecl(hasTypeLoc(loc(asString("int (int, int)", true, + {"-fblocks"})); +} + +TEST(HasTypeLoc, MatchesCXXBaseSpecifierAndCtorInitializer) { + llvm::StringRef code = R"cpp( + class Foo {}; + class Bar : public Foo { +Bar() : Foo() {} + }; + )cpp"; + + EXPECT_TRUE(matches( + code, cxxRecordDecl(hasAnyBase(hasTypeLoc(loc(asString("class Foo"))); + EXPECT_TRUE(matches( + code, cxxCtorInitializer(hasTypeLoc(loc(asString("class Foo")); +} + +TEST(HasTypeLoc, MatchesCXXFunctionalCastExpr) { + EXPECT_TRUE(matches("auto x = int(3);", + cxxFunctionalCastExpr(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesCXXNewExpr) { + EXPECT_TRUE(matches("auto* x = new int(3);", + cxxNewExpr(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("class Foo{}; auto* x = new Foo();", + cxxNewExpr(hasTypeLoc(loc(asString("class Foo")); +} + +TEST(HasTypeLoc, MatchesCXXTemporaryObjectExpr) { + EXPECT_TRUE( + matches("struct Foo { Foo(int, int); }; auto x = Foo(1, 2);", + cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("struct Foo")); +} + +TEST(HasTypeLoc, MatchesCXXUnresolvedConstructExpr) { + EXPECT_TRUE( + matches("template T make() { return T(); }", + cxxUnresolvedConstructExpr(hasTypeLoc(loc(asString("T")); +} + +TEST(HasTypeLoc, MatchesClassTemplateSpecializationDecl) { + EXPECT_TRUE(matches( + "template class Foo; template <> class Foo {};", + classTemplateSpecializationDecl(hasTypeLoc(loc(asString("Foo")); +} + +TEST(HasTypeLoc, MatchesCompoundLiteralExpr) { + EXPECT_TRUE( + matches("int* x = (int [2]) { 0, 1 };", + compoundLiteralExpr(hasTypeLoc(loc(asString("int [2]")); +} + +TEST(HasTypeLoc, MatchesDeclaratorDecl) { 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, MatchesExplicitCastExpr) { + EXPECT_TRUE(matches("auto x = (int) 3;", + explicitCastExpr(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("auto x = static_cast(3);", + explicitCastExpr(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesObjCPropertyDecl) { + EXPECT_TRUE(matchesObjC(R"objc( + @interface Foo + @property int enabled; + @end +)objc", + objcPropertyDecl(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesTemplateArgumentLoc) { + EXPECT_TRUE(matches("template class Foo {}; Foo x;", + templateArgumentLoc(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesTypedefNameDecl) { + EXPECT_TRUE(matches("typedef int X;", + typedefNameDecl(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("using X = int;", + typedefNameDecl(hasTypeLoc(loc(asString("int")); +} TEST(Callee, MatchesDeclarations) { StatementMatcher CallMethodX = callExpr(callee(cxxMethodDecl(hasName("x"; Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h === --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/AS
[PATCH] D101572: Make `hasTypeLoc` matcher support more node types.
SilensAngelusNex updated this revision to Diff 343219. SilensAngelusNex marked 2 inline comments as done. SilensAngelusNex added a comment. Regenerate docs and replace `is_one_of` with `TypeListContainsSuperOf`. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -11,6 +11,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" #include "gtest/gtest.h" @@ -375,15 +376,104 @@ typedefNameDecl(hasType(asString("foo")), hasName("bar"; } -TEST(HasTypeLoc, MatchesDeclaratorDecls) { +TEST(HasTypeLoc, MatchesBlockDecl) { + EXPECT_TRUE(matchesConditionally( + "auto x = ^int (int a, int b) { return a + b; };", + blockDecl(hasTypeLoc(loc(asString("int (int, int)", true, + {"-fblocks"})); +} + +TEST(HasTypeLoc, MatchesCXXBaseSpecifierAndCtorInitializer) { + llvm::StringRef code = R"cpp( + class Foo {}; + class Bar : public Foo { +Bar() : Foo() {} + }; + )cpp"; + + EXPECT_TRUE(matches( + code, cxxRecordDecl(hasAnyBase(hasTypeLoc(loc(asString("class Foo"))); + EXPECT_TRUE(matches( + code, cxxCtorInitializer(hasTypeLoc(loc(asString("class Foo")); +} + +TEST(HasTypeLoc, MatchesCXXFunctionalCastExpr) { + EXPECT_TRUE(matches("auto x = int(3);", + cxxFunctionalCastExpr(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesCXXNewExpr) { + EXPECT_TRUE(matches("auto* x = new int(3);", + cxxNewExpr(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("class Foo{}; auto* x = new Foo();", + cxxNewExpr(hasTypeLoc(loc(asString("class Foo")); +} + +TEST(HasTypeLoc, MatchesCXXTemporaryObjectExpr) { + EXPECT_TRUE( + matches("struct Foo { Foo(int, int); }; auto x = Foo(1, 2);", + cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("struct Foo")); +} + +TEST(HasTypeLoc, MatchesCXXUnresolvedConstructExpr) { + EXPECT_TRUE( + matches("template T make() { return T(); }", + cxxUnresolvedConstructExpr(hasTypeLoc(loc(asString("T")); +} + +TEST(HasTypeLoc, MatchesClassTemplateSpecializationDecl) { + EXPECT_TRUE(matches( + "template class Foo; template <> class Foo {};", + classTemplateSpecializationDecl(hasTypeLoc(loc(asString("Foo")); +} + +TEST(HasTypeLoc, MatchesCompoundLiteralExpr) { + EXPECT_TRUE( + matches("int* x = (int [2]) { 0, 1 };", + compoundLiteralExpr(hasTypeLoc(loc(asString("int [2]")); +} + +TEST(HasTypeLoc, MatchesDeclaratorDecl) { 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, MatchesExplicitCastExpr) { + EXPECT_TRUE(matches("auto x = (int) 3;", + explicitCastExpr(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("auto x = static_cast(3);", + explicitCastExpr(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesObjCPropertyDecl) { + EXPECT_TRUE(matchesObjC(R"objc( + @interface Foo + @property int enabled; + @end +)objc", + objcPropertyDecl(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesTemplateArgumentLoc) { + EXPECT_TRUE(matches("template class Foo {}; Foo x;", + templateArgumentLoc(hasTypeLoc(loc(asString("int")); +} + +TEST(HasTypeLoc, MatchesTypedefNameDecl) { + EXPECT_TRUE(matches("typedef int X;", + typedefNameDecl(hasTypeLoc(loc(asString("int")); + EXPECT_TRUE(matches("using X = int;", + typedefNameDecl(hasTypeLoc(loc(asString("int")); +} TEST(Callee, MatchesDeclarations) { StatementMatcher CallMethodX = callExpr(callee(cxxMethodDecl(hasName("x"; Index: clang/include/clang/ASTMatchers/ASTMatchersInter
[PATCH] D101572: Make `hasTypeLoc` matcher support more node types.
SilensAngelusNex added a comment. Here's my branch on Github: https://github.com/SilensAngelusNex/llvm-project/tree/has-type-info Comment at: clang/include/clang/ASTMatchers/ASTMatchersInternal.h:138-150 +template struct disjunction; +template struct disjunction : public T {}; +template struct disjunction { + using type = + typename std::conditional>::type; + static constexpr bool value = type::value; +}; steveire wrote: > SilensAngelusNex wrote: > > Is there a better way to express this? I was originally using > > > > ``` > > template struct is_one_of { > > template > > static constexpr bool value = (std::is_base_of_v || ...); > > }; > > ``` > > but that didn't compile because `is_base_of_v` and fold expressions are > > C++17 features. > > > > Maybe it would be better to just explicitly write out an overload of > > `GetTypeSourceInfo` for each type? > > I like your c++17 solution too, but given that we have > `TypeListContainsSuperOf` in this file used for this kind of thing, I think > it makes sense to use that. I think this will work: > > ``` > templatestd::enable_if_t ast_matchers::internal::TypeList< > CXXBaseSpecifier, CXXCtorInitializer, CXXTemporaryObjectExpr, > CXXUnresolvedConstructExpr, CompoundLiteralExpr, DeclaratorDecl, > ObjCPropertyDecl, TemplateArgumentLoc, TypedefNameDecl>, > T>::value> > * = nullptr> > ``` > Perfect, thanks! Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D101572: Make `hasTypeLoc` matcher support more node types.
SilensAngelusNex added a comment. I don't have commit access; you can go ahead and submit it. Thanks for the review! Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101572/new/ https://reviews.llvm.org/D101572 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D102185: Widen `name` stencil to support `TypeLoc` nodes.
SilensAngelusNex created this revision. SilensAngelusNex requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D102185 Files: clang/include/clang/Tooling/Transformer/RangeSelector.h clang/lib/Tooling/Transformer/RangeSelector.cpp clang/unittests/Tooling/RangeSelectorTest.cpp Index: clang/unittests/Tooling/RangeSelectorTest.cpp === --- clang/unittests/Tooling/RangeSelectorTest.cpp +++ clang/unittests/Tooling/RangeSelectorTest.cpp @@ -457,6 +457,35 @@ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); } +TEST(RangeSelectorTest, NameOpTypeLoc) { + StringRef Code = R"cc( +namespace ns { +struct Foo { + Foo(); + Foo(int); + Foo(int, int); +}; +} // namespace ns + +ns::Foo a; +auto b = ns::Foo(3); +auto c = ns::Foo(1, 2); + )cc"; + const char *CtorTy = "ctor_ty"; + // Matches declaration of `a` + TestMatch MatchA = matchCode( + Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo")); + // Matches call of Foo(int) + TestMatch MatchB = matchCode( + Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo")); + // Matches call of Foo(int, int) + TestMatch MatchC = matchCode( + Code, cxxTemporaryObjectExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchC), HasValue("Foo")); +} + TEST(RangeSelectorTest, NameOpErrors) { EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")), Failed(withUnboundNodeMessage())); Index: clang/lib/Tooling/Transformer/RangeSelector.cpp === --- clang/lib/Tooling/Transformer/RangeSelector.cpp +++ clang/lib/Tooling/Transformer/RangeSelector.cpp @@ -8,6 +8,7 @@ #include "clang/Tooling/Transformer/RangeSelector.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" @@ -228,6 +229,14 @@ SourceLocation L = I->getMemberLocation(); return CharSourceRange::getTokenRange(L, L); } +if (const auto *T = Node.get()) { + TypeLoc Loc = *T; + auto ET = T->getAs(); + if (!ET.isNull()) { +Loc = ET.getNamedTypeLoc(); + } + return CharSourceRange::getTokenRange(Loc.getSourceRange()); +} return typeError(ID, Node.getNodeKind(), "DeclRefExpr, NamedDecl, CXXCtorInitializer"); }; Index: clang/include/clang/Tooling/Transformer/RangeSelector.h === --- clang/include/clang/Tooling/Transformer/RangeSelector.h +++ clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -73,9 +73,9 @@ /// binding in the match result. RangeSelector member(std::string ID); -/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr or \c -/// CxxCtorInitializer) selects the name's token. Only selects the final -/// identifier of a qualified name, but not any qualifiers or template +/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr, \c +/// CxxCtorInitializer, and \c TypeLoc) selects the name's token. Only selects\ +/// the final identifier of a qualified name, but not any qualifiers or template /// arguments. For example, for `::foo::bar::baz` and `::foo::bar::baz`, /// it selects only `baz`. /// Index: clang/unittests/Tooling/RangeSelectorTest.cpp === --- clang/unittests/Tooling/RangeSelectorTest.cpp +++ clang/unittests/Tooling/RangeSelectorTest.cpp @@ -457,6 +457,35 @@ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); } +TEST(RangeSelectorTest, NameOpTypeLoc) { + StringRef Code = R"cc( +namespace ns { +struct Foo { + Foo(); + Foo(int); + Foo(int, int); +}; +} // namespace ns + +ns::Foo a; +auto b = ns::Foo(3); +auto c = ns::Foo(1, 2); + )cc"; + const char *CtorTy = "ctor_ty"; + // Matches declaration of `a` + TestMatch MatchA = matchCode( + Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo")); + // Matches call of Foo(int) + TestMatch MatchB = matchCode( + Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo")); + // Matches call of Foo(int, int) + TestMatch MatchC = matchCode( + Code, cxxTemporaryObjectExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchC), HasValue("Foo")); +} + TEST(RangeSelector
[PATCH] D102185: Widen `name` stencil to support `TypeLoc` nodes.
SilensAngelusNex updated this revision to Diff 344132. SilensAngelusNex added a comment. Fix typo in `name`'s doc comment and add `TypeLoc` to the list of expected types in `name`'s `typeError`. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D102185/new/ https://reviews.llvm.org/D102185 Files: clang/include/clang/Tooling/Transformer/RangeSelector.h clang/lib/Tooling/Transformer/RangeSelector.cpp clang/unittests/Tooling/RangeSelectorTest.cpp Index: clang/unittests/Tooling/RangeSelectorTest.cpp === --- clang/unittests/Tooling/RangeSelectorTest.cpp +++ clang/unittests/Tooling/RangeSelectorTest.cpp @@ -457,6 +457,35 @@ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); } +TEST(RangeSelectorTest, NameOpTypeLoc) { + StringRef Code = R"cc( +namespace ns { +struct Foo { + Foo(); + Foo(int); + Foo(int, int); +}; +} // namespace ns + +ns::Foo a; +auto b = ns::Foo(3); +auto c = ns::Foo(1, 2); + )cc"; + const char *CtorTy = "ctor_ty"; + // Matches declaration of `a` + TestMatch MatchA = matchCode( + Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo")); + // Matches call of Foo(int) + TestMatch MatchB = matchCode( + Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo")); + // Matches call of Foo(int, int) + TestMatch MatchC = matchCode( + Code, cxxTemporaryObjectExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchC), HasValue("Foo")); +} + TEST(RangeSelectorTest, NameOpErrors) { EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")), Failed(withUnboundNodeMessage())); Index: clang/lib/Tooling/Transformer/RangeSelector.cpp === --- clang/lib/Tooling/Transformer/RangeSelector.cpp +++ clang/lib/Tooling/Transformer/RangeSelector.cpp @@ -8,6 +8,7 @@ #include "clang/Tooling/Transformer/RangeSelector.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" @@ -228,8 +229,16 @@ SourceLocation L = I->getMemberLocation(); return CharSourceRange::getTokenRange(L, L); } +if (const auto *T = Node.get()) { + TypeLoc Loc = *T; + auto ET = T->getAs(); + if (!ET.isNull()) { +Loc = ET.getNamedTypeLoc(); + } + return CharSourceRange::getTokenRange(Loc.getSourceRange()); +} return typeError(ID, Node.getNodeKind(), - "DeclRefExpr, NamedDecl, CXXCtorInitializer"); + "DeclRefExpr, NamedDecl, CXXCtorInitializer, TypeLoc"); }; } Index: clang/include/clang/Tooling/Transformer/RangeSelector.h === --- clang/include/clang/Tooling/Transformer/RangeSelector.h +++ clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -73,9 +73,9 @@ /// binding in the match result. RangeSelector member(std::string ID); -/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr or \c -/// CxxCtorInitializer) selects the name's token. Only selects the final -/// identifier of a qualified name, but not any qualifiers or template +/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr, \c +/// CxxCtorInitializer, and \c TypeLoc) selects the name's token. Only selects +/// the final identifier of a qualified name, but not any qualifiers or template /// arguments. For example, for `::foo::bar::baz` and `::foo::bar::baz`, /// it selects only `baz`. /// Index: clang/unittests/Tooling/RangeSelectorTest.cpp === --- clang/unittests/Tooling/RangeSelectorTest.cpp +++ clang/unittests/Tooling/RangeSelectorTest.cpp @@ -457,6 +457,35 @@ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); } +TEST(RangeSelectorTest, NameOpTypeLoc) { + StringRef Code = R"cc( +namespace ns { +struct Foo { + Foo(); + Foo(int); + Foo(int, int); +}; +} // namespace ns + +ns::Foo a; +auto b = ns::Foo(3); +auto c = ns::Foo(1, 2); + )cc"; + const char *CtorTy = "ctor_ty"; + // Matches declaration of `a` + TestMatch MatchA = matchCode( + Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo")); + // Matches call of Foo(int) + TestMatch MatchB = matchCode( + Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo")); + // Matches call of Foo(int, int) + TestMatch MatchC
[PATCH] D102185: Widen `name` stencil to support `TypeLoc` nodes.
SilensAngelusNex updated this revision to Diff 344486. SilensAngelusNex added a comment. `T->` => `Loc.` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D102185/new/ https://reviews.llvm.org/D102185 Files: clang/include/clang/Tooling/Transformer/RangeSelector.h clang/lib/Tooling/Transformer/RangeSelector.cpp clang/unittests/Tooling/RangeSelectorTest.cpp Index: clang/unittests/Tooling/RangeSelectorTest.cpp === --- clang/unittests/Tooling/RangeSelectorTest.cpp +++ clang/unittests/Tooling/RangeSelectorTest.cpp @@ -457,6 +457,35 @@ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); } +TEST(RangeSelectorTest, NameOpTypeLoc) { + StringRef Code = R"cc( +namespace ns { +struct Foo { + Foo(); + Foo(int); + Foo(int, int); +}; +} // namespace ns + +ns::Foo a; +auto b = ns::Foo(3); +auto c = ns::Foo(1, 2); + )cc"; + const char *CtorTy = "ctor_ty"; + // Matches declaration of `a` + TestMatch MatchA = matchCode( + Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo")); + // Matches call of Foo(int) + TestMatch MatchB = matchCode( + Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo")); + // Matches call of Foo(int, int) + TestMatch MatchC = matchCode( + Code, cxxTemporaryObjectExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchC), HasValue("Foo")); +} + TEST(RangeSelectorTest, NameOpErrors) { EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")), Failed(withUnboundNodeMessage())); Index: clang/lib/Tooling/Transformer/RangeSelector.cpp === --- clang/lib/Tooling/Transformer/RangeSelector.cpp +++ clang/lib/Tooling/Transformer/RangeSelector.cpp @@ -8,6 +8,7 @@ #include "clang/Tooling/Transformer/RangeSelector.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" @@ -228,8 +229,16 @@ SourceLocation L = I->getMemberLocation(); return CharSourceRange::getTokenRange(L, L); } +if (const auto *T = Node.get()) { + TypeLoc Loc = *T; + auto ET = Loc.getAs(); + if (!ET.isNull()) { +Loc = ET.getNamedTypeLoc(); + } + return CharSourceRange::getTokenRange(Loc.getSourceRange()); +} return typeError(ID, Node.getNodeKind(), - "DeclRefExpr, NamedDecl, CXXCtorInitializer"); + "DeclRefExpr, NamedDecl, CXXCtorInitializer, TypeLoc"); }; } Index: clang/include/clang/Tooling/Transformer/RangeSelector.h === --- clang/include/clang/Tooling/Transformer/RangeSelector.h +++ clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -73,9 +73,9 @@ /// binding in the match result. RangeSelector member(std::string ID); -/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr or \c -/// CxxCtorInitializer) selects the name's token. Only selects the final -/// identifier of a qualified name, but not any qualifiers or template +/// Given a node with a "name", (like \c NamedDecl, \c DeclRefExpr, \c +/// CxxCtorInitializer, and \c TypeLoc) selects the name's token. Only selects +/// the final identifier of a qualified name, but not any qualifiers or template /// arguments. For example, for `::foo::bar::baz` and `::foo::bar::baz`, /// it selects only `baz`. /// Index: clang/unittests/Tooling/RangeSelectorTest.cpp === --- clang/unittests/Tooling/RangeSelectorTest.cpp +++ clang/unittests/Tooling/RangeSelectorTest.cpp @@ -457,6 +457,35 @@ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); } +TEST(RangeSelectorTest, NameOpTypeLoc) { + StringRef Code = R"cc( +namespace ns { +struct Foo { + Foo(); + Foo(int); + Foo(int, int); +}; +} // namespace ns + +ns::Foo a; +auto b = ns::Foo(3); +auto c = ns::Foo(1, 2); + )cc"; + const char *CtorTy = "ctor_ty"; + // Matches declaration of `a` + TestMatch MatchA = matchCode( + Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo")); + // Matches call of Foo(int) + TestMatch MatchB = matchCode( + Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy; + EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo")); + // Matches call of Foo(int, int) + TestMatch MatchC = matchCode( + Code, cxxTemporaryObjectExpr(hasTypeLoc(typeLoc().bind(CtorTy; +