[PATCH] D101572: Make `hasTypeLoc` matcher support nodes of type `CXXFunctionalCastExpr` and `CXXTemporaryObjectExpr`.

2021-04-29 Thread Weston Carvalho via Phabricator via cfe-commits
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`.

2021-04-30 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-04 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-04 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-05 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-05 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-05 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-07 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-10 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-10 Thread Weston Carvalho via Phabricator via cfe-commits
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.

2021-05-11 Thread Weston Carvalho via Phabricator via cfe-commits
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;
+