[ASTMatchers] Fix traversal matchers with explicit and defaulted methods
authorStephen Kelly <steveire@gmail.com>
Sat, 26 Dec 2020 16:22:32 +0000 (16:22 +0000)
committerStephen Kelly <steveire@gmail.com>
Tue, 5 Jan 2021 15:22:21 +0000 (15:22 +0000)
Differential Revision: https://reviews.llvm.org/D94030

clang/include/clang/ASTMatchers/ASTMatchers.h
clang/include/clang/ASTMatchers/ASTMatchersInternal.h
clang/lib/ASTMatchers/ASTMatchFinder.cpp
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

index ba2dd86..a45e083 100644 (file)
@@ -5490,6 +5490,9 @@ AST_MATCHER(FunctionDecl, isVariadic) {
 /// \endcode
 AST_MATCHER_P(CXXMethodDecl, ofClass,
               internal::Matcher<CXXRecordDecl>, InnerMatcher) {
+
+  ASTChildrenNotSpelledInSourceScope RAII(Finder, false);
+
   const CXXRecordDecl *Parent = Node.getParent();
   return (Parent != nullptr &&
           InnerMatcher.matches(*Parent, Finder, Builder));
@@ -7037,6 +7040,9 @@ AST_MATCHER_P(FunctionDecl, hasExplicitSpecifier, internal::Matcher<Expr>,
   ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(&Node);
   if (!ES.getExpr())
     return false;
+
+  ASTChildrenNotSpelledInSourceScope RAII(Finder, false);
+
   return InnerMatcher.matches(*ES.getExpr(), Finder, Builder);
 }
 
index f49728d..39b3a84 100644 (file)
@@ -742,6 +742,24 @@ protected:
                                  const DynTypedMatcher &Matcher,
                                  BoundNodesTreeBuilder *Builder,
                                  AncestorMatchMode MatchMode) = 0;
+private:
+  friend struct ASTChildrenNotSpelledInSourceScope;
+  virtual bool isMatchingChildrenNotSpelledInSource() const = 0;
+  virtual void setMatchingChildrenNotSpelledInSource(bool Set) = 0;
+};
+
+struct ASTChildrenNotSpelledInSourceScope {
+  ASTChildrenNotSpelledInSourceScope(ASTMatchFinder *V, bool B)
+      : MV(V), MB(V->isMatchingChildrenNotSpelledInSource()) {
+    V->setMatchingChildrenNotSpelledInSource(B);
+  }
+  ~ASTChildrenNotSpelledInSourceScope() {
+    MV->setMatchingChildrenNotSpelledInSource(MB);
+  }
+
+private:
+  ASTMatchFinder *MV;
+  bool MB;
 };
 
 /// Specialization of the conversion functions for QualType.
index af21e22..54dc874 100644 (file)
@@ -666,6 +666,13 @@ public:
   bool IsMatchingInASTNodeNotSpelledInSource() const override {
     return TraversingASTNodeNotSpelledInSource;
   }
+  bool isMatchingChildrenNotSpelledInSource() const override {
+    return TraversingASTChildrenNotSpelledInSource;
+  }
+  void setMatchingChildrenNotSpelledInSource(bool Set) override {
+    TraversingASTChildrenNotSpelledInSource = Set;
+  }
+
   bool IsMatchingInASTNodeNotAsIs() const override {
     return TraversingASTNodeNotAsIs;
   }
@@ -719,20 +726,6 @@ private:
     bool MB;
   };
 
-  struct ASTChildrenNotSpelledInSource {
-    ASTChildrenNotSpelledInSource(MatchASTVisitor *V, bool B)
-        : MV(V), MB(V->TraversingASTChildrenNotSpelledInSource) {
-      V->TraversingASTChildrenNotSpelledInSource = B;
-    }
-    ~ASTChildrenNotSpelledInSource() {
-      MV->TraversingASTChildrenNotSpelledInSource = MB;
-    }
-
-  private:
-    MatchASTVisitor *MV;
-    bool MB;
-  };
-
   class TimeBucketRegion {
   public:
     TimeBucketRegion() : Bucket(nullptr) {}
@@ -1168,7 +1161,7 @@ bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
   }
 
   ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
-  ASTChildrenNotSpelledInSource RAII2(this, ScopedChildren);
+  ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
 
   match(*DeclNode);
   return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
index 1dc5179..cde3e46 100644 (file)
@@ -2706,6 +2706,52 @@ void callDefaultArg()
     EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
     EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
   }
+  Code = R"cpp(
+struct A
+{
+    ~A();
+private:
+    int i;
+};
+
+A::~A() = default;
+)cpp";
+  {
+    auto M = cxxDestructorDecl(isDefaulted(),
+                               ofClass(cxxRecordDecl(has(fieldDecl()))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  Code = R"cpp(
+struct S
+{
+    static constexpr bool getTrue() { return true; }
+};
+
+struct A
+{
+    explicit(S::getTrue()) A();
+};
+
+A::A() = default;
+)cpp";
+  {
+    EXPECT_TRUE(matchesConditionally(
+        Code,
+        traverse(TK_AsIs,
+                 cxxConstructorDecl(
+                     isDefaulted(),
+                     hasExplicitSpecifier(expr(ignoringImplicit(
+                         callExpr(has(ignoringImplicit(declRefExpr())))))))),
+        true, {"-std=c++20"}));
+    EXPECT_TRUE(matchesConditionally(
+        Code,
+        traverse(TK_IgnoreUnlessSpelledInSource,
+                 cxxConstructorDecl(
+                     isDefaulted(),
+                     hasExplicitSpecifier(callExpr(has(declRefExpr()))))),
+        true, {"-std=c++20"}));
+  }
 }
 
 template <typename MatcherT>