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