steveire created this revision.
steveire added reviewers: sammccall, aaron.ballman, gribozavr2, ymandel, klimek.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
steveire updated this revision to Diff 267750.
steveire added a comment.

Update


IgnoreUnlessSpelledInSource mode should ignore these because they are
not written in the source.  This matters for example when trying to
replace types or values which are templated.  The new test in
TransformerTest.cpp in this commit demonstrates the problem.

In existing matcher code, users can write
`unless(isInTemplateInstantiation())` or `unless(isInstantiated())` (the
user must know which to use).  The point of the
TK_IgnoreUnlessSpelledInSource mode is to allow the novice to avoid such
details.  This patch changes the IgnoreUnlessSpelledInSource mode to
skip over implicit template instantiations.

This patch does not change the TK_AsIs mode. Adjust existing clang-tidy
matchers which explicitly desire to match implicit template
instantiations.

Note: An obvious attempt at an alternative implementation would simply
change the shouldVisitTemplateInstantiations() in ASTMatchFinder.cpp to
return something conditional on the operational TraversalKind.  That
does not work because shouldVisitTemplateInstantiations() is called
before a possible top-level traverse() matcher changes the operational
TraversalKind.

WIP: This change is WIP because I have not yet adjusted unit tests which
currently rely on the current behavior.  I am soliciting feedback to
determine whether there is mood to proceed.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80961

Files:
  clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp
  clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
  clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
  clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
  clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
  clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
  clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
  clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
  clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
  clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
  
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
  clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/AST/ASTDumper.cpp
  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
@@ -695,6 +695,70 @@
   EXPECT_EQ(ErrorCount, 0);
 }
 
+TEST_F(TransformerTest, TemplateInstantiation) {
+
+  std::string NonTemplatesInput = R"cpp(
+struct S {
+  int m_i;
+};
+)cpp";
+  std::string NonTemplatesExpected = R"cpp(
+struct S {
+  safe_int m_i;
+};
+)cpp";
+
+  std::string TemplatesInput = R"cpp(
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+}
+)cpp";
+
+  auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
+
+  // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
+  testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
+                    changeTo(cat("safe_int ", name("theField")))),
+           NonTemplatesInput + TemplatesInput,
+           NonTemplatesExpected + TemplatesInput);
+
+  // In AsIs mode, template instantiations are modified, which is
+  // often not desired:
+
+  std::string IncorrectTemplatesExpected = R"cpp(
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  safe_int m_t;
+};
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+}
+)cpp";
+
+  // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
+  testRule(makeRule(traverse(TK_AsIs, MatchedField),
+                    changeTo(cat("safe_int ", name("theField")))),
+
+           NonTemplatesInput + TemplatesInput,
+           NonTemplatesExpected + IncorrectTemplatesExpected);
+}
+
 // Transformation of macro source text when the change encompasses the entirety
 // of the expanded text.
 TEST_F(TransformerTest, SimpleMacro) {
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1890,7 +1890,60 @@
                    substNonTypeTemplateParmExpr(has(integerLiteral())))))))));
 
   EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource,
-                                     staticAssertDecl(has(integerLiteral())))));
+                                     staticAssertDecl(has(declRefExpr())))));
+
+  Code = R"cpp(
+
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+template<typename T>
+T timesTwo(T input)
+{
+  return input * 2;
+}
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+  TemplStruct<double> td;
+  (void)timesTwo<int>(2);
+  (void)timesTwo<double>(2);
+}
+
+)cpp";
+  {
+    auto M = cxxRecordDecl(hasName("TemplStruct"),
+                           has(fieldDecl(hasType(asString("int")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M = cxxRecordDecl(hasName("TemplStruct"),
+                           has(fieldDecl(hasType(asString("double")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M =
+        functionDecl(hasName("timesTwo"),
+                     hasParameter(0, parmVarDecl(hasType(asString("int")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    auto M =
+        functionDecl(hasName("timesTwo"),
+                     hasParameter(0, parmVarDecl(hasType(asString("double")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
 }
 
 template <typename MatcherT>
@@ -3337,24 +3390,24 @@
   StatementMatcher IsPlacementNew = cxxNewExpr(hasAnyPlacementArg(anything()));
 
   EXPECT_TRUE(matches(R"(
-    void* operator new(decltype(sizeof(void*)), void*); 
+    void* operator new(decltype(sizeof(void*)), void*);
     int *foo(void* Storage) {
-      return new (Storage) int; 
+      return new (Storage) int;
     })",
                       IsPlacementNew));
 
   EXPECT_TRUE(matches(R"(
-    void* operator new(decltype(sizeof(void*)), void*, unsigned); 
+    void* operator new(decltype(sizeof(void*)), void*, unsigned);
     int *foo(void* Storage) {
-      return new (Storage, 16) int; 
+      return new (Storage, 16) int;
     })",
                       cxxNewExpr(hasPlacementArg(
                           1, ignoringImpCasts(integerLiteral(equals(16)))))));
 
   EXPECT_TRUE(notMatches(R"(
-    void* operator new(decltype(sizeof(void*)), void*); 
+    void* operator new(decltype(sizeof(void*)), void*);
     int *foo(void* Storage) {
-      return new int; 
+      return new int;
     })",
                          IsPlacementNew));
 }
Index: clang/unittests/AST/ASTTraverserTest.cpp
===================================================================
--- clang/unittests/AST/ASTTraverserTest.cpp
+++ clang/unittests/AST/ASTTraverserTest.cpp
@@ -68,6 +68,14 @@
   void Visit(const TemplateArgument &A, SourceRange R = {},
              const Decl *From = nullptr, const char *Label = nullptr) {
     OS << "TemplateArgument";
+    switch (A.getKind()) {
+    case TemplateArgument::Type: {
+      OS << " type " << A.getAsType().getAsString();
+      break;
+    }
+    default:
+      break;
+    }
   }
 
   template <typename... T> void Visit(T...) {}
@@ -420,8 +428,9 @@
 
   {
     auto FN = ast_matchers::match(
-        functionDecl(hasName("template_test"),
-                     hasDescendant(staticAssertDecl().bind("staticAssert"))),
+        traverse(TK_AsIs, functionDecl(hasName("template_test"),
+                                       hasDescendant(staticAssertDecl().bind(
+                                           "staticAssert")))),
         AST->getASTContext());
     EXPECT_EQ(FN.size(), 2u);
 
@@ -873,4 +882,141 @@
   }
 }
 
+TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
+
+  auto AST = buildASTFromCode(R"cpp(
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+template<typename T>
+T timesTwo(T input)
+{
+  return input * 2;
+}
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+  TemplStruct<double> td;
+  (void)timesTwo<int>(2);
+  (void)timesTwo<double>(2);
+}
+)cpp");
+  {
+    auto BN = ast_matchers::match(
+        classTemplateDecl(hasName("TemplStruct")).bind("rec"),
+        AST->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+ClassTemplateDecl 'TemplStruct'
+|-TemplateTypeParmDecl 'T'
+`-CXXRecordDecl 'TemplStruct'
+  |-CXXRecordDecl 'TemplStruct'
+  |-CXXConstructorDecl 'TemplStruct<T>'
+  | `-CompoundStmt
+  |-CXXDestructorDecl '~TemplStruct<T>'
+  | `-CompoundStmt
+  |-AccessSpecDecl
+  `-FieldDecl 'm_t'
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+ClassTemplateDecl 'TemplStruct'
+|-TemplateTypeParmDecl 'T'
+|-CXXRecordDecl 'TemplStruct'
+| |-CXXRecordDecl 'TemplStruct'
+| |-CXXConstructorDecl 'TemplStruct<T>'
+| | `-CompoundStmt
+| |-CXXDestructorDecl '~TemplStruct<T>'
+| | `-CompoundStmt
+| |-AccessSpecDecl
+| `-FieldDecl 'm_t'
+|-ClassTemplateSpecializationDecl 'TemplStruct'
+| |-TemplateArgument type int
+| |-CXXRecordDecl 'TemplStruct'
+| |-CXXConstructorDecl 'TemplStruct'
+| | `-CompoundStmt
+| |-CXXDestructorDecl '~TemplStruct'
+| | `-CompoundStmt
+| |-AccessSpecDecl
+| |-FieldDecl 'm_t'
+| `-CXXConstructorDecl 'TemplStruct'
+|   `-ParmVarDecl ''
+`-ClassTemplateSpecializationDecl 'TemplStruct'
+  |-TemplateArgument type double
+  |-CXXRecordDecl 'TemplStruct'
+  |-CXXConstructorDecl 'TemplStruct'
+  | `-CompoundStmt
+  |-CXXDestructorDecl '~TemplStruct'
+  | `-CompoundStmt
+  |-AccessSpecDecl
+  |-FieldDecl 'm_t'
+  `-CXXConstructorDecl 'TemplStruct'
+    `-ParmVarDecl ''
+)cpp");
+  }
+  {
+    auto BN = ast_matchers::match(
+        functionTemplateDecl(hasName("timesTwo")).bind("fn"),
+        AST->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("fn")),
+              R"cpp(
+FunctionTemplateDecl 'timesTwo'
+|-TemplateTypeParmDecl 'T'
+`-FunctionDecl 'timesTwo'
+  |-ParmVarDecl 'input'
+  `-CompoundStmt
+    `-ReturnStmt
+      `-BinaryOperator
+        |-DeclRefExpr 'input'
+        `-IntegerLiteral
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
+              R"cpp(
+FunctionTemplateDecl 'timesTwo'
+|-TemplateTypeParmDecl 'T'
+|-FunctionDecl 'timesTwo'
+| |-ParmVarDecl 'input'
+| `-CompoundStmt
+|   `-ReturnStmt
+|     `-BinaryOperator
+|       |-DeclRefExpr 'input'
+|       `-IntegerLiteral
+|-FunctionDecl 'timesTwo'
+| |-TemplateArgument type int
+| |-ParmVarDecl 'input'
+| `-CompoundStmt
+|   `-ReturnStmt
+|     `-BinaryOperator
+|       |-ImplicitCastExpr
+|       | `-DeclRefExpr 'input'
+|       `-IntegerLiteral
+`-FunctionDecl 'timesTwo'
+  |-TemplateArgument type double
+  |-ParmVarDecl 'input'
+  `-CompoundStmt
+    `-ReturnStmt
+      `-BinaryOperator
+        |-ImplicitCastExpr
+        | `-DeclRefExpr 'input'
+        `-ImplicitCastExpr
+          `-IntegerLiteral
+)cpp");
+  }
+}
+
 } // namespace clang
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -282,6 +282,13 @@
   TraversalKindScope RAII(Finder->getASTContext(),
                           Implementation->TraversalKind());
 
+  if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
+      TK_IgnoreUnlessSpelledInSource) {
+    if (Finder->isMatchingInImplicitTemplateInstantiation()) {
+      return false;
+    }
+  }
+
   auto N =
       Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode);
 
Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -561,6 +561,114 @@
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return true; }
 
+  bool m_traversingImplicitTemplateInstantiation = false;
+
+  bool isMatchingInImplicitTemplateInstantiation() const override {
+    return m_traversingImplicitTemplateInstantiation;
+  }
+
+  struct ImplicitTemplateInstantiationScope {
+    ImplicitTemplateInstantiationScope(MatchASTVisitor *V, bool b) : m_V(V) {
+      m_B = V->m_traversingImplicitTemplateInstantiation;
+      V->m_traversingImplicitTemplateInstantiation = b;
+    }
+    ~ImplicitTemplateInstantiationScope() {
+      m_V->m_traversingImplicitTemplateInstantiation = m_B;
+    }
+
+  private:
+    MatchASTVisitor *m_V;
+    bool m_B;
+  };
+
+#define TRY_TO(CALL_EXPR)                                                      \
+  do {                                                                         \
+    if (!getDerived().CALL_EXPR)                                               \
+      return false;                                                            \
+  } while (false)
+
+  bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
+    for (auto *SD : D->specializations()) {
+      for (auto *RD : SD->redecls()) {
+        // We don't want to visit injected-class-names in this traversal.
+        if (cast<CXXRecordDecl>(RD)->isInjectedClassName())
+          continue;
+
+        switch (cast<ClassTemplateSpecializationDecl>(RD)
+                    ->getSpecializationKind()) {
+        // Visit the implicit instantiations with the requested pattern.
+        case TSK_Undeclared:
+        case TSK_ImplicitInstantiation: {
+          ImplicitTemplateInstantiationScope RAII(this, true);
+          TRY_TO(TraverseDecl(RD));
+          break;
+        }
+
+        // We don't need to do anything on an explicit instantiation
+        // or explicit specialization because there will be an explicit
+        // node for it elsewhere.
+        case TSK_ExplicitInstantiationDeclaration:
+        case TSK_ExplicitInstantiationDefinition:
+        case TSK_ExplicitSpecialization:
+          break;
+        }
+      }
+    }
+
+    return true;
+  }
+
+  bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
+    for (auto *SD : D->specializations()) {
+      for (auto *RD : SD->redecls()) {
+        switch (
+            cast<VarTemplateSpecializationDecl>(RD)->getSpecializationKind()) {
+        case TSK_Undeclared:
+        case TSK_ImplicitInstantiation: {
+          ImplicitTemplateInstantiationScope RAII(this, true);
+          TRY_TO(TraverseDecl(RD));
+          break;
+        }
+
+        case TSK_ExplicitInstantiationDeclaration:
+        case TSK_ExplicitInstantiationDefinition:
+        case TSK_ExplicitSpecialization:
+          break;
+        }
+      }
+    }
+
+    return true;
+  }
+
+  bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
+    for (auto *FD : D->specializations()) {
+      for (auto *RD : FD->redecls()) {
+        switch (RD->getTemplateSpecializationKind()) {
+        case TSK_Undeclared:
+        case TSK_ImplicitInstantiation: {
+          // We don't know what kind of FunctionDecl this is.
+          ImplicitTemplateInstantiationScope RAII(this, true);
+          TRY_TO(TraverseDecl(RD));
+          break;
+        }
+
+        // FIXME: For now traverse explicit instantiations here. Change that
+        // once they are represented as dedicated nodes in the AST.
+        case TSK_ExplicitInstantiationDeclaration:
+        case TSK_ExplicitInstantiationDefinition:
+          TRY_TO(TraverseDecl(RD));
+          break;
+
+        case TSK_ExplicitSpecialization:
+          break;
+        }
+      }
+    }
+
+    return true;
+  }
+
 private:
   class TimeBucketRegion {
   public:
Index: clang/lib/AST/ASTDumper.cpp
===================================================================
--- clang/lib/AST/ASTDumper.cpp
+++ clang/lib/AST/ASTDumper.cpp
@@ -129,9 +129,10 @@
 
   Visit(D->getTemplatedDecl());
 
-  for (const auto *Child : D->specializations())
-    dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
-                                   !D->isCanonicalDecl());
+  if (GetTraversalKind() == TK_AsIs)
+    for (const auto *Child : D->specializations())
+      dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
+                                     !D->isCanonicalDecl());
 }
 
 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1056,6 +1056,8 @@
 
   virtual ASTContext &getASTContext() const = 0;
 
+  virtual bool isMatchingInImplicitTemplateInstantiation() const = 0;
+
 protected:
   virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
                               const DynTypedMatcher &Matcher,
Index: clang/include/clang/AST/ASTNodeTraverser.h
===================================================================
--- clang/include/clang/AST/ASTNodeTraverser.h
+++ clang/include/clang/AST/ASTNodeTraverser.h
@@ -78,6 +78,7 @@
   bool getDeserialize() const { return Deserialize; }
 
   void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
+  TraversalKind GetTraversalKind() const { return Traversal; }
 
   void Visit(const Decl *D) {
     getNodeDelegate().AddChild([=] {
@@ -475,8 +476,9 @@
 
     Visit(D->getTemplatedDecl());
 
-    for (const auto *Child : D->specializations())
-      dumpTemplateDeclSpecialization(Child);
+    if (Traversal == TK_AsIs)
+      for (const auto *Child : D->specializations())
+        dumpTemplateDeclSpecialization(Child);
   }
 
   void VisitTypeAliasDecl(const TypeAliasDecl *D) {
Index: clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp
+++ clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp
@@ -28,11 +28,12 @@
 
 void TemporaryObjectsCheck::registerMatchers(MatchFinder *Finder) {
   // Matcher for default constructors.
-  Finder->addMatcher(
-      cxxTemporaryObjectExpr(hasDeclaration(cxxConstructorDecl(hasParent(
-                                 cxxRecordDecl(matchesAnyName(Names))))))
-          .bind("temps"),
-      this);
+  Finder->addMatcher(traverse(ast_type_traits::TK_AsIs,
+                              cxxTemporaryObjectExpr(
+                                  hasDeclaration(cxxConstructorDecl(hasParent(
+                                      cxxRecordDecl(matchesAnyName(Names))))))
+                                  .bind("temps")),
+                     this);
 
   // Matcher for user-defined constructors.
   Finder->addMatcher(
Index: clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -39,8 +39,7 @@
 void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()),
-                                      varDecl(hasStaticStorageDuration()))),
-                 unless(isInTemplateInstantiation()))
+                                      varDecl(hasStaticStorageDuration()))))
           .bind("memberExpression"),
       this);
 }
Index: clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
@@ -127,30 +127,35 @@
   auto IsBoundToType = refersToType(equalsBoundNode("type"));
 
   Finder->addMatcher(
-      ExplicitSingleVarDecl(hasType(autoType(hasDeducedType(
+      traverse(TK_AsIs, ExplicitSingleVarDecl(
+                            hasType(autoType(hasDeducedType(
                                 pointerType(pointee(unless(functionType())))))),
-                            "auto"),
+                            "auto")),
       this);
 
   Finder->addMatcher(
-      ExplicitSingleVarDeclInTemplate(
-          allOf(hasType(autoType(hasDeducedType(pointerType(
-                    pointee(hasUnqualifiedType(qualType().bind("type")),
-                            unless(functionType())))))),
-                anyOf(hasAncestor(
-                          functionDecl(hasAnyTemplateArgument(IsBoundToType))),
-                      hasAncestor(classTemplateSpecializationDecl(
-                          hasAnyTemplateArgument(IsBoundToType))))),
-          "auto"),
+      traverse(TK_AsIs,
+               ExplicitSingleVarDeclInTemplate(
+                   allOf(hasType(autoType(hasDeducedType(pointerType(pointee(
+                             hasUnqualifiedType(qualType().bind("type")),
+                             unless(functionType())))))),
+                         anyOf(hasAncestor(functionDecl(
+                                   hasAnyTemplateArgument(IsBoundToType))),
+                               hasAncestor(classTemplateSpecializationDecl(
+                                   hasAnyTemplateArgument(IsBoundToType))))),
+                   "auto")),
       this);
   if (!AddConstToQualified)
     return;
-  Finder->addMatcher(ExplicitSingleVarDecl(
-                         hasType(pointerType(pointee(autoType()))), "auto_ptr"),
-                     this);
   Finder->addMatcher(
-      ExplicitSingleVarDecl(hasType(lValueReferenceType(pointee(autoType()))),
-                            "auto_ref"),
+      traverse(TK_AsIs,
+               ExplicitSingleVarDecl(hasType(pointerType(pointee(autoType()))),
+                                     "auto_ptr")),
+      this);
+  Finder->addMatcher(
+      traverse(TK_AsIs, ExplicitSingleVarDecl(
+                            hasType(lValueReferenceType(pointee(autoType()))),
+                            "auto_ref")),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -55,13 +55,15 @@
           hasParent(explicitCastExpr(hasDestinationType(booleanType())))));
 
   Finder->addMatcher(
-      cxxMemberCallExpr(on(expr(anyOf(hasType(ValidContainer),
-                                      hasType(pointsTo(ValidContainer)),
-                                      hasType(references(ValidContainer))))),
-                        callee(cxxMethodDecl(hasName("size"))), WrongUse,
-                        unless(hasAncestor(cxxMethodDecl(
-                            ofClass(equalsBoundNode("container"))))))
-          .bind("SizeCallExpr"),
+      traverse(TK_AsIs,
+               cxxMemberCallExpr(
+                   on(expr(anyOf(hasType(ValidContainer),
+                                 hasType(pointsTo(ValidContainer)),
+                                 hasType(references(ValidContainer))))),
+                   callee(cxxMethodDecl(hasName("size"))), WrongUse,
+                   unless(hasAncestor(
+                       cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+                   .bind("SizeCallExpr")),
       this);
 
   // Empty constructor matcher.
@@ -86,13 +88,15 @@
                     expr(hasType(pointsTo(ValidContainer))).bind("Pointee"))),
             expr(hasType(ValidContainer)).bind("STLObject"));
   Finder->addMatcher(
-      cxxOperatorCallExpr(
-          hasAnyOverloadedOperatorName("==", "!="),
-          anyOf(allOf(hasArgument(0, WrongComparend), hasArgument(1, STLArg)),
-                allOf(hasArgument(0, STLArg), hasArgument(1, WrongComparend))),
-          unless(hasAncestor(
-              cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
-          .bind("BinCmp"),
+      traverse(TK_AsIs,
+               cxxOperatorCallExpr(hasAnyOverloadedOperatorName("==", "!="),
+                                   anyOf(allOf(hasArgument(0, WrongComparend),
+                                               hasArgument(1, STLArg)),
+                                         allOf(hasArgument(0, STLArg),
+                                               hasArgument(1, WrongComparend))),
+                                   unless(hasAncestor(cxxMethodDecl(
+                                       ofClass(equalsBoundNode("container"))))))
+                   .bind("BinCmp")),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
@@ -69,15 +69,17 @@
                  "find_last_of", "find_last_not_of");
 
   Finder->addMatcher(
-      cxxMemberCallExpr(
-          callee(functionDecl(StringFindFunctions).bind("func")),
-          anyOf(argumentCountIs(1), argumentCountIs(2)),
-          hasArgument(0, SingleChar),
-          on(expr(
-              hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
-                  recordDecl(hasAnyName(SmallVector<StringRef, 4>(
-                      StringLikeClasses.begin(), StringLikeClasses.end()))))))),
-              unless(hasSubstitutedType())))),
+      traverse(TK_AsIs,
+               cxxMemberCallExpr(
+                   callee(functionDecl(StringFindFunctions).bind("func")),
+                   anyOf(argumentCountIs(1), argumentCountIs(2)),
+                   hasArgument(0, SingleChar),
+                   on(expr(hasType(hasUnqualifiedDesugaredType(
+                               recordType(hasDeclaration(recordDecl(
+                                   hasAnyName(SmallVector<StringRef, 4>(
+                                       StringLikeClasses.begin(),
+                                       StringLikeClasses.end()))))))),
+                           unless(hasSubstitutedType()))))),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
@@ -21,29 +21,32 @@
 
   // Using declaration: warning and fix-it.
   Finder->addMatcher(
-      usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(hasName(MatchText))))
-          .bind("using_decl"),
+      traverse(TK_AsIs, usingDecl(hasAnyUsingShadowDecl(
+                                      hasTargetDecl(hasName(MatchText))))
+                            .bind("using_decl")),
       this);
 
   // DeclRefExpr: warning, no fix-it.
   Finder->addMatcher(
-      declRefExpr(to(functionDecl(hasName(MatchText))), unless(callExpr()))
-          .bind("decl_ref_expr"),
+      traverse(TK_AsIs, declRefExpr(to(functionDecl(hasName(MatchText))),
+                                    unless(callExpr()))
+                            .bind("decl_ref_expr")),
       this);
 
   auto DirectCallToUncaughtException = callee(expr(ignoringImpCasts(
       declRefExpr(hasDeclaration(functionDecl(hasName(MatchText)))))));
 
   // CallExpr: warning, fix-it.
-  Finder->addMatcher(callExpr(DirectCallToUncaughtException,
-                              unless(hasAncestor(initListExpr())))
-                         .bind("call_expr"),
-                     this);
+  Finder->addMatcher(
+      traverse(TK_AsIs, callExpr(DirectCallToUncaughtException,
+                                 unless(hasAncestor(initListExpr())))
+                            .bind("call_expr")),
+      this);
   // CallExpr in initialisation list: warning, fix-it with avoiding narrowing
   // conversions.
-  Finder->addMatcher(callExpr(DirectCallToUncaughtException,
-                              hasAncestor(initListExpr()))
-                         .bind("init_call_expr"),
+  Finder->addMatcher(traverse(TK_AsIs, callExpr(DirectCallToUncaughtException,
+                                                hasAncestor(initListExpr()))
+                                           .bind("init_call_expr")),
                      this);
 }
 
Index: clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
@@ -34,10 +34,13 @@
 void UseOverrideCheck::registerMatchers(MatchFinder *Finder) {
   if (IgnoreDestructors)
     Finder->addMatcher(
-        cxxMethodDecl(isOverride(), unless(cxxDestructorDecl())).bind("method"),
+        traverse(TK_AsIs,
+                 cxxMethodDecl(isOverride(), unless(cxxDestructorDecl()))
+                     .bind("method")),
         this);
   else
-    Finder->addMatcher(cxxMethodDecl(isOverride()).bind("method"), this);
+    Finder->addMatcher(
+        traverse(TK_AsIs, cxxMethodDecl(isOverride()).bind("method")), this);
 }
 
 // Re-lex the tokens to get precise locations to insert 'override' and remove
Index: clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
@@ -95,19 +95,23 @@
   //
   //   std::auto_ptr<int> fn(std::auto_ptr<int>);
   //        ^~~~~~~~~~~~~         ^~~~~~~~~~~~~
-  Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
-                                          // Skip elaboratedType() as the named
-                                          // type will match soon thereafter.
-                                          unless(elaboratedType()))))
-                         .bind(AutoPtrTokenId),
-                     this);
+  Finder->addMatcher(
+      traverse(TK_AsIs,
+               typeLoc(loc(qualType(AutoPtrType,
+                                    // Skip elaboratedType() as the named
+                                    // type will match soon thereafter.
+                                    unless(elaboratedType()))))
+                   .bind(AutoPtrTokenId)),
+      this);
 
   //   using std::auto_ptr;
   //   ^~~~~~~~~~~~~~~~~~~
-  Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
-                                   hasName("auto_ptr"), isFromStdNamespace()))))
-                         .bind(AutoPtrTokenId),
-                     this);
+  Finder->addMatcher(
+      traverse(TK_AsIs,
+               usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
+                             hasName("auto_ptr"), isFromStdNamespace()))))
+                   .bind(AutoPtrTokenId)),
+      this);
 
   // Find ownership transfers via copy construction and assignment.
   // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
@@ -119,9 +123,10 @@
       expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
 
   Finder->addMatcher(
-      cxxOperatorCallExpr(hasOverloadedOperatorName("="),
-                          callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
-                          hasArgument(1, MovableArgumentMatcher)),
+      traverse(TK_AsIs,
+               cxxOperatorCallExpr(hasOverloadedOperatorName("="),
+                                   callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
+                                   hasArgument(1, MovableArgumentMatcher))),
       this);
   Finder->addMatcher(
       traverse(ast_type_traits::TK_AsIs,
Index: clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -114,6 +114,8 @@
   // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
   // 'std::make_unique' or other function that creates smart_ptr.
 
+  TraversalKindScope RAII(*Result.Context, TK_AsIs);
+
   SourceManager &SM = *Result.SourceManager;
   const auto *Construct =
       Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
Index: clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp
@@ -34,7 +34,8 @@
   auto IoStateType =
       qualType(hasDeclaration(IoStateDecl), unless(elaboratedType()));
 
-  Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this);
+  Finder->addMatcher(
+      traverse(TK_AsIs, typeLoc(loc(IoStateType)).bind("TypeLoc")), this);
 }
 
 void DeprecatedIosBaseAliasesCheck::check(
Index: clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
+++ clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
@@ -18,23 +18,25 @@
 
 void ExceptionBaseclassCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      cxxThrowExpr(
-          unless(has(expr(anyOf(isTypeDependent(), isValueDependent())))),
-          // The thrown value is not derived from 'std::exception'.
-          has(expr(unless(
-              hasType(qualType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
-                  isSameOrDerivedFrom(hasName("::std::exception")))))))))),
-          // This condition is always true, but will bind to the
-          // template value if the thrown type is templated.
-          anyOf(has(expr(
-                    hasType(substTemplateTypeParmType().bind("templ_type")))),
-                anything()),
-          // Bind to the declaration of the type of the value that
-          // is thrown. 'anything()' is necessary to always succeed
-          // in the 'eachOf' because builtin types are not
-          // 'namedDecl'.
-          eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything()))
-          .bind("bad_throw"),
+      traverse(
+          TK_AsIs,
+          cxxThrowExpr(
+              unless(has(expr(anyOf(isTypeDependent(), isValueDependent())))),
+              // The thrown value is not derived from 'std::exception'.
+              has(expr(unless(hasType(
+                  qualType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
+                      isSameOrDerivedFrom(hasName("::std::exception")))))))))),
+              // This condition is always true, but will bind to the
+              // template value if the thrown type is templated.
+              anyOf(has(expr(hasType(
+                        substTemplateTypeParmType().bind("templ_type")))),
+                    anything()),
+              // Bind to the declaration of the type of the value that
+              // is thrown. 'anything()' is necessary to always succeed
+              // in the 'eachOf' because builtin types are not
+              // 'namedDecl'.
+              eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything()))
+              .bind("bad_throw")),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
+++ clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
@@ -168,10 +168,11 @@
                               .bind("class")))))
           .bind("method");
 
-  Finder->addMatcher(expr(anyOf(callExpr(callee(Methods)).bind("call"),
-                                declRefExpr(to(Methods)).bind("ref")),
-                          LocationFilter),
-                     this);
+  Finder->addMatcher(
+      traverse(TK_AsIs, expr(anyOf(callExpr(callee(Methods)).bind("call"),
+                                   declRefExpr(to(Methods)).bind("ref")),
+                             LocationFilter)),
+      this);
 
   Finder->addMatcher(
       usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(Methods)), LocationFilter)
Index: clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
@@ -216,11 +216,13 @@
 
 void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      cxxMethodDecl(
-          unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(),
-                       cxxDestructorDecl(), cxxConversionDecl(), isStatic(),
-                       isOverloadedOperator())))
-          .bind("method"),
+      traverse(
+          TK_AsIs,
+          cxxMethodDecl(
+              unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(),
+                           cxxDestructorDecl(), cxxConversionDecl(), isStatic(),
+                           isOverloadedOperator())))
+              .bind("method")),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
@@ -30,18 +30,20 @@
 
   // Check whether destination object is not TriviallyCopyable.
   // Applicable to all three memory manipulation functions.
-  Finder->addMatcher(callExpr(callee(functionDecl(hasAnyName(
-                                  "::memset", "::memcpy", "::memmove"))),
-                              hasArgument(0, NotTriviallyCopyableObject))
-                         .bind("dest"),
-                     this);
+  Finder->addMatcher(
+      traverse(TK_AsIs, callExpr(callee(functionDecl(hasAnyName(
+                                     "::memset", "::memcpy", "::memmove"))),
+                                 hasArgument(0, NotTriviallyCopyableObject))
+                            .bind("dest")),
+      this);
 
   // Check whether source object is not TriviallyCopyable.
   // Only applicable to memcpy() and memmove().
   Finder->addMatcher(
-      callExpr(callee(functionDecl(hasAnyName("::memcpy", "::memmove"))),
-               hasArgument(1, NotTriviallyCopyableObject))
-          .bind("src"),
+      traverse(TK_AsIs, callExpr(callee(functionDecl(
+                                     hasAnyName("::memcpy", "::memmove"))),
+                                 hasArgument(1, NotTriviallyCopyableObject))
+                            .bind("src")),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
@@ -79,20 +79,22 @@
       expr(ignoringParenImpCasts(hasType(isInteger()))).bind(LoopIncrementName);
 
   Finder->addMatcher(
-      forStmt(
-          hasCondition(anyOf(
-              binaryOperator(hasOperatorName("<"),
-                             hasLHS(LoopVarConversionMatcher),
-                             hasRHS(LoopBoundMatcher)),
-              binaryOperator(hasOperatorName("<="),
-                             hasLHS(LoopVarConversionMatcher),
-                             hasRHS(LoopBoundMatcher)),
-              binaryOperator(hasOperatorName(">"), hasLHS(LoopBoundMatcher),
-                             hasRHS(LoopVarConversionMatcher)),
-              binaryOperator(hasOperatorName(">="), hasLHS(LoopBoundMatcher),
-                             hasRHS(LoopVarConversionMatcher)))),
-          hasIncrement(IncrementMatcher))
-          .bind(LoopName),
+      traverse(TK_AsIs,
+               forStmt(hasCondition(anyOf(
+                           binaryOperator(hasOperatorName("<"),
+                                          hasLHS(LoopVarConversionMatcher),
+                                          hasRHS(LoopBoundMatcher)),
+                           binaryOperator(hasOperatorName("<="),
+                                          hasLHS(LoopVarConversionMatcher),
+                                          hasRHS(LoopBoundMatcher)),
+                           binaryOperator(hasOperatorName(">"),
+                                          hasLHS(LoopBoundMatcher),
+                                          hasRHS(LoopVarConversionMatcher)),
+                           binaryOperator(hasOperatorName(">="),
+                                          hasLHS(LoopBoundMatcher),
+                                          hasRHS(LoopVarConversionMatcher)))),
+                       hasIncrement(IncrementMatcher))
+                   .bind(LoopName)),
       this);
 }
 
Index: clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
@@ -97,9 +97,10 @@
   //       the sizeof size_t.
   if (WarnOnSizeOfConstant) {
     Finder->addMatcher(
-        expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),
-             unless(SizeOfZero))
-            .bind("sizeof-constant"),
+        traverse(TK_AsIs,
+                 expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),
+                      unless(SizeOfZero))
+                     .bind("sizeof-constant")),
         this);
   }
 
@@ -186,14 +187,15 @@
   const auto DenomType = qualType(hasCanonicalType(type().bind("denom-type")));
 
   Finder->addMatcher(
-      binaryOperator(hasOperatorName("/"),
-                     hasLHS(expr(ignoringParenImpCasts(
-                         anyOf(sizeOfExpr(has(NumType)),
-                               sizeOfExpr(has(expr(hasType(NumType)))))))),
-                     hasRHS(expr(ignoringParenImpCasts(
-                         anyOf(sizeOfExpr(has(DenomType)),
-                               sizeOfExpr(has(expr(hasType(DenomType)))))))))
-          .bind("sizeof-divide-expr"),
+      traverse(TK_AsIs,
+               binaryOperator(hasOperatorName("/"),
+                              hasLHS(expr(ignoringParenImpCasts(anyOf(
+                                  sizeOfExpr(has(NumType)),
+                                  sizeOfExpr(has(expr(hasType(NumType)))))))),
+                              hasRHS(expr(ignoringParenImpCasts(anyOf(
+                                  sizeOfExpr(has(DenomType)),
+                                  sizeOfExpr(has(expr(hasType(DenomType)))))))))
+                   .bind("sizeof-divide-expr")),
       this);
 
   // Detect expression like: sizeof(...) * sizeof(...)); most likely an error.
Index: clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
+++ clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp
@@ -29,57 +29,66 @@
   // Match expressions like `a *= b` and `a /= b` where `a` has type
   // `absl::Duration` and `b` is not of a built-in type.
   Finder->addMatcher(
-      cxxOperatorCallExpr(
-          argumentCountIs(2),
-          hasArgument(
-              0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))),
-          hasArgument(1, expr().bind("arg")),
-          callee(functionDecl(
-              hasParent(functionTemplateDecl()),
-              unless(hasTemplateArgument(0, refersToType(builtinType()))),
-              hasAnyName("operator*=", "operator/="))))
-          .bind("OuterExpr"),
+      traverse(
+          ast_type_traits::TK_AsIs,
+          cxxOperatorCallExpr(
+              argumentCountIs(2),
+              hasArgument(
+                  0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))),
+              hasArgument(1, expr().bind("arg")),
+              callee(functionDecl(
+                  hasParent(functionTemplateDecl()),
+                  unless(hasTemplateArgument(0, refersToType(builtinType()))),
+                  hasAnyName("operator*=", "operator/="))))
+              .bind("OuterExpr")),
       this);
 
   // Match expressions like `a.operator*=(b)` and `a.operator/=(b)` where `a`
   // has type `absl::Duration` and `b` is not of a built-in type.
   Finder->addMatcher(
-      cxxMemberCallExpr(
-          callee(cxxMethodDecl(
-              ofClass(cxxRecordDecl(hasName("::absl::Duration"))),
-              hasParent(functionTemplateDecl()),
-              unless(hasTemplateArgument(0, refersToType(builtinType()))),
-              hasAnyName("operator*=", "operator/="))),
-          argumentCountIs(1), hasArgument(0, expr().bind("arg")))
-          .bind("OuterExpr"),
+      traverse(
+          ast_type_traits::TK_AsIs,
+          cxxMemberCallExpr(
+              callee(cxxMethodDecl(
+                  ofClass(cxxRecordDecl(hasName("::absl::Duration"))),
+                  hasParent(functionTemplateDecl()),
+                  unless(hasTemplateArgument(0, refersToType(builtinType()))),
+                  hasAnyName("operator*=", "operator/="))),
+              argumentCountIs(1), hasArgument(0, expr().bind("arg")))
+              .bind("OuterExpr")),
       this);
 
   // Match expressions like `a * b`, `a / b`, `operator*(a, b)`, and
   // `operator/(a, b)` where `a` has type `absl::Duration` and `b` is not of a
   // built-in type.
   Finder->addMatcher(
-      callExpr(callee(functionDecl(
-                   hasParent(functionTemplateDecl()),
-                   unless(hasTemplateArgument(0, refersToType(builtinType()))),
-                   hasAnyName("::absl::operator*", "::absl::operator/"))),
-               argumentCountIs(2),
-               hasArgument(0, expr(hasType(
-                                  cxxRecordDecl(hasName("::absl::Duration"))))),
-               hasArgument(1, expr().bind("arg")))
-          .bind("OuterExpr"),
+      traverse(
+          ast_type_traits::TK_AsIs,
+          callExpr(
+              callee(functionDecl(
+                  hasParent(functionTemplateDecl()),
+                  unless(hasTemplateArgument(0, refersToType(builtinType()))),
+                  hasAnyName("::absl::operator*", "::absl::operator/"))),
+              argumentCountIs(2),
+              hasArgument(
+                  0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))),
+              hasArgument(1, expr().bind("arg")))
+              .bind("OuterExpr")),
       this);
 
   // Match expressions like `a * b` and `operator*(a, b)` where `a` is not of a
   // built-in type and `b` has type `absl::Duration`.
   Finder->addMatcher(
-      callExpr(callee(functionDecl(
-                   hasParent(functionTemplateDecl()),
-                   unless(hasTemplateArgument(0, refersToType(builtinType()))),
-                   hasName("::absl::operator*"))),
-               argumentCountIs(2), hasArgument(0, expr().bind("arg")),
-               hasArgument(1, expr(hasType(
-                                  cxxRecordDecl(hasName("::absl::Duration"))))))
-          .bind("OuterExpr"),
+      traverse(
+          ast_type_traits::TK_AsIs,
+          callExpr(callee(functionDecl(hasParent(functionTemplateDecl()),
+                                       unless(hasTemplateArgument(
+                                           0, refersToType(builtinType()))),
+                                       hasName("::absl::operator*"))),
+                   argumentCountIs(2), hasArgument(0, expr().bind("arg")),
+                   hasArgument(1, expr(hasType(cxxRecordDecl(
+                                      hasName("::absl::Duration"))))))
+              .bind("OuterExpr")),
       this);
 
   // For the factory functions, we match only the non-templated overloads that
Index: clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp
+++ clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp
@@ -114,7 +114,7 @@
                                           hasLHS(TimeInverseMatcher))
                                .bind("binop")))
             .bind("outer_call");
-    Finder->addMatcher(CallMatcher, this);
+    Finder->addMatcher(traverse(TK_AsIs, CallMatcher), this);
 
     // Match cases where we know the second operand is a 'Time'. Since
     // subtracting a 'Time' from a 'Duration' is not defined, in these cases,
@@ -122,7 +122,7 @@
     auto OperandMatcher =
         binaryOperator(hasOperatorName("-"), hasRHS(TimeInverseMatcher))
             .bind("binop");
-    Finder->addMatcher(OperandMatcher, this);
+    Finder->addMatcher(traverse(TK_AsIs, OperandMatcher), this);
   }
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to