From 2253878a40594751eb4d9ea3dd00d3d596836bd2 Mon Sep 17 00:00:00 2001 From: Jonas Toth Date: Tue, 11 Sep 2018 16:09:19 +0000 Subject: [PATCH] [ASTMatchers] add three matchers for dependent expressions Summary: The new matchers can be used to check if an expression is type-, value- or instantiation-dependent in a templated context. These matchers are used in a clang-tidy check and generally useful as the problem of unresolved templates occurs more often in clang-tidy and they provide an easy way to check for this issue. Reviewers: aaron.ballman, alexfh, klimek Reviewed By: aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D51880 llvm-svn: 341958 --- clang/docs/LibASTMatchersReference.html | 40 +++++++++++++++++++++ clang/include/clang/ASTMatchers/ASTMatchers.h | 42 ++++++++++++++++++++++ clang/lib/ASTMatchers/Dynamic/Registry.cpp | 3 ++ .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 42 ++++++++++++++++++++++ 4 files changed, 127 insertions(+) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index ae44662..68a1ab5 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -2758,6 +2758,46 @@ enum class Y {}; +Matcher<Expr>isInstantiationDependent +
Matches expressions that are instantiation-dependent even if it is
+neither type- nor value-dependent.
+
+In the following example, the expression sizeof(sizeof(T() + T()))
+is instantiation-dependent (since it involves a template parameter T),
+but is neither type- nor value-dependent, since the type of the inner
+sizeof is known (std::size_t) and therefore the size of the outer
+sizeof is known.
+  template<typename T>
+  void f(T x, T y) { sizeof(sizeof(T() + T()); }
+expr(isInstantiationDependent()) matches sizeof(sizeof(T() + T())
+
+ + +Matcher<Expr>isTypeDependent +
Matches expressions that are type-dependent because the template type
+is not yet instantiated.
+
+For example, the expressions "x" and "x + y" are type-dependent in
+the following code, but "y" is not type-dependent:
+  template<typename T>
+  void add(T x, int y) {
+    x + y;
+  }
+expr(isTypeDependent()) matches x + y
+
+ + +Matcher<Expr>isValueDependent +
Matches expression that are value-dependent because they contain a
+non-type template parameter.
+
+For example, the array bound of "Chars" in the following example is
+value-dependent.
+  template<int Size> int f() { return Size; }
+expr(isValueDependent()) matches return Size
+
+ + Matcher<FieldDecl>hasBitWidthunsigned Width
Matches non-static data members that are bit-fields of the specified
 bit width.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 25152d9..500d0a6 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -816,6 +816,48 @@ AST_MATCHER_P(QualType, ignoringParens,
   return InnerMatcher.matches(Node.IgnoreParens(), Finder, Builder);
 }
 
+/// Matches expressions that are instantiation-dependent even if it is
+/// neither type- nor value-dependent.
+///
+/// In the following example, the expression sizeof(sizeof(T() + T()))
+/// is instantiation-dependent (since it involves a template parameter T),
+/// but is neither type- nor value-dependent, since the type of the inner
+/// sizeof is known (std::size_t) and therefore the size of the outer
+/// sizeof is known.
+/// \code
+///   template
+///   void f(T x, T y) { sizeof(sizeof(T() + T()); }
+/// \endcode
+/// expr(isInstantiationDependent()) matches sizeof(sizeof(T() + T())
+AST_MATCHER(Expr, isInstantiationDependent) {
+  return Node.isInstantiationDependent();
+}
+
+/// Matches expressions that are type-dependent because the template type
+/// is not yet instantiated.
+///
+/// For example, the expressions "x" and "x + y" are type-dependent in
+/// the following code, but "y" is not type-dependent:
+/// \code
+///   template
+///   void add(T x, int y) {
+///     x + y;
+///   }
+/// \endcode
+/// expr(isTypeDependent()) matches x + y
+AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
+
+/// Matches expression that are value-dependent because they contain a
+/// non-type template parameter.
+///
+/// For example, the array bound of "Chars" in the following example is
+/// value-dependent.
+/// \code
+///   template int f() { return Size; }
+/// \endcode
+/// expr(isValueDependent()) matches return Size
+AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
+
 /// Matches classTemplateSpecializations, templateSpecializationType and
 /// functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
 ///
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 4cf70f9..e2f4adb 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -357,6 +357,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(isExpansionInSystemHeader);
   REGISTER_MATCHER(isInteger);
   REGISTER_MATCHER(isIntegral);
+  REGISTER_MATCHER(isInstantiationDependent);
   REGISTER_MATCHER(isInTemplateInstantiation);
   REGISTER_MATCHER(isLambda);
   REGISTER_MATCHER(isListInitialization);
@@ -376,8 +377,10 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(isStaticStorageClass);
   REGISTER_MATCHER(isStruct);
   REGISTER_MATCHER(isTemplateInstantiation);
+  REGISTER_MATCHER(isTypeDependent);
   REGISTER_MATCHER(isUnion);
   REGISTER_MATCHER(isUnsignedInteger);
+  REGISTER_MATCHER(isValueDependent);
   REGISTER_MATCHER(isVariadic);
   REGISTER_MATCHER(isVirtual);
   REGISTER_MATCHER(isVirtualAsWritten);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index ac73fdf..537ffbb 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1768,6 +1768,48 @@ TEST(IsInTemplateInstantiation, Sharing) {
     Matcher));
 }
 
+TEST(IsInstantiationDependent, MatchesNonValueTypeDependent) {
+  EXPECT_TRUE(matches(
+      "template void f() { (void) sizeof(sizeof(T() + T())); }",
+      expr(isInstantiationDependent())));
+}
+
+TEST(IsInstantiationDependent, MatchesValueDependent) {
+  EXPECT_TRUE(matches("template int f() { return T; }",
+                      expr(isInstantiationDependent())));
+}
+
+TEST(IsInstantiationDependent, MatchesTypeDependent) {
+  EXPECT_TRUE(matches("template T f() { return T(); }",
+                      expr(isInstantiationDependent())));
+}
+
+TEST(IsTypeDependent, MatchesTypeDependent) {
+  EXPECT_TRUE(matches("template T f() { return T(); }",
+                      expr(isTypeDependent())));
+}
+
+TEST(IsTypeDependent, NotMatchesValueDependent) {
+  EXPECT_TRUE(notMatches("template int f() { return T; }",
+                         expr(isTypeDependent())));
+}
+
+TEST(IsValueDependent, MatchesValueDependent) {
+  EXPECT_TRUE(matches("template int f() { return T; }",
+                      expr(isValueDependent())));
+}
+
+TEST(IsValueDependent, MatchesTypeDependent) {
+  EXPECT_TRUE(matches("template T f() { return T(); }",
+                      expr(isValueDependent())));
+}
+
+TEST(IsValueDependent, MatchesInstantiationDependent) {
+  EXPECT_TRUE(matches(
+      "template void f() { (void) sizeof(sizeof(T() + T())); }",
+      expr(isValueDependent())));
+}
+
 TEST(IsExplicitTemplateSpecialization,
      DoesNotMatchPrimaryTemplate) {
   EXPECT_TRUE(notMatches(
-- 
2.7.4