steveire updated this revision to Diff 304103.
steveire added a comment.

Update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D90982/new/

https://reviews.llvm.org/D90982

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/ASTMatchers/ASTMatchFinder.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/AST/ASTTraverserTest.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
  clang/unittests/Tooling/TransformerTest.cpp

Index: clang/unittests/Tooling/TransformerTest.cpp
===================================================================
--- clang/unittests/Tooling/TransformerTest.cpp
+++ clang/unittests/Tooling/TransformerTest.cpp
@@ -132,6 +132,13 @@
     compareSnippets(Expected, rewrite(Input));
   }
 
+  template <typename R> void testRuleFailure(R Rule, StringRef Input) {
+    Transformers.push_back(
+        std::make_unique<Transformer>(std::move(Rule), consumer()));
+    Transformers.back()->registerMatchers(&MatchFinder);
+    ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
+  }
+
   // Transformers are referenced by MatchFinder.
   std::vector<std::unique_ptr<Transformer>> Transformers;
   clang::ast_matchers::MatchFinder MatchFinder;
@@ -1067,6 +1074,179 @@
   EXPECT_EQ(ErrorCount, 0);
 }
 
+TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) {
+
+  std::string OtherStructPrefix = R"cpp(
+struct Other {
+)cpp";
+  std::string OtherStructSuffix = "};";
+
+  std::string CopyableStructName = "struct Copyable";
+  std::string BrokenStructName = "struct explicit Copyable";
+
+  std::string CodeSuffix = R"cpp(
+{
+    Other m_i;
+    Copyable();
+};
+)cpp";
+
+  std::string CopyCtor = "Other(const Other&) = default;";
+  std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;";
+  std::string BrokenExplicitCopyCtor =
+      "explicit explicit explicit Other(const Other&) = default;";
+
+  std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix +
+                             CopyableStructName + CodeSuffix;
+  std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor +
+                                      OtherStructSuffix + CopyableStructName +
+                                      CodeSuffix;
+  std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor +
+                                    OtherStructSuffix + BrokenStructName +
+                                    CodeSuffix;
+
+  auto MatchedRecord =
+      cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
+
+  auto RewriteRule =
+      changeTo(before(node("copyConstructor")), cat("explicit "));
+
+  testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
+                    RewriteRule),
+           RewriteInput, ExpectedRewriteOutput);
+
+  testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
+           RewriteInput, BrokenRewriteOutput);
+}
+
+TEST_F(TransformerTest, ImplicitNodes_RangeFor) {
+
+  std::string CodePrefix = R"cpp(
+struct Container
+{
+    int* begin() const;
+    int* end() const;
+    int* cbegin() const;
+    int* cend() const;
+};
+
+void foo()
+{
+  const Container c;
+)cpp";
+
+  std::string BeginCallBefore = "  c.begin();";
+  std::string BeginCallAfter = "  c.cbegin();";
+
+  std::string ForLoop = "for (auto i : c)";
+  std::string BrokenForLoop = "for (auto i :.cbegin() c)";
+
+  std::string CodeSuffix = R"cpp(
+  {
+  }
+}
+)cpp";
+
+  std::string RewriteInput =
+      CodePrefix + BeginCallBefore + ForLoop + CodeSuffix;
+  std::string ExpectedRewriteOutput =
+      CodePrefix + BeginCallAfter + ForLoop + CodeSuffix;
+  std::string BrokenRewriteOutput =
+      CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix;
+
+  auto MatchedRecord =
+      cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(),
+                                                 hasDeclaration(cxxRecordDecl(
+                                                     hasName("Container"))))))
+                               .bind("callTarget")),
+                        callee(cxxMethodDecl(hasName("begin"))))
+          .bind("constBeginCall");
+
+  auto RewriteRule =
+      changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
+
+  testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
+                    RewriteRule),
+           RewriteInput, ExpectedRewriteOutput);
+
+  testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
+           RewriteInput, BrokenRewriteOutput);
+}
+
+TEST_F(TransformerTest, ImplicitNodes_ForStmt) {
+
+  std::string CodePrefix = R"cpp(
+struct NonTrivial {
+    NonTrivial() {}
+    NonTrivial(NonTrivial&) {}
+    NonTrivial& operator=(NonTrivial const&) { return *this; }
+
+    ~NonTrivial() {}
+};
+
+struct ContainsArray {
+    NonTrivial arr[2];
+    ContainsArray& operator=(ContainsArray const&) = default;
+};
+
+void testIt()
+{
+    ContainsArray ca1;
+    ContainsArray ca2;
+    ca2 = ca1;
+)cpp";
+
+  auto CodeSuffix = "}";
+
+  auto LoopBody = R"cpp(
+    {
+
+    }
+)cpp";
+
+  auto RawLoop = "for (auto i = 0; i != 5; ++i)";
+
+  auto RangeLoop = "for (auto i : boost::irange(5))";
+
+  // Expect to rewrite the raw loop to the ranged loop.
+  // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
+  // mode also matches the hidden for loop generated in the copy assignment
+  // operator of ContainsArray. Transformer then fails to transform the code at
+  // all.
+
+  auto RewriteInput =
+      CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
+
+  auto RewriteOutput =
+      CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
+  {
+    auto MatchedLoop = forStmt(
+        has(declStmt(
+            hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
+                              .bind("loopVar")))),
+        has(binaryOperator(hasOperatorName("!="),
+                           hasLHS(ignoringImplicit(declRefExpr(
+                               to(varDecl(equalsBoundNode("loopVar")))))),
+                           hasRHS(expr().bind("upperBoundExpr")))),
+        has(unaryOperator(hasOperatorName("++"),
+                          hasUnaryOperand(declRefExpr(
+                              to(varDecl(equalsBoundNode("loopVar"))))))
+                .bind("incrementOp")));
+
+    auto RewriteRule =
+        changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
+                 cat("auto ", name("loopVar"), " : boost::irange(",
+                     node("upperBoundExpr"), ")"));
+
+    testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
+                      RewriteRule),
+             RewriteInput, RewriteOutput);
+
+    testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
+                    RewriteInput);
+  }
+}
+
 TEST_F(TransformerTest, TemplateInstantiation) {
 
   std::string NonTemplatesInput = R"cpp(
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -2331,6 +2331,255 @@
   }
 }
 
+TEST(Traversal, traverseNoImplicit) {
+  StringRef Code = R"cpp(
+struct NonTrivial {
+    NonTrivial() {}
+    NonTrivial(NonTrivial&) {}
+    NonTrivial& operator=(NonTrivial&) { return *this; }
+
+    ~NonTrivial() {}
+};
+
+struct NoSpecialMethods {
+    NonTrivial nt;
+};
+
+struct ContainsArray {
+    NonTrivial arr[2];
+    ContainsArray& operator=(ContainsArray &other) = default;
+};
+
+void copyIt()
+{
+    NoSpecialMethods nc1;
+    NoSpecialMethods nc2(nc1);
+    nc2 = nc1;
+
+    ContainsArray ca;
+    ContainsArray ca2;
+    ca2 = ca;
+}
+
+struct HasCtorInits : NoSpecialMethods, NonTrivial
+{
+  int m_i;
+  NonTrivial m_nt;
+  HasCtorInits() : NoSpecialMethods(), m_i(42) {}
+};
+
+)cpp";
+  {
+    auto M = cxxRecordDecl(hasName("NoSpecialMethods"),
+                           has(cxxRecordDecl(hasName("NoSpecialMethods"))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+    M = cxxRecordDecl(hasName("NoSpecialMethods"),
+                      has(cxxConstructorDecl(isCopyConstructor())));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+    M = cxxRecordDecl(hasName("NoSpecialMethods"),
+                      has(cxxMethodDecl(isCopyAssignmentOperator())));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+    M = cxxRecordDecl(hasName("NoSpecialMethods"),
+                      has(cxxConstructorDecl(isDefaultConstructor())));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+    M = cxxRecordDecl(hasName("NoSpecialMethods"), has(cxxDestructorDecl()));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    // Compiler generates a forStmt to copy the array
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, forStmt())));
+    EXPECT_FALSE(
+        matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, forStmt())));
+  }
+  {
+    // The defaulted method declaration can be matched, but not its
+    // definition, in IgnoreUnlessSpelledInSource mode
+    auto MDecl = cxxMethodDecl(ofClass(cxxRecordDecl(hasName("ContainsArray"))),
+                               isCopyAssignmentOperator(), isDefaulted());
+
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDecl)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDecl)));
+
+    auto MDef = cxxMethodDecl(MDecl, has(compoundStmt()));
+
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDef)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDef)));
+
+    // The parameter of the defaulted method can still be matched.
+    auto MParm =
+        cxxMethodDecl(MDecl, hasParameter(0, parmVarDecl(hasName("other"))));
+
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MParm)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MParm)));
+  }
+  {
+    auto M =
+        cxxConstructorDecl(hasName("HasCtorInits"),
+                           has(cxxCtorInitializer(forField(hasName("m_i")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M =
+        cxxConstructorDecl(hasName("HasCtorInits"),
+                           has(cxxCtorInitializer(forField(hasName("m_nt")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = cxxConstructorDecl(
+        hasName("HasCtorInits"),
+        has(cxxCtorInitializer(withInitializer(cxxConstructExpr(hasDeclaration(
+            cxxConstructorDecl(hasName("NoSpecialMethods"))))))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = cxxConstructorDecl(
+        hasName("HasCtorInits"),
+        has(cxxCtorInitializer(withInitializer(cxxConstructExpr(
+            hasDeclaration(cxxConstructorDecl(hasName("NonTrivial"))))))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = cxxCtorInitializer(forField(hasName("m_nt")));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+
+  Code = R"cpp(
+  void rangeFor()
+  {
+    int arr[2];
+    for (auto i : arr)
+    {
+
+    }
+  }
+  )cpp";
+  {
+    auto M = cxxForRangeStmt(has(binaryOperator(hasOperatorName("!="))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M =
+        cxxForRangeStmt(hasDescendant(binaryOperator(hasOperatorName("+"))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M =
+        cxxForRangeStmt(hasDescendant(unaryOperator(hasOperatorName("++"))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = cxxForRangeStmt(has(declStmt()));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M =
+        cxxForRangeStmt(hasLoopVariable(varDecl(hasName("i"))),
+                        hasRangeInit(declRefExpr(to(varDecl(hasName("arr"))))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = cxxForRangeStmt(unless(hasInitStatement(stmt())));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+
+  Code = R"cpp(
+  void rangeFor()
+  {
+    int arr[2];
+    for (auto& a = arr; auto i : a)
+    {
+
+    }
+  }
+  )cpp";
+  {
+    auto M = cxxForRangeStmt(has(binaryOperator(hasOperatorName("!="))));
+    EXPECT_TRUE(
+        matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20"}));
+    EXPECT_FALSE(
+        matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
+                             true, {"-std=c++20"}));
+  }
+  {
+    auto M =
+        cxxForRangeStmt(hasDescendant(binaryOperator(hasOperatorName("+"))));
+    EXPECT_TRUE(
+        matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20"}));
+    EXPECT_FALSE(
+        matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
+                             true, {"-std=c++20"}));
+  }
+  {
+    auto M =
+        cxxForRangeStmt(hasDescendant(unaryOperator(hasOperatorName("++"))));
+    EXPECT_TRUE(
+        matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20"}));
+    EXPECT_FALSE(
+        matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
+                             true, {"-std=c++20"}));
+  }
+  {
+    auto M = cxxForRangeStmt(has(declStmt()));
+    EXPECT_TRUE(
+        matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20"}));
+    EXPECT_FALSE(
+        matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
+                             true, {"-std=c++20"}));
+  }
+  {
+    auto M = cxxForRangeStmt(
+        hasInitStatement(declStmt(hasSingleDecl(varDecl(
+            hasName("a"),
+            hasInitializer(declRefExpr(to(varDecl(hasName("arr"))))))))),
+        hasLoopVariable(varDecl(hasName("i"))),
+        hasRangeInit(declRefExpr(to(varDecl(hasName("a"))))));
+    EXPECT_TRUE(
+        matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20"}));
+    EXPECT_TRUE(
+        matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M),
+                             true, {"-std=c++20"}));
+  }
+  Code = R"cpp(
+void hasDefaultArg(int i, int j = 0)
+{
+}
+void callDefaultArg()
+{
+  hasDefaultArg(42);
+}
+)cpp";
+  {
+    auto M = callExpr(has(integerLiteral(equals(42))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = callExpr(has(cxxDefaultArgExpr()));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+}
+
 template <typename MatcherT>
 bool matcherTemplateWithBinding(StringRef Code, const MatcherT &M) {
   return matchAndVerifyResultTrue(
Index: clang/unittests/AST/ASTTraverserTest.cpp
===================================================================
--- clang/unittests/AST/ASTTraverserTest.cpp
+++ clang/unittests/AST/ASTTraverserTest.cpp
@@ -35,6 +35,10 @@
   }
 
   void Visit(const Stmt *S) {
+    if (!S) {
+      OS << "<<<NULL>>>";
+      return;
+    }
     OS << S->getStmtClassName();
     if (auto *E = dyn_cast<DeclRefExpr>(S)) {
       OS << " '" << E->getDecl()->getDeclName() << "'";
@@ -51,7 +55,14 @@
     OS << C->getCommentKindName();
   }
 
-  void Visit(const CXXCtorInitializer *Init) { OS << "CXXCtorInitializer"; }
+  void Visit(const CXXCtorInitializer *Init) {
+    OS << "CXXCtorInitializer";
+    if (const auto *F = Init->getAnyMember()) {
+      OS << " '" << F->getNameAsString() << "'";
+    } else if (auto const *TSI = Init->getTypeSourceInfo()) {
+      OS << " '" << TSI->getType().getAsString() << "'";
+    }
+  }
 
   void Visit(const Attr *A) {
     switch (A->getKind()) {
@@ -226,7 +237,7 @@
 
   verifyWithDynNode(Init,
                     R"cpp(
-CXXCtorInitializer
+CXXCtorInitializer 'm_number'
 `-IntegerLiteral
 )cpp");
 
@@ -1050,6 +1061,438 @@
   }
 }
 
+TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) {
+  {
+    auto AST = buildASTFromCode(R"cpp(
+int i = 0;
+)cpp");
+    const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl();
+
+#if _WIN32
+    EXPECT_EQ(dumpASTString(TK_AsIs, TUDecl),
+              R"cpp(
+TranslationUnitDecl
+|-CXXRecordDecl '_GUID'
+| `-TypeVisibilityAttr
+|-TypedefDecl '__int128_t'
+| `-BuiltinType
+|-TypedefDecl '__uint128_t'
+| `-BuiltinType
+|-TypedefDecl '__NSConstantString'
+| `-RecordType
+|-CXXRecordDecl 'type_info'
+| `-TypeVisibilityAttr
+|-TypedefDecl 'size_t'
+| `-BuiltinType
+|-TypedefDecl '__builtin_ms_va_list'
+| `-PointerType
+|   `-BuiltinType
+|-TypedefDecl '__builtin_va_list'
+| `-PointerType
+|   `-BuiltinType
+`-VarDecl 'i'
+  `-IntegerLiteral
+)cpp");
+#else
+    EXPECT_EQ(dumpASTString(TK_AsIs, TUDecl),
+              R"cpp(
+TranslationUnitDecl
+|-TypedefDecl '__int128_t'
+| `-BuiltinType
+|-TypedefDecl '__uint128_t'
+| `-BuiltinType
+|-TypedefDecl '__NSConstantString'
+| `-RecordType
+|-TypedefDecl '__builtin_ms_va_list'
+| `-PointerType
+|   `-BuiltinType
+|-TypedefDecl '__builtin_va_list'
+| `-ConstantArrayType
+|   `-RecordType
+`-VarDecl 'i'
+  `-IntegerLiteral
+)cpp");
+#endif
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl),
+              R"cpp(
+TranslationUnitDecl
+`-VarDecl 'i'
+  `-IntegerLiteral
+)cpp");
+  }
+
+  auto AST2 = buildASTFromCodeWithArgs(R"cpp(
+struct Simple {
+};
+struct Other {
+};
+
+struct Record : Simple, Other {
+  Record() : Simple(), m_i(42) {}
+private:
+  int m_i;
+  int m_i2 = 42;
+  Simple m_s;
+};
+
+struct NonTrivial {
+    NonTrivial() {}
+    NonTrivial(NonTrivial&) {}
+    NonTrivial& operator=(NonTrivial&) { return *this; }
+
+    ~NonTrivial() {}
+};
+
+struct ContainsArray {
+    NonTrivial arr[2];
+    int irr[2];
+    ContainsArray& operator=(ContainsArray &) = default;
+};
+
+void copyIt()
+{
+    ContainsArray ca;
+    ContainsArray ca2;
+    ca2 = ca;
+}
+
+void forLoop()
+{
+    int arr[2];
+    for (auto i : arr)
+    {
+
+    }
+    for (auto& a = arr; auto i : a)
+    {
+
+    }
+}
+
+struct DefaultedAndDeleted {
+  NonTrivial nt;
+  DefaultedAndDeleted() = default;
+  ~DefaultedAndDeleted() = default;
+  DefaultedAndDeleted(DefaultedAndDeleted &) = default;
+  DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;
+  DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;
+  DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;
+};
+
+void copyIt2()
+{
+    DefaultedAndDeleted ca;
+    DefaultedAndDeleted ca2;
+    ca2 = ca;
+}
+
+void hasDefaultArg(int i, int j = 0)
+{
+}
+void callDefaultArg()
+{
+  hasDefaultArg(42);
+}
+)cpp",
+                                       {"-std=c++20"});
+
+  {
+    auto BN = ast_matchers::match(
+        cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
+        AST2->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+CXXRecordDecl 'Record'
+|-CXXRecordDecl 'Record'
+|-CXXConstructorDecl 'Record'
+| |-CXXCtorInitializer 'struct Simple'
+| | `-CXXConstructExpr
+| |-CXXCtorInitializer 'struct Other'
+| | `-CXXConstructExpr
+| |-CXXCtorInitializer 'm_i'
+| | `-IntegerLiteral
+| |-CXXCtorInitializer 'm_i2'
+| | `-CXXDefaultInitExpr
+| |-CXXCtorInitializer 'm_s'
+| | `-CXXConstructExpr
+| `-CompoundStmt
+|-AccessSpecDecl
+|-FieldDecl 'm_i'
+|-FieldDecl 'm_i2'
+| `-IntegerLiteral
+`-FieldDecl 'm_s'
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+CXXRecordDecl 'Record'
+|-CXXConstructorDecl 'Record'
+| |-CXXCtorInitializer 'struct Simple'
+| | `-CXXConstructExpr
+| |-CXXCtorInitializer 'm_i'
+| | `-IntegerLiteral
+| `-CompoundStmt
+|-AccessSpecDecl
+|-FieldDecl 'm_i'
+|-FieldDecl 'm_i2'
+| `-IntegerLiteral
+`-FieldDecl 'm_s'
+)cpp");
+  }
+  {
+    auto BN = ast_matchers::match(
+        cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
+            .bind("rec"),
+        AST2->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+CXXRecordDecl 'ContainsArray'
+|-CXXRecordDecl 'ContainsArray'
+|-FieldDecl 'arr'
+|-FieldDecl 'irr'
+|-CXXMethodDecl 'operator='
+| |-ParmVarDecl ''
+| `-CompoundStmt
+|   |-ForStmt
+|   | |-DeclStmt
+|   | | `-VarDecl '__i0'
+|   | |   `-IntegerLiteral
+|   | |-<<<NULL>>>
+|   | |-BinaryOperator
+|   | | |-ImplicitCastExpr
+|   | | | `-DeclRefExpr '__i0'
+|   | | `-IntegerLiteral
+|   | |-UnaryOperator
+|   | | `-DeclRefExpr '__i0'
+|   | `-CXXMemberCallExpr
+|   |   |-MemberExpr
+|   |   | `-ArraySubscriptExpr
+|   |   |   |-ImplicitCastExpr
+|   |   |   | `-MemberExpr
+|   |   |   |   `-CXXThisExpr
+|   |   |   `-ImplicitCastExpr
+|   |   |     `-DeclRefExpr '__i0'
+|   |   `-ArraySubscriptExpr
+|   |     |-ImplicitCastExpr
+|   |     | `-MemberExpr
+|   |     |   `-DeclRefExpr ''
+|   |     `-ImplicitCastExpr
+|   |       `-DeclRefExpr '__i0'
+|   |-CallExpr
+|   | |-ImplicitCastExpr
+|   | | `-DeclRefExpr '__builtin_memcpy'
+|   | |-ImplicitCastExpr
+|   | | `-UnaryOperator
+|   | |   `-MemberExpr
+|   | |     `-CXXThisExpr
+|   | |-ImplicitCastExpr
+|   | | `-UnaryOperator
+|   | |   `-MemberExpr
+|   | |     `-DeclRefExpr ''
+|   | `-IntegerLiteral
+|   `-ReturnStmt
+|     `-UnaryOperator
+|       `-CXXThisExpr
+|-CXXConstructorDecl 'ContainsArray'
+| `-ParmVarDecl ''
+|-CXXDestructorDecl '~ContainsArray'
+| `-CompoundStmt
+`-CXXConstructorDecl 'ContainsArray'
+  |-CXXCtorInitializer 'arr'
+  | `-CXXConstructExpr
+  `-CompoundStmt
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+CXXRecordDecl 'ContainsArray'
+|-FieldDecl 'arr'
+|-FieldDecl 'irr'
+`-CXXMethodDecl 'operator='
+  `-ParmVarDecl ''
+)cpp");
+  }
+  {
+    auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
+                                  AST2->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")),
+              R"cpp(
+FunctionDecl 'forLoop'
+`-CompoundStmt
+  |-DeclStmt
+  | `-VarDecl 'arr'
+  |-CXXForRangeStmt
+  | |-<<<NULL>>>
+  | |-DeclStmt
+  | | `-VarDecl '__range1'
+  | |   `-DeclRefExpr 'arr'
+  | |-DeclStmt
+  | | `-VarDecl '__begin1'
+  | |   `-ImplicitCastExpr
+  | |     `-DeclRefExpr '__range1'
+  | |-DeclStmt
+  | | `-VarDecl '__end1'
+  | |   `-BinaryOperator
+  | |     |-ImplicitCastExpr
+  | |     | `-DeclRefExpr '__range1'
+  | |     `-IntegerLiteral
+  | |-BinaryOperator
+  | | |-ImplicitCastExpr
+  | | | `-DeclRefExpr '__begin1'
+  | | `-ImplicitCastExpr
+  | |   `-DeclRefExpr '__end1'
+  | |-UnaryOperator
+  | | `-DeclRefExpr '__begin1'
+  | |-DeclStmt
+  | | `-VarDecl 'i'
+  | |   `-ImplicitCastExpr
+  | |     `-UnaryOperator
+  | |       `-ImplicitCastExpr
+  | |         `-DeclRefExpr '__begin1'
+  | `-CompoundStmt
+  `-CXXForRangeStmt
+    |-DeclStmt
+    | `-VarDecl 'a'
+    |   `-DeclRefExpr 'arr'
+    |-DeclStmt
+    | `-VarDecl '__range1'
+    |   `-DeclRefExpr 'a'
+    |-DeclStmt
+    | `-VarDecl '__begin1'
+    |   `-ImplicitCastExpr
+    |     `-DeclRefExpr '__range1'
+    |-DeclStmt
+    | `-VarDecl '__end1'
+    |   `-BinaryOperator
+    |     |-ImplicitCastExpr
+    |     | `-DeclRefExpr '__range1'
+    |     `-IntegerLiteral
+    |-BinaryOperator
+    | |-ImplicitCastExpr
+    | | `-DeclRefExpr '__begin1'
+    | `-ImplicitCastExpr
+    |   `-DeclRefExpr '__end1'
+    |-UnaryOperator
+    | `-DeclRefExpr '__begin1'
+    |-DeclStmt
+    | `-VarDecl 'i'
+    |   `-ImplicitCastExpr
+    |     `-UnaryOperator
+    |       `-ImplicitCastExpr
+    |         `-DeclRefExpr '__begin1'
+    `-CompoundStmt
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("func")),
+              R"cpp(
+FunctionDecl 'forLoop'
+`-CompoundStmt
+  |-DeclStmt
+  | `-VarDecl 'arr'
+  |-CXXForRangeStmt
+  | |-<<<NULL>>>
+  | |-VarDecl 'i'
+  | |-DeclRefExpr 'arr'
+  | `-CompoundStmt
+  `-CXXForRangeStmt
+    |-DeclStmt
+    | `-VarDecl 'a'
+    |   `-DeclRefExpr 'arr'
+    |-VarDecl 'i'
+    |-DeclRefExpr 'a'
+    `-CompoundStmt
+)cpp");
+  }
+  {
+    auto BN = ast_matchers::match(
+        cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
+            .bind("rec"),
+        AST2->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+CXXRecordDecl 'DefaultedAndDeleted'
+|-CXXRecordDecl 'DefaultedAndDeleted'
+|-FieldDecl 'nt'
+|-CXXConstructorDecl 'DefaultedAndDeleted'
+| |-CXXCtorInitializer 'nt'
+| | `-CXXConstructExpr
+| `-CompoundStmt
+|-CXXDestructorDecl '~DefaultedAndDeleted'
+| `-CompoundStmt
+|-CXXConstructorDecl 'DefaultedAndDeleted'
+| `-ParmVarDecl ''
+|-CXXMethodDecl 'operator='
+| |-ParmVarDecl ''
+| `-CompoundStmt
+|   |-CXXMemberCallExpr
+|   | |-MemberExpr
+|   | | `-MemberExpr
+|   | |   `-CXXThisExpr
+|   | `-MemberExpr
+|   |   `-DeclRefExpr ''
+|   `-ReturnStmt
+|     `-UnaryOperator
+|       `-CXXThisExpr
+|-CXXConstructorDecl 'DefaultedAndDeleted'
+| `-ParmVarDecl ''
+`-CXXMethodDecl 'operator='
+  `-ParmVarDecl ''
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+CXXRecordDecl 'DefaultedAndDeleted'
+|-FieldDecl 'nt'
+|-CXXConstructorDecl 'DefaultedAndDeleted'
+|-CXXDestructorDecl '~DefaultedAndDeleted'
+|-CXXConstructorDecl 'DefaultedAndDeleted'
+| `-ParmVarDecl ''
+|-CXXMethodDecl 'operator='
+| `-ParmVarDecl ''
+|-CXXConstructorDecl 'DefaultedAndDeleted'
+| `-ParmVarDecl ''
+`-CXXMethodDecl 'operator='
+  `-ParmVarDecl ''
+)cpp");
+  }
+  {
+    auto BN = ast_matchers::match(
+        callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
+            .bind("funcCall"),
+        AST2->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")),
+              R"cpp(
+CallExpr
+|-ImplicitCastExpr
+| `-DeclRefExpr 'hasDefaultArg'
+|-IntegerLiteral
+`-CXXDefaultArgExpr
+)cpp");
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<CallExpr>("funcCall")),
+              R"cpp(
+CallExpr
+|-DeclRefExpr 'hasDefaultArg'
+`-IntegerLiteral
+)cpp");
+  }
+}
+
 TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
 
   auto AST = buildASTFromCode(R"cpp(
@@ -1108,7 +1551,6 @@
 ClassTemplateDecl 'TemplStruct'
 |-TemplateTypeParmDecl 'T'
 `-CXXRecordDecl 'TemplStruct'
-  |-CXXRecordDecl 'TemplStruct'
   |-CXXConstructorDecl 'TemplStruct<T>'
   | `-CompoundStmt
   |-CXXDestructorDecl '~TemplStruct<T>'
@@ -1216,7 +1658,6 @@
 ClassTemplateSpecializationDecl 'TemplStruct'
 |-TemplateArgument type _Bool
 | `-BuiltinType
-|-CXXRecordDecl 'TemplStruct'
 |-CXXConstructorDecl 'TemplStruct'
 | `-CompoundStmt
 |-CXXDestructorDecl '~TemplStruct'
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -289,7 +289,7 @@
                           Implementation->TraversalKind());
 
   if (!Finder->isTraversalAsIs() &&
-      Finder->IsMatchingInTemplateInstantiationNotSpelledInSource())
+      Finder->IsMatchingInASTNodeNotSpelledInSource())
     return false;
 
   auto N =
@@ -313,7 +313,7 @@
                           Implementation->TraversalKind());
 
   if (!Finder->isTraversalAsIs() &&
-      Finder->IsMatchingInTemplateInstantiationNotSpelledInSource())
+      Finder->IsMatchingInASTNodeNotSpelledInSource())
     return false;
 
   auto N =
Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -95,9 +95,12 @@
   // matching the descendants.
   MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
                        BoundNodesTreeBuilder *Builder, int MaxDepth,
-                       TraversalKind Traversal, ASTMatchFinder::BindKind Bind)
+                       TraversalKind Traversal, bool IgnoreImplicitChildren,
+                       ASTMatchFinder::BindKind Bind)
       : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
-        MaxDepth(MaxDepth), Traversal(Traversal), Bind(Bind), Matches(false) {}
+        MaxDepth(MaxDepth), Traversal(Traversal),
+        IgnoreImplicitChildren(IgnoreImplicitChildren), Bind(Bind),
+        Matches(false) {}
 
   // Returns true if a match is found in the subtree rooted at the
   // given AST node. This is done via a set of mutually recursive
@@ -145,6 +148,10 @@
   // They are public only to allow CRTP to work. They are *not *part
   // of the public API of this class.
   bool TraverseDecl(Decl *DeclNode) {
+
+    if (DeclNode && DeclNode->isImplicit() && !Finder->isTraversalAsIs())
+      return baseTraverse(*DeclNode);
+
     ScopedIncrement ScopedDepth(&CurrentDepth);
     return (DeclNode == nullptr) || traverse(*DeclNode);
   }
@@ -176,6 +183,10 @@
     Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
     if (!StmtToTraverse)
       return true;
+
+    if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
+      return true;
+
     if (!match(*StmtToTraverse))
       return false;
     return VisitorBase::TraverseStmt(StmtToTraverse, Queue);
@@ -265,7 +276,7 @@
   }
 
   bool shouldVisitTemplateInstantiations() const { return true; }
-  bool shouldVisitImplicitCode() const { return true; }
+  bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }
 
 private:
   // Used for updating the depth during traversal.
@@ -360,6 +371,7 @@
   int CurrentDepth;
   const int MaxDepth;
   const TraversalKind Traversal;
+  const bool IgnoreImplicitChildren;
   const ASTMatchFinder::BindKind Bind;
   bool Matches;
 };
@@ -497,19 +509,21 @@
                           const DynTypedMatcher &Matcher,
                           BoundNodesTreeBuilder *Builder, int MaxDepth,
                           TraversalKind Traversal, BindKind Bind) {
-    bool ScopedTraversal = TraversingTemplateInstantiationNotSpelledInSource;
+    bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
+                           TraversingASTChildrenNotSpelledInSource;
 
-    if (const auto *CTSD = Node.get<ClassTemplateSpecializationDecl>()) {
-      int SK = CTSD->getSpecializationKind();
-      if (SK == TSK_ExplicitInstantiationDeclaration ||
-          SK == TSK_ExplicitInstantiationDefinition)
+    bool IgnoreImplicitChildren = false;
+
+    if (!isTraversalAsIs()) {
+      IgnoreImplicitChildren = true;
+      if (Node.get<CXXForRangeStmt>())
         ScopedTraversal = true;
     }
 
-    TemplateInstantiationNotSpelledInSourceScope RAII(this, ScopedTraversal);
+    ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
 
-    MatchChildASTVisitor Visitor(
-      &Matcher, this, Builder, MaxDepth, Traversal, Bind);
+    MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth, Traversal,
+                                 IgnoreImplicitChildren, Bind);
     return Visitor.findMatch(Node);
   }
 
@@ -592,38 +606,53 @@
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return true; }
 
-  bool IsMatchingInTemplateInstantiationNotSpelledInSource() const override {
-    return TraversingTemplateInstantiationNotSpelledInSource;
+  bool IsMatchingInASTNodeNotSpelledInSource() const override {
+    return TraversingASTNodeNotSpelledInSource;
   }
 
   bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
-    TemplateInstantiationNotSpelledInSourceScope RAII(this, true);
+    ASTNodeNotSpelledInSourceScope RAII(this, true);
     return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
         D);
   }
 
   bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
-    TemplateInstantiationNotSpelledInSourceScope RAII(this, true);
+    ASTNodeNotSpelledInSourceScope RAII(this, true);
     return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
         D);
   }
 
   bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
-    TemplateInstantiationNotSpelledInSourceScope RAII(this, true);
+    ASTNodeNotSpelledInSourceScope RAII(this, true);
     return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
         D);
   }
 
 private:
-  bool TraversingTemplateInstantiationNotSpelledInSource = false;
+  bool TraversingASTNodeNotSpelledInSource = false;
+  bool TraversingASTChildrenNotSpelledInSource = false;
 
-  struct TemplateInstantiationNotSpelledInSourceScope {
-    TemplateInstantiationNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
-        : MV(V), MB(V->TraversingTemplateInstantiationNotSpelledInSource) {
-      V->TraversingTemplateInstantiationNotSpelledInSource = B;
+  struct ASTNodeNotSpelledInSourceScope {
+    ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
+        : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {
+      V->TraversingASTNodeNotSpelledInSource = B;
     }
-    ~TemplateInstantiationNotSpelledInSourceScope() {
-      MV->TraversingTemplateInstantiationNotSpelledInSource = MB;
+    ~ASTNodeNotSpelledInSourceScope() {
+      MV->TraversingASTNodeNotSpelledInSource = MB;
+    }
+
+  private:
+    MatchASTVisitor *MV;
+    bool MB;
+  };
+
+  struct ASTChildrenNotSpelledInSource {
+    ASTChildrenNotSpelledInSource(MatchASTVisitor *V, bool B)
+        : MV(V), MB(V->TraversingASTChildrenNotSpelledInSource) {
+      V->TraversingASTChildrenNotSpelledInSource = B;
+    }
+    ~ASTChildrenNotSpelledInSource() {
+      MV->TraversingASTChildrenNotSpelledInSource = MB;
     }
 
   private:
@@ -1050,6 +1079,24 @@
   if (!DeclNode) {
     return true;
   }
+
+  auto ScopedTraversal =
+      TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
+  auto ScopedChildren = TraversingASTChildrenNotSpelledInSource;
+
+  if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
+    auto SK = CTSD->getSpecializationKind();
+    if (SK == TSK_ExplicitInstantiationDeclaration ||
+        SK == TSK_ExplicitInstantiationDefinition)
+      ScopedChildren = true;
+  } else if (const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
+    if (FD->isDefaulted())
+      ScopedChildren = true;
+  }
+
+  ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
+  ASTChildrenNotSpelledInSource RAII2(this, ScopedChildren);
+
   match(*DeclNode);
   return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
 }
@@ -1058,6 +1105,10 @@
   if (!StmtNode) {
     return true;
   }
+  auto ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
+                         TraversingASTChildrenNotSpelledInSource;
+
+  ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
   match(*StmtNode);
   return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
 }
@@ -1103,6 +1154,14 @@
   if (!CtorInit)
     return true;
 
+  auto ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
+                         TraversingASTChildrenNotSpelledInSource;
+
+  if (!CtorInit->isWritten())
+    ScopedTraversal = true;
+
+  ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
+
   match(*CtorInit);
 
   return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1060,7 +1060,7 @@
 
   virtual ASTContext &getASTContext() const = 0;
 
-  virtual bool IsMatchingInTemplateInstantiationNotSpelledInSource() const = 0;
+  virtual bool IsMatchingInASTNodeNotSpelledInSource() const = 0;
 
   bool isTraversalAsIs() const;
 
Index: clang/include/clang/AST/ASTNodeTraverser.h
===================================================================
--- clang/include/clang/AST/ASTNodeTraverser.h
+++ clang/include/clang/AST/ASTNodeTraverser.h
@@ -85,6 +85,9 @@
   TraversalKind GetTraversalKind() const { return Traversal; }
 
   void Visit(const Decl *D) {
+    if (Traversal != TK_AsIs && D->isImplicit())
+      return;
+
     getNodeDelegate().AddChild([=] {
       getNodeDelegate().Visit(D);
       if (!D)
@@ -144,7 +147,8 @@
       if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S))
         return;
 
-      if (isa<LambdaExpr>(S) && Traversal == TK_IgnoreUnlessSpelledInSource)
+      if (Traversal == TK_IgnoreUnlessSpelledInSource &&
+          isa<LambdaExpr, CXXForRangeStmt, CallExpr>(S))
         return;
 
       for (const Stmt *SubStmt : S->children())
@@ -185,6 +189,8 @@
   }
 
   void Visit(const CXXCtorInitializer *Init) {
+    if (Traversal != TK_AsIs && !Init->isWritten())
+      return;
     getNodeDelegate().AddChild([=] {
       getNodeDelegate().Visit(Init);
       Visit(Init->getInit());
@@ -401,6 +407,9 @@
     if (const Expr *TRC = D->getTrailingRequiresClause())
       Visit(TRC);
 
+    if (Traversal != TK_AsIs && D->isDefaulted())
+      return;
+
     if (const auto *C = dyn_cast<CXXConstructorDecl>(D))
       for (const auto *I : C->inits())
         Visit(I);
@@ -417,6 +426,9 @@
   }
 
   void VisitVarDecl(const VarDecl *D) {
+    if (Traversal != TK_AsIs && D->isCXXForRangeDecl())
+      return;
+
     if (D->hasInit())
       Visit(D->getInit());
   }
@@ -717,6 +729,26 @@
       Visit(CatchParam);
   }
 
+  void VisitCXXForRangeStmt(const CXXForRangeStmt *Node) {
+    if (Traversal != TK_AsIs) {
+      Visit(Node->getInit());
+      Visit(Node->getLoopVariable());
+      Visit(Node->getRangeInit());
+      Visit(Node->getBody());
+    }
+  }
+
+  void VisitCallExpr(const CallExpr *Node) {
+    for (auto Child :
+         make_filter_range(Node->children(), [this](const Stmt *Child) {
+           if (Traversal == TK_AsIs)
+             return false;
+           return !isa<CXXDefaultArgExpr>(Child);
+         })) {
+      Visit(Child);
+    }
+  }
+
   void VisitExpressionTemplateArgument(const TemplateArgument &TA) {
     Visit(TA.getAsExpr());
   }
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -227,7 +227,9 @@
 AST Matchers
 ------------
 
-- ...
+- The behavior of TK_IgnoreUnlessSpelledInSource with the traverse() matcher
+  has been changed to no longer match on template instantiations or on
+  implicit nodes which are not spelled in the source.
 
 clang-format
 ------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to