steveire updated this revision to Diff 270517. steveire added a comment. Update
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D80961/new/ 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/misc/UnusedUsingDeclsCheck.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/AST/RecursiveASTVisitor.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/ASTContextParentMapTest.cpp clang/unittests/AST/ASTImporterTest.cpp clang/unittests/AST/ASTTraverserTest.cpp clang/unittests/AST/SourceLocationTest.cpp clang/unittests/AST/StructuralEquivalenceTest.cpp clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp clang/unittests/Sema/GslOwnerPointerInference.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/Sema/GslOwnerPointerInference.cpp =================================================================== --- clang/unittests/Sema/GslOwnerPointerInference.cpp +++ clang/unittests/Sema/GslOwnerPointerInference.cpp @@ -14,42 +14,45 @@ using namespace ast_matchers; TEST(OwnerPointer, BothHaveAttributes) { - EXPECT_TRUE(matches("template<class T>" - "class [[gsl::Owner]] C;" + EXPECT_TRUE(matches( + "template<class T>" + "class [[gsl::Owner]] C;" - "template<class T>" - "class [[gsl::Owner]] C {};" + "template<class T>" + "class [[gsl::Owner]] C {};" - "C<int> c;", - classTemplateSpecializationDecl( - hasName("C"), hasAttr(clang::attr::Owner)))); + "C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasName("C"), hasAttr(clang::attr::Owner))))); } TEST(OwnerPointer, ForwardDeclOnly) { - EXPECT_TRUE(matches("template<class T>" - "class [[gsl::Owner]] C;" + EXPECT_TRUE(matches( + "template<class T>" + "class [[gsl::Owner]] C;" - "template<class T>" - "class C {};" + "template<class T>" + "class C {};" - "C<int> c;", - classTemplateSpecializationDecl( - hasName("C"), hasAttr(clang::attr::Owner)))); + "C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasName("C"), hasAttr(clang::attr::Owner))))); } TEST(OwnerPointer, LateForwardDeclOnly) { - EXPECT_TRUE(matches("template<class T>" - "class C;" + EXPECT_TRUE(matches( + "template<class T>" + "class C;" - "template<class T>" - "class C {};" + "template<class T>" + "class C {};" - "template<class T>" - "class [[gsl::Owner]] C;" + "template<class T>" + "class [[gsl::Owner]] C;" - "C<int> c;", - classTemplateSpecializationDecl( - hasName("C"), hasAttr(clang::attr::Owner)))); + "C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasName("C"), hasAttr(clang::attr::Owner))))); } } // namespace clang Index: clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp =================================================================== --- clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -268,13 +268,15 @@ } TEST_F(RegistryTest, TemplateArgument) { - Matcher<Decl> HasTemplateArgument = constructMatcher( - "classTemplateSpecializationDecl", + Matcher<Decl> HasTemplateArgument = traverse( + TK_AsIs, constructMatcher( - "hasAnyTemplateArgument", - constructMatcher("refersToType", - constructMatcher("asString", StringRef("int"))))) - .getTypedMatcher<Decl>(); + "classTemplateSpecializationDecl", + constructMatcher( + "hasAnyTemplateArgument", + constructMatcher("refersToType", + constructMatcher("asString", StringRef("int"))))) + .getTypedMatcher<Decl>()); EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;", HasTemplateArgument)); EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;", Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -26,13 +26,14 @@ } TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { - EXPECT_TRUE(matches( - "template <typename T> struct A {" - " template <typename T2> struct F {};" - "};" - "template <typename T> struct B : A<T>::template F<T> {};" - "B<int> b;", - cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl())))); + EXPECT_TRUE( + matches("template <typename T> struct A {" + " template <typename T2> struct F {};" + "};" + "template <typename T> struct B : A<T>::template F<T> {};" + "B<int> b;", + traverse(TK_AsIs, cxxRecordDecl(hasName("B"), + isDerivedFrom(recordDecl()))))); } TEST(DeclarationMatcher, hasDeclContext) { @@ -828,33 +829,35 @@ TEST(Matcher, MatchesTypeTemplateArgument) { EXPECT_TRUE(matches( - "template<typename T> struct B {};" + "template<typename T> struct B {};" "B<int> b;", - classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( - asString("int")))))); + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToType(asString("int"))))))); } TEST(Matcher, MatchesTemplateTemplateArgument) { - EXPECT_TRUE(matches("template<template <typename> class S> class X {};" - "template<typename T> class Y {};" - "X<Y> xi;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToTemplate(templateName()))))); + EXPECT_TRUE(matches( + "template<template <typename> class S> class X {};" + "template<typename T> class Y {};" + "X<Y> xi;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToTemplate(templateName())))))); } TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) { - EXPECT_TRUE(matches( - "struct B { int next; };" - "template<int(B::*next_ptr)> struct A {};" - "A<&B::next> a;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToDeclaration(fieldDecl(hasName("next"))))))); + EXPECT_TRUE( + matches("struct B { int next; };" + "template<int(B::*next_ptr)> struct A {};" + "A<&B::next> a;", + traverse(TK_AsIs, + classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToDeclaration(fieldDecl(hasName("next")))))))); EXPECT_TRUE(notMatches( - "template <typename T> struct A {};" + "template <typename T> struct A {};" "A<int> a;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToDeclaration(decl()))))); + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToDeclaration(decl())))))); EXPECT_TRUE(matches( "struct B { int next; };" @@ -873,15 +876,15 @@ TEST(Matcher, MatchesSpecificArgument) { EXPECT_TRUE(matches( - "template<typename T, typename U> class A {};" + "template<typename T, typename U> class A {};" "A<bool, int> a;", - classTemplateSpecializationDecl(hasTemplateArgument( - 1, refersToType(asString("int")))))); + traverse(TK_AsIs, classTemplateSpecializationDecl(hasTemplateArgument( + 1, refersToType(asString("int"))))))); EXPECT_TRUE(notMatches( - "template<typename T, typename U> class A {};" + "template<typename T, typename U> class A {};" "A<int, bool> a;", - classTemplateSpecializationDecl(hasTemplateArgument( - 1, refersToType(asString("int")))))); + traverse(TK_AsIs, classTemplateSpecializationDecl(hasTemplateArgument( + 1, refersToType(asString("int"))))))); EXPECT_TRUE(matches( "template<typename T, typename U> class A {};" @@ -894,27 +897,30 @@ templateSpecializationType(hasTemplateArgument( 1, refersToType(asString("int")))))); - EXPECT_TRUE(matches( - "template<typename T> void f() {};" - "void func() { f<int>(); }", - functionDecl(hasTemplateArgument(0, refersToType(asString("int")))))); - EXPECT_TRUE(notMatches( - "template<typename T> void f() {};", - functionDecl(hasTemplateArgument(0, refersToType(asString("int")))))); + EXPECT_TRUE( + matches("template<typename T> void f() {};" + "void func() { f<int>(); }", + traverse(TK_AsIs, functionDecl(hasTemplateArgument( + 0, refersToType(asString("int"))))))); + EXPECT_TRUE( + notMatches("template<typename T> void f() {};", + traverse(TK_AsIs, functionDecl(hasTemplateArgument( + 0, refersToType(asString("int"))))))); } TEST(TemplateArgument, Matches) { - EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(templateArgument())))); + EXPECT_TRUE(matches( + "template<typename T> struct C {}; C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasAnyTemplateArgument(templateArgument()))))); EXPECT_TRUE(matches( "template<typename T> struct C {}; C<int> c;", templateSpecializationType(hasAnyTemplateArgument(templateArgument())))); - EXPECT_TRUE(matches( - "template<typename T> void f() {};" - "void func() { f<int>(); }", - functionDecl(hasAnyTemplateArgument(templateArgument())))); + EXPECT_TRUE(matches("template<typename T> void f() {};" + "void func() { f<int>(); }", + traverse(TK_AsIs, functionDecl(hasAnyTemplateArgument( + templateArgument()))))); } TEST(TemplateTypeParmDecl, CXXMethodDecl) { @@ -1005,13 +1011,14 @@ } TEST(RefersToIntegralType, Matches) { - EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(refersToIntegralType( - asString("int")))))); - EXPECT_TRUE(notMatches("template<unsigned T> struct C {}; C<42> c;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToIntegralType(asString("int")))))); + EXPECT_TRUE(matches( + "template<int T> struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToIntegralType(asString("int"))))))); + EXPECT_TRUE(notMatches( + "template<unsigned T> struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToIntegralType(asString("int"))))))); } TEST(ConstructorDeclaration, SimpleCase) { @@ -1381,13 +1388,13 @@ TEST(Matcher, VisitsTemplateInstantiations) { EXPECT_TRUE(matches( - "class A { public: void x(); };" + "class A { public: void x(); };" "template <typename T> class B { public: void y() { T t; t.x(); } };" "void f() { B<A> b; b.y(); }", - callExpr(callee(cxxMethodDecl(hasName("x")))))); + traverse(TK_AsIs, callExpr(callee(cxxMethodDecl(hasName("x"))))))); EXPECT_TRUE(matches( - "class A { public: void x(); };" + "class A { public: void x(); };" "class C {" " public:" " template <typename T> class B { public: void y() { T t; t.x(); } };" @@ -1395,8 +1402,9 @@ "void f() {" " C::B<A> b; b.y();" "}", - recordDecl(hasName("C"), hasDescendant(callExpr( - callee(cxxMethodDecl(hasName("x")))))))); + traverse(TK_AsIs, + recordDecl(hasName("C"), hasDescendant(callExpr(callee( + cxxMethodDecl(hasName("x"))))))))); } TEST(Matcher, HasCondition) { @@ -1890,7 +1898,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> @@ -2668,11 +2729,12 @@ anyOf(unless(anything()), anything())), std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( - "template<typename T1, typename T2> class X {}; X<float, int> x;", - classTemplateSpecializationDecl( - decl().bind("x"), - hasAnyTemplateArgument(refersToType(asString("int")))), - std::make_unique<VerifyIdIsBoundTo<Decl>>("x", 1))); + "template<typename T1, typename T2> class X {}; X<float, int> x;", + traverse(TK_AsIs, + classTemplateSpecializationDecl( + decl().bind("x"), + hasAnyTemplateArgument(refersToType(asString("int"))))), + std::make_unique<VerifyIdIsBoundTo<Decl>>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class X { void f(); void g(); };", cxxRecordDecl(decl().bind("x"), hasMethod(hasName("g"))), @@ -2716,12 +2778,13 @@ functionDecl(decl().bind("x"), hasAncestor(recordDecl(hasName("::A")))), std::make_unique<VerifyIdIsBoundTo<Decl>>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( - "template <typename T> struct A { struct B {" + "template <typename T> struct A { struct B {" " void f() { if(true) {} }" "}; };" "void t() { A<int>::B b; b.f(); }", - ifStmt(stmt().bind("x"), hasAncestor(recordDecl(hasName("::A")))), - std::make_unique<VerifyIdIsBoundTo<Stmt>>("x", 2))); + traverse(TK_AsIs, ifStmt(stmt().bind("x"), + hasAncestor(recordDecl(hasName("::A"))))), + std::make_unique<VerifyIdIsBoundTo<Stmt>>("x", 2))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A {};", recordDecl(hasName("::A"), decl().bind("x"), unless(hasName("fooble"))), @@ -2838,10 +2901,10 @@ TEST(HasAncestor, MatchesInTemplateInstantiations) { EXPECT_TRUE(matches( - "template <typename T> struct A { struct B { struct C { T t; }; }; }; " + "template <typename T> struct A { struct B { struct C { T t; }; }; }; " "A<int>::B::C a;", - fieldDecl(hasType(asString("int")), - hasAncestor(recordDecl(hasName("A")))))); + traverse(TK_AsIs, fieldDecl(hasType(asString("int")), + hasAncestor(recordDecl(hasName("A"))))))); } TEST(HasAncestor, MatchesInImplicitCode) { @@ -3293,20 +3356,24 @@ "double F(T t);" "int i;" "double j = F(i);"; - EXPECT_TRUE(matches(Fragment, substTemplateTypeParmType(hasReplacementType( - qualType(asString("int")))))); - EXPECT_TRUE(notMatches(Fragment, substTemplateTypeParmType(hasReplacementType( - qualType(asString("double")))))); - EXPECT_TRUE( - notMatches("template<int N>" - "double F();" - "double j = F<5>();", - substTemplateTypeParmType(hasReplacementType(qualType())))); + EXPECT_TRUE(matches( + Fragment, traverse(TK_AsIs, substTemplateTypeParmType(hasReplacementType( + qualType(asString("int"))))))); + EXPECT_TRUE(notMatches( + Fragment, traverse(TK_AsIs, substTemplateTypeParmType(hasReplacementType( + qualType(asString("double"))))))); + EXPECT_TRUE(notMatches( + "template<int N>" + "double F();" + "double j = F<5>();", + traverse(TK_AsIs, + substTemplateTypeParmType(hasReplacementType(qualType()))))); } TEST(ClassTemplateSpecializationDecl, HasSpecializedTemplate) { - auto Matcher = classTemplateSpecializationDecl( - hasSpecializedTemplate(classTemplateDecl())); + auto Matcher = + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasSpecializedTemplate(classTemplateDecl()))); EXPECT_TRUE( matches("template<typename T> class A {}; typedef A<int> B;", Matcher)); EXPECT_TRUE(notMatches("template<typename T> class A {};", Matcher)); Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -561,12 +561,12 @@ TEST(Matcher, MatchesClassTemplateSpecialization) { EXPECT_TRUE(matches("template<typename T> struct A {};" - "template<> struct A<int> {};", - classTemplateSpecializationDecl())); + "template<> struct A<int> {};", + traverse(TK_AsIs, classTemplateSpecializationDecl()))); EXPECT_TRUE(matches("template<typename T> struct A {}; A<int> a;", - classTemplateSpecializationDecl())); + traverse(TK_AsIs, classTemplateSpecializationDecl()))); EXPECT_TRUE(notMatches("template<typename T> struct A {};", - classTemplateSpecializationDecl())); + traverse(TK_AsIs, classTemplateSpecializationDecl()))); } TEST(DeclaratorDecl, MatchesDeclaratorDecls) { @@ -1485,10 +1485,12 @@ " return 1 + T();" "}" "int i = F<int>();"; - EXPECT_FALSE(matches(code, binaryOperator(hasLHS( - expr(hasType(substTemplateTypeParmType())))))); - EXPECT_TRUE(matches(code, binaryOperator(hasRHS( - expr(hasType(substTemplateTypeParmType())))))); + EXPECT_FALSE( + matches(code, traverse(TK_AsIs, binaryOperator(hasLHS(expr(hasType( + substTemplateTypeParmType()))))))); + EXPECT_TRUE( + matches(code, traverse(TK_AsIs, binaryOperator(hasRHS(expr(hasType( + substTemplateTypeParmType()))))))); } TEST(NNS, MatchesNestedNameSpecifiers) { Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -493,9 +493,9 @@ EXPECT_TRUE(notMatches("", IsAX)); DeclarationMatcher ZIsDerivedFromX = - cxxRecordDecl(hasName("Z"), isDerivedFrom("X")); - DeclarationMatcher ZIsDirectlyDerivedFromX = - cxxRecordDecl(hasName("Z"), isDirectlyDerivedFrom("X")); + traverse(TK_AsIs, cxxRecordDecl(hasName("Z"), isDerivedFrom("X"))); + DeclarationMatcher ZIsDirectlyDerivedFromX = traverse( + TK_AsIs, cxxRecordDecl(hasName("Z"), isDirectlyDerivedFrom("X"))); EXPECT_TRUE( matches("class X {}; class Y : public X {}; class Z : public Y {};", ZIsDerivedFromX)); @@ -1248,42 +1248,49 @@ } TEST(TemplateArgumentCountIs, Matches) { - EXPECT_TRUE( - matches("template<typename T> struct C {}; C<int> c;", - classTemplateSpecializationDecl(templateArgumentCountIs(1)))); - EXPECT_TRUE( - notMatches("template<typename T> struct C {}; C<int> c;", - classTemplateSpecializationDecl(templateArgumentCountIs(2)))); + EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + templateArgumentCountIs(1))))); + EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + templateArgumentCountIs(2))))); EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;", - templateSpecializationType(templateArgumentCountIs(1)))); - EXPECT_TRUE( - notMatches("template<typename T> struct C {}; C<int> c;", - templateSpecializationType(templateArgumentCountIs(2)))); + traverse(TK_AsIs, templateSpecializationType( + templateArgumentCountIs(1))))); + EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;", + traverse(TK_AsIs, templateSpecializationType( + templateArgumentCountIs(2))))); } TEST(IsIntegral, Matches) { - EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(isIntegral())))); - EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - templateArgument(isIntegral()))))); + EXPECT_TRUE( + matches("template<int T> struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasAnyTemplateArgument(isIntegral()))))); + EXPECT_TRUE(notMatches( + "template<typename T> struct C {}; C<int> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + templateArgument(isIntegral())))))); } TEST(EqualsIntegralValue, Matches) { - EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(equalsIntegralValue("42"))))); - EXPECT_TRUE(matches("template<int T> struct C {}; C<-42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(equalsIntegralValue("-42"))))); - EXPECT_TRUE(matches("template<int T> struct C {}; C<-0042> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(equalsIntegralValue("-34"))))); - EXPECT_TRUE(notMatches("template<int T> struct C {}; C<42> c;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - equalsIntegralValue("0042"))))); + EXPECT_TRUE(matches( + "template<int T> struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("42")))))); + EXPECT_TRUE(matches( + "template<int T> struct C {}; C<-42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("-42")))))); + EXPECT_TRUE(matches( + "template<int T> struct C {}; C<-0042> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("-34")))))); + EXPECT_TRUE(notMatches( + "template<int T> struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("0042")))))); } TEST(Matcher, MatchesAccessSpecDecls) { @@ -2056,56 +2063,63 @@ // Make sure that we can both match the class by name (::X) and by the type // the template was instantiated with (via a field). - EXPECT_TRUE(matches( - "template <typename T> class X {}; class A {}; X<A> x;", - cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); + EXPECT_TRUE( + matches("template <typename T> class X {}; class A {}; X<A> x;", + traverse(TK_AsIs, cxxRecordDecl(hasName("::X"), + isTemplateInstantiation())))); EXPECT_TRUE(matches( - "template <typename T> class X { T t; }; class A {}; X<A> x;", - cxxRecordDecl(isTemplateInstantiation(), hasDescendant( - fieldDecl(hasType(recordDecl(hasName("A")))))))); + "template <typename T> class X { T t; }; class A {}; X<A> x;", + traverse(TK_AsIs, cxxRecordDecl(isTemplateInstantiation(), + hasDescendant(fieldDecl(hasType( + recordDecl(hasName("A"))))))))); } TEST(IsTemplateInstantiation, MatchesImplicitFunctionTemplateInstantiation) { EXPECT_TRUE(matches( - "template <typename T> void f(T t) {} class A {}; void g() { f(A()); }", - functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))), - isTemplateInstantiation()))); + "template <typename T> void f(T t) {} class A {}; void g() { f(A()); }", + traverse(TK_AsIs, + functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))), + isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( - "template <typename T> class X { T t; }; class A {};" + "template <typename T> class X { T t; }; class A {};" "template class X<A>;", - cxxRecordDecl(isTemplateInstantiation(), hasDescendant( - fieldDecl(hasType(recordDecl(hasName("A")))))))); + traverse(TK_AsIs, cxxRecordDecl(isTemplateInstantiation(), + hasDescendant(fieldDecl(hasType( + recordDecl(hasName("A"))))))))); // Make sure that we match the instantiation instead of the template // definition by checking whether the member function is present. - EXPECT_TRUE( - matches("template <typename T> class X { void f() { T t; } };" - "extern template class X<int>;", - cxxRecordDecl(isTemplateInstantiation(), - unless(hasDescendant(varDecl(hasName("t"))))))); + EXPECT_TRUE(matches( + "template <typename T> class X { void f() { T t; } };" + "extern template class X<int>;", + traverse(TK_AsIs, + cxxRecordDecl(isTemplateInstantiation(), + unless(hasDescendant(varDecl(hasName("t")))))))); } TEST(IsTemplateInstantiation, MatchesInstantiationOfPartiallySpecializedClassTemplate) { - EXPECT_TRUE(matches( - "template <typename T> class X {};" - "template <typename T> class X<T*> {}; class A {}; X<A*> x;", - cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); + EXPECT_TRUE( + matches("template <typename T> class X {};" + "template <typename T> class X<T*> {}; class A {}; X<A*> x;", + traverse(TK_AsIs, cxxRecordDecl(hasName("::X"), + isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, MatchesInstantiationOfClassTemplateNestedInNonTemplate) { - EXPECT_TRUE(matches( - "class A {};" - "class X {" - " template <typename U> class Y { U u; };" - " Y<A> y;" - "};", - cxxRecordDecl(hasName("::X::Y"), isTemplateInstantiation()))); + EXPECT_TRUE( + matches("class A {};" + "class X {" + " template <typename U> class Y { U u; };" + " Y<A> y;" + "};", + traverse(TK_AsIs, cxxRecordDecl(hasName("::X::Y"), + isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { @@ -2113,73 +2127,79 @@ // normal use case as long as the uppermost instantiation always is marked // as template instantiation, but it might be confusing as a predicate. EXPECT_TRUE(matches( - "class A {};" + "class A {};" "template <typename T> class X {" " template <typename U> class Y { U u; };" " Y<T> y;" "}; X<A> x;", - cxxRecordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); + traverse(TK_AsIs, cxxRecordDecl(hasName("::X<A>::Y"), + unless(isTemplateInstantiation()))))); } TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) { - EXPECT_TRUE(notMatches( - "template <typename T> class X {}; class A {};" - "template <> class X<A> {}; X<A> x;", - cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("template <typename T> class X {}; class A {};" + "template <> class X<A> {}; X<A> x;", + traverse(TK_AsIs, cxxRecordDecl(hasName("::X"), + isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { - EXPECT_TRUE(notMatches( - "class A {}; class Y { A a; };", - cxxRecordDecl(isTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("class A {}; class Y { A a; };", + traverse(TK_AsIs, cxxRecordDecl(isTemplateInstantiation())))); } TEST(IsInstantiated, MatchesInstantiation) { EXPECT_TRUE( - matches("template<typename T> class A { T i; }; class Y { A<int> a; };", - cxxRecordDecl(isInstantiated()))); + matches("template<typename T> class A { T i; }; class Y { A<int> a; };", + traverse(TK_AsIs, cxxRecordDecl(isInstantiated())))); } TEST(IsInstantiated, NotMatchesDefinition) { EXPECT_TRUE(notMatches("template<typename T> class A { T i; };", - cxxRecordDecl(isInstantiated()))); + traverse(TK_AsIs, cxxRecordDecl(isInstantiated())))); } TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { - EXPECT_TRUE(matches("template<typename T> struct A { A() { T i; } };" - "class Y { A<int> a; }; Y y;", - declStmt(isInTemplateInstantiation()))); + EXPECT_TRUE( + matches("template<typename T> struct A { A() { T i; } };" + "class Y { A<int> a; }; Y y;", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) { - EXPECT_TRUE(notMatches("template<typename T> struct A { void x() { T i; } };", - declStmt(isInTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("template<typename T> struct A { void x() { T i; } };", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInstantiated, MatchesFunctionInstantiation) { EXPECT_TRUE( - matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", - functionDecl(isInstantiated()))); + matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", + traverse(TK_AsIs, functionDecl(isInstantiated())))); } TEST(IsInstantiated, NotMatchesFunctionDefinition) { EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }", - varDecl(isInstantiated()))); + traverse(TK_AsIs, varDecl(isInstantiated())))); } TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) { EXPECT_TRUE( - matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", - declStmt(isInTemplateInstantiation()))); + matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) { - EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }", - declStmt(isInTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("template<typename T> void A(T t) { T i; }", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInTemplateInstantiation, Sharing) { - auto Matcher = binaryOperator(unless(isInTemplateInstantiation())); + auto Matcher = + traverse(TK_AsIs, binaryOperator(unless(isInTemplateInstantiation()))); // FIXME: Node sharing is an implementation detail, exposing it is ugly // and makes the matcher behave in non-obvious ways. EXPECT_TRUE(notMatches( Index: clang/unittests/AST/StructuralEquivalenceTest.cpp =================================================================== --- clang/unittests/AST/StructuralEquivalenceTest.cpp +++ clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -933,7 +933,8 @@ // Instantiate with substitution Arg into P1. template class Templ <Arg>; )", - Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary"))); + Lang_CXX03, + traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("Primary")))); EXPECT_TRUE(testStructuralMatch(t)); } @@ -964,7 +965,8 @@ // Instantiate with substitution Arg into P1. template class Templ <Arg>; )", - Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary"))); + Lang_CXX03, + traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("Primary")))); EXPECT_FALSE(testStructuralMatch(t)); } @@ -987,8 +989,9 @@ void f(); }; )"; - auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11, - functionTemplateDecl(hasName("f"))); + auto t = makeDecls<FunctionTemplateDecl>( + Code, Code, Lang_CXX11, + traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_TRUE(testStructuralMatch(t)); } @@ -1005,22 +1008,22 @@ template <typename> struct enable_if; )"; - auto t = makeDecls<FunctionTemplateDecl>(Code + R"( + auto t = makeDecls<FunctionTemplateDecl>( + Code + R"( struct S { template <typename T, typename enable_if<S1<T>>::type> void f(); }; )", - Code + R"( + Code + R"( struct S { template <typename T, typename enable_if<S2<T>>::type> void f(); }; )", - Lang_CXX11, - functionTemplateDecl(hasName("f"))); + Lang_CXX11, traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_FALSE(testStructuralMatch(t)); } @@ -1040,8 +1043,9 @@ void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ }; )"; - auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11, - functionTemplateDecl(hasName("f"))); + auto t = makeDecls<FunctionTemplateDecl>( + Code, Code, Lang_CXX11, + traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_TRUE(testStructuralMatch(t)); } @@ -1058,22 +1062,22 @@ template <bool> struct enable_if; )"; - auto t = makeDecls<FunctionTemplateDecl>(Code + R"( + auto t = makeDecls<FunctionTemplateDecl>( + Code + R"( struct S { template <typename T, typename enable_if<S1<T>::value>::type> void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ }; )", - Code + R"( + Code + R"( struct S { template <typename T, typename enable_if<S2<T>::value>::type> void f(); }; )", - Lang_CXX03, - functionTemplateDecl(hasName("f"))); + Lang_CXX03, traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_FALSE(testStructuralMatch(t)); } @@ -1087,22 +1091,22 @@ template <bool> struct enable_if; )"; - auto t = makeDecls<FunctionTemplateDecl>(Code + R"( + auto t = makeDecls<FunctionTemplateDecl>( + Code + R"( struct S { template <typename T, typename enable_if<S1<T>::value1>::type> void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ }; )", - Code + R"( + Code + R"( struct S { template <typename T, typename enable_if<S1<T>::value2>::type> void f(); }; )", - Lang_CXX03, - functionTemplateDecl(hasName("f"))); + Lang_CXX03, traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_FALSE(testStructuralMatch(t)); } Index: clang/unittests/AST/SourceLocationTest.cpp =================================================================== --- clang/unittests/AST/SourceLocationTest.cpp +++ clang/unittests/AST/SourceLocationTest.cpp @@ -269,10 +269,10 @@ TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) { RangeVerifier<CompoundLiteralExpr> Verifier; Verifier.expectRange(2, 20, 2, 31); - EXPECT_TRUE(Verifier.match( - "typedef int int2 __attribute__((ext_vector_type(2)));\n" - "constant int2 i2 = (int2)(1, 2);", - compoundLiteralExpr(), Lang_OpenCL)); + EXPECT_TRUE( + Verifier.match("typedef int int2 __attribute__((ext_vector_type(2)));\n" + "constant int2 i2 = (int2)(1, 2);", + compoundLiteralExpr(), Lang_OpenCL)); } TEST(InitListExpr, VectorLiteralListBraceRange) { @@ -612,14 +612,15 @@ TEST(FriendDecl, InstantiationSourceRange) { RangeVerifier<FriendDecl> Verifier; Verifier.expectRange(4, 3, 4, 35); - EXPECT_TRUE(Verifier.match( - "template <typename T> class S;\n" - "template<class T> void operator+(S<T> x);\n" - "template<class T> struct S {\n" - " friend void operator+<>(S<T> src);\n" - "};\n" - "void test(S<double> s) { +s; }", - friendDecl(hasParent(cxxRecordDecl(isTemplateInstantiation()))))); + EXPECT_TRUE( + Verifier.match("template <typename T> class S;\n" + "template<class T> void operator+(S<T> x);\n" + "template<class T> struct S {\n" + " friend void operator+<>(S<T> src);\n" + "};\n" + "void test(S<double> s) { +s; }", + traverse(TK_AsIs, friendDecl(hasParent(cxxRecordDecl( + isTemplateInstantiation())))))); } TEST(ObjCMessageExpr, ParenExprRange) { 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...) {} @@ -234,7 +242,8 @@ } auto Result = ast_matchers::match( - classTemplateSpecializationDecl(hasName("templ")).bind("fn"), + traverse(TK_AsIs, + classTemplateSpecializationDecl(hasName("templ")).bind("fn")), AST->getASTContext()); EXPECT_EQ(Result.size(), 1u); auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn"); @@ -243,7 +252,7 @@ verifyWithDynNode(TA, R"cpp( -TemplateArgument +TemplateArgument type int )cpp"); Func = getFunctionNode(AST.get(), "parmvardecl_attr"); @@ -420,8 +429,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 +883,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/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -3260,7 +3260,7 @@ } )", Lang_CXX11); auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl(hasName("X"))); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); // FieldDecl without InitlistExpr: auto *ToField = *ToSpec->field_begin(); ASSERT_TRUE(ToField); @@ -3273,7 +3273,7 @@ } )", Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - FromTU, classTemplateSpecializationDecl(hasName("X"))); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); // FieldDecl with InitlistExpr: auto *FromField = *FromSpec->field_begin(); ASSERT_TRUE(FromField); @@ -3312,19 +3312,19 @@ } )", Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - FromTU, classTemplateSpecializationDecl(hasName("X"))); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); auto FunPattern = functionDecl(hasName("g"), hasParent(classTemplateSpecializationDecl())); - auto *FromFun = - FirstDeclMatcher<FunctionDecl>().match(FromTU, FunPattern); - auto *ToFun = - FirstDeclMatcher<FunctionDecl>().match(ToTU, FunPattern); + auto *FromFun = FirstDeclMatcher<FunctionDecl>().match( + FromTU, traverse(TK_AsIs, FunPattern)); + auto *ToFun = FirstDeclMatcher<FunctionDecl>().match( + ToTU, traverse(TK_AsIs, FunPattern)); ASSERT_TRUE(FromFun->hasBody()); ASSERT_FALSE(ToFun->hasBody()); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); ASSERT_TRUE(ImportedSpec); auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl(hasName("X"))); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); EXPECT_EQ(ImportedSpec, ToSpec); EXPECT_TRUE(ToFun->hasBody()); } @@ -3359,7 +3359,7 @@ )", Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - FromTU, classTemplateSpecializationDecl(hasName("X"))); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); // We expect one (ODR) warning during the import. @@ -3369,9 +3369,9 @@ // ODR, consequently we expect to keep the first specialization only, which is // already in the "To" context. EXPECT_FALSE(ImportedSpec); - EXPECT_EQ(1u, - DeclCounter<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl(hasName("X")))); + EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl( + hasName("X"))))); } TEST_P(ASTImporterOptionSpecificTestBase, @@ -3397,21 +3397,21 @@ } )", Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - FromTU, classTemplateSpecializationDecl(hasName("X"))); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); // Match the void(int) ctor. auto CtorPattern = cxxConstructorDecl(hasParameter(0, varDecl(hasType(asString("int")))), hasParent(classTemplateSpecializationDecl())); - auto *FromCtor = - FirstDeclMatcher<CXXConstructorDecl>().match(FromTU, CtorPattern); - auto *ToCtor = - FirstDeclMatcher<CXXConstructorDecl>().match(ToTU, CtorPattern); + auto *FromCtor = FirstDeclMatcher<CXXConstructorDecl>().match( + FromTU, traverse(TK_AsIs, CtorPattern)); + auto *ToCtor = FirstDeclMatcher<CXXConstructorDecl>().match( + ToTU, traverse(TK_AsIs, CtorPattern)); ASSERT_TRUE(FromCtor->hasBody()); ASSERT_FALSE(ToCtor->hasBody()); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); ASSERT_TRUE(ImportedSpec); auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl(hasName("X"))); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); EXPECT_EQ(ImportedSpec, ToSpec); EXPECT_TRUE(ToCtor->hasBody()); } @@ -3432,15 +3432,16 @@ Decl *FromTU = getTuDecl(Code, Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match( - FromTU, classTemplatePartialSpecializationDecl()); + FromTU, traverse(TK_AsIs, classTemplatePartialSpecializationDecl())); auto *ToSpec = FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match( - ToTU, classTemplatePartialSpecializationDecl()); + ToTU, traverse(TK_AsIs, classTemplatePartialSpecializationDecl())); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); EXPECT_EQ(ImportedSpec, ToSpec); EXPECT_EQ(1u, DeclCounter<ClassTemplatePartialSpecializationDecl>().match( - ToTU, classTemplatePartialSpecializationDecl())); + ToTU, traverse(TK_AsIs, + classTemplatePartialSpecializationDecl()))); } TEST_P(ASTImporterOptionSpecificTestBase, @@ -3458,14 +3459,15 @@ Decl *ToTU = getToTuDecl(Code, Lang_CXX11); Decl *FromTU = getTuDecl(Code, Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - FromTU, classTemplateSpecializationDecl()); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl())); auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl()); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl())); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); EXPECT_EQ(ImportedSpec, ToSpec); - EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl())); + EXPECT_EQ(1u, + DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl()))); } TEST_P(ASTImporterOptionSpecificTestBase, @@ -3488,17 +3490,20 @@ Decl *ToTU = getToTuDecl(PrimaryTemplate + FullSpec, Lang_CXX11); Decl *FromTU = getTuDecl(PrimaryTemplate + PartialSpec, Lang_CXX11); auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - FromTU, classTemplateSpecializationDecl()); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl())); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); EXPECT_TRUE(ImportedSpec); // Check the number of partial specializations. EXPECT_EQ(1u, DeclCounter<ClassTemplatePartialSpecializationDecl>().match( - ToTU, classTemplatePartialSpecializationDecl())); + ToTU, traverse(TK_AsIs, + classTemplatePartialSpecializationDecl()))); // Check the number of full specializations. - EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl( - unless(classTemplatePartialSpecializationDecl())))); + EXPECT_EQ( + 1u, DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, traverse(TK_AsIs, + classTemplateSpecializationDecl(unless( + classTemplatePartialSpecializationDecl()))))); } TEST_P(ASTImporterOptionSpecificTestBase, @@ -3794,7 +3799,8 @@ } TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) { - auto Pattern = classTemplateSpecializationDecl(hasName("X")); + auto Pattern = + traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X"))); ClassTemplateSpecializationDecl *Imported1; { @@ -4050,8 +4056,9 @@ Lang_CXX03, "input0.cc"); // Check that the function template instantiation is NOT the child of the TU. - auto Pattern = translationUnitDecl( - unless(has(functionDecl(hasName("f"), isTemplateInstantiation())))); + auto Pattern = + traverse(TK_AsIs, translationUnitDecl(unless(has(functionDecl( + hasName("f"), isTemplateInstantiation()))))); ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern)); auto *Foo = FirstDeclMatcher<FunctionDecl>().match( @@ -4074,8 +4081,10 @@ Lang_CXX03, "input0.cc"); // Check that the function template instantiation is NOT the child of the TU. - auto Instantiation = functionDecl(hasName("f"), isTemplateInstantiation()); - auto Pattern = translationUnitDecl(unless(has(Instantiation))); + auto Instantiation = + traverse(TK_AsIs, functionDecl(hasName("f"), isTemplateInstantiation())); + auto Pattern = + traverse(TK_AsIs, translationUnitDecl(unless(has(Instantiation)))); ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern)); ASSERT_TRUE(Import(FirstDeclMatcher<Decl>().match(FromTU, Instantiation), @@ -4642,7 +4651,7 @@ fieldDecl(hasParent(cxxRecordDecl(hasParent(classTemplateDecl()))))); auto *Spec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( - ToTU, classTemplateSpecializationDecl(hasName("X"))); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); FieldDecl *FieldInSpec = *Spec->field_begin(); ASSERT_TRUE(FieldInSpec); Index: clang/unittests/AST/ASTContextParentMapTest.cpp =================================================================== --- clang/unittests/AST/ASTContextParentMapTest.cpp +++ clang/unittests/AST/ASTContextParentMapTest.cpp @@ -54,20 +54,24 @@ EXPECT_TRUE(DeclVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - cxxMethodDecl(hasName("f"), - hasParent(cxxRecordDecl(isTemplateInstantiation()))))); + traverse(TK_AsIs, + cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl( + isTemplateInstantiation())))))); EXPECT_TRUE(DeclVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - cxxMethodDecl(hasName("f"), - hasParent(cxxRecordDecl(unless(isTemplateInstantiation())))))); + traverse(TK_AsIs, + cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(unless( + isTemplateInstantiation()))))))); EXPECT_FALSE(DeclVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - cxxMethodDecl( - hasName("f"), - allOf(hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))), - hasParent(cxxRecordDecl(isTemplateInstantiation())))))); + traverse( + TK_AsIs, + cxxMethodDecl( + hasName("f"), + allOf(hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))), + hasParent(cxxRecordDecl(isTemplateInstantiation()))))))); } TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) { 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); @@ -302,6 +309,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,44 @@ bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } + bool TraversingImplicitTemplateInstantiation = false; + + bool isMatchingInImplicitTemplateInstantiation() const override { + return TraversingImplicitTemplateInstantiation; + } + + struct ImplicitTemplateInstantiationScope { + ImplicitTemplateInstantiationScope(MatchASTVisitor *V, bool B) + : MV(V), MB(V->TraversingImplicitTemplateInstantiation) { + V->TraversingImplicitTemplateInstantiation = B; + } + ~ImplicitTemplateInstantiationScope() { + MV->TraversingImplicitTemplateInstantiation = MB; + } + + private: + MatchASTVisitor *MV; + bool MB; + }; + + bool TraverseTemplateInstantiations(ClassTemplateDecl *D) { + ImplicitTemplateInstantiationScope RAII(this, true); + return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations( + D); + } + + bool TraverseTemplateInstantiations(VarTemplateDecl *D) { + ImplicitTemplateInstantiationScope RAII(this, true); + return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations( + D); + } + + bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) { + ImplicitTemplateInstantiationScope RAII(this, true); + return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations( + D); + } + 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 @@ -585,6 +585,10 @@ return this->InnerMatcher.matches(DynTypedNode::create(*Node), Finder, Builder); } + + llvm::Optional<clang::TraversalKind> TraversalKind() const override { + return this->InnerMatcher.getTraversalKind(); + } }; private: @@ -1056,6 +1060,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/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -508,6 +508,13 @@ bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child); +#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \ + bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D); + DEF_TRAVERSE_TMPL_INST(Class) + DEF_TRAVERSE_TMPL_INST(Var) + DEF_TRAVERSE_TMPL_INST(Function) +#undef DEF_TRAVERSE_TMPL_INST + private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); @@ -516,12 +523,6 @@ template <typename T> bool TraverseDeclTemplateParameterLists(T *D); -#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \ - bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D); - DEF_TRAVERSE_TMPL_INST(Class) - DEF_TRAVERSE_TMPL_INST(Var) - DEF_TRAVERSE_TMPL_INST(Function) -#undef DEF_TRAVERSE_TMPL_INST bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, unsigned Count); bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); 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/misc/UnusedUsingDeclsCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -62,20 +62,24 @@ auto DeclMatcher = hasDeclaration(namedDecl().bind("used")); Finder->addMatcher(loc(enumType(DeclMatcher)), this); Finder->addMatcher(loc(recordType(DeclMatcher)), this); - Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this); - Finder->addMatcher(loc(deducedTemplateSpecializationType( - refsToTemplatedDecl(namedDecl().bind("used")))), - this); + Finder->addMatcher( + traverse(TK_AsIs, loc(templateSpecializationType(DeclMatcher))), this); + Finder->addMatcher( + traverse(TK_AsIs, loc(deducedTemplateSpecializationType( + refsToTemplatedDecl(namedDecl().bind("used"))))), + this); Finder->addMatcher(declRefExpr().bind("used"), this); Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))), this); Finder->addMatcher( - callExpr(hasDeclaration(functionDecl( - forEachTemplateArgument(templateArgument().bind("used"))))), + traverse(TK_AsIs, + callExpr(hasDeclaration(functionDecl( + forEachTemplateArgument(templateArgument().bind("used")))))), + this); + Finder->addMatcher( + traverse(TK_AsIs, loc(templateSpecializationType(forEachTemplateArgument( + templateArgument().bind("used"))))), this); - Finder->addMatcher(loc(templateSpecializationType(forEachTemplateArgument( - templateArgument().bind("used")))), - this); } void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { 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