diff --git a/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp b/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp --- a/clang-tools-extra/clang-tidy/abseil/TimeSubtractionCheck.cpp +++ b/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); } } diff --git a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp --- a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp +++ b/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 diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp +++ b/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. diff --git a/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp --- a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp +++ b/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) diff --git a/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp --- a/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp +++ b/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( diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ b/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(ConstructorCall); diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp @@ -95,19 +95,23 @@ // // std::auto_ptr fn(std::auto_ptr); // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ - 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, diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp +++ b/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 diff --git a/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/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( - 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( + StringLikeClasses.begin(), + StringLikeClasses.end()))))))), + unless(hasSubstitutedType()))))), this); } diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp +++ b/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); } diff --git a/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp b/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp --- a/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp +++ b/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( diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/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) { diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/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 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); diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -585,6 +585,10 @@ return this->InnerMatcher.matches(DynTypedNode::create(*Node), Finder, Builder); } + + llvm::Optional 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, diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp --- a/clang/lib/AST/ASTDumper.cpp +++ b/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) { diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -561,6 +561,40 @@ 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::TraverseTemplateInstantiations(D); + } + + bool TraverseTemplateInstantiations(VarTemplateDecl *D) { + ImplicitTemplateInstantiationScope RAII(this, true); + return RecursiveASTVisitor::TraverseTemplateInstantiations(D); + } + + bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) { + ImplicitTemplateInstantiationScope RAII(this, true); + return RecursiveASTVisitor::TraverseTemplateInstantiations(D); + } + private: class TimeBucketRegion { public: diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/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); diff --git a/clang/unittests/AST/ASTContextParentMapTest.cpp b/clang/unittests/AST/ASTContextParentMapTest.cpp --- a/clang/unittests/AST/ASTContextParentMapTest.cpp +++ b/clang/unittests/AST/ASTContextParentMapTest.cpp @@ -54,20 +54,24 @@ EXPECT_TRUE(DeclVerifier.match( "template struct C { void f() {} };" "void g() { C c; c.f(); }", - cxxMethodDecl(hasName("f"), - hasParent(cxxRecordDecl(isTemplateInstantiation()))))); + traverse(TK_AsIs, + cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl( + isTemplateInstantiation())))))); EXPECT_TRUE(DeclVerifier.match( "template struct C { void f() {} };" "void g() { C 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 struct C { void f() {} };" "void g() { C 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) { diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -3260,7 +3260,7 @@ } )", Lang_CXX11); auto *ToSpec = FirstDeclMatcher().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().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().match( - FromTU, classTemplateSpecializationDecl(hasName("X"))); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); auto FunPattern = functionDecl(hasName("g"), hasParent(classTemplateSpecializationDecl())); - auto *FromFun = - FirstDeclMatcher().match(FromTU, FunPattern); - auto *ToFun = - FirstDeclMatcher().match(ToTU, FunPattern); + auto *FromFun = FirstDeclMatcher().match( + FromTU, traverse(TK_AsIs, FunPattern)); + auto *ToFun = FirstDeclMatcher().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().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().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().match( - ToTU, classTemplateSpecializationDecl(hasName("X")))); + EXPECT_EQ(1u, DeclCounter().match( + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl( + hasName("X"))))); } TEST_P(ASTImporterOptionSpecificTestBase, @@ -3397,21 +3397,21 @@ } )", Lang_CXX11); auto *FromSpec = FirstDeclMatcher().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().match(FromTU, CtorPattern); - auto *ToCtor = - FirstDeclMatcher().match(ToTU, CtorPattern); + auto *FromCtor = FirstDeclMatcher().match( + FromTU, traverse(TK_AsIs, CtorPattern)); + auto *ToCtor = FirstDeclMatcher().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().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().match( - FromTU, classTemplatePartialSpecializationDecl()); + FromTU, traverse(TK_AsIs, classTemplatePartialSpecializationDecl())); auto *ToSpec = FirstDeclMatcher().match( - ToTU, classTemplatePartialSpecializationDecl()); + ToTU, traverse(TK_AsIs, classTemplatePartialSpecializationDecl())); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); EXPECT_EQ(ImportedSpec, ToSpec); EXPECT_EQ(1u, DeclCounter().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().match( - FromTU, classTemplateSpecializationDecl()); + FromTU, traverse(TK_AsIs, classTemplateSpecializationDecl())); auto *ToSpec = FirstDeclMatcher().match( - ToTU, classTemplateSpecializationDecl()); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl())); auto *ImportedSpec = Import(FromSpec, Lang_CXX11); EXPECT_EQ(ImportedSpec, ToSpec); - EXPECT_EQ(1u, DeclCounter().match( - ToTU, classTemplateSpecializationDecl())); + EXPECT_EQ(1u, + DeclCounter().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().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().match( - ToTU, classTemplatePartialSpecializationDecl())); + ToTU, traverse(TK_AsIs, + classTemplatePartialSpecializationDecl()))); // Check the number of full specializations. - EXPECT_EQ(1u, DeclCounter().match( - ToTU, classTemplateSpecializationDecl( - unless(classTemplatePartialSpecializationDecl())))); + EXPECT_EQ( + 1u, DeclCounter().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{}.match(FromTU, Pattern)); auto *Foo = FirstDeclMatcher().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{}.match(FromTU, Pattern)); ASSERT_TRUE(Import(FirstDeclMatcher().match(FromTU, Instantiation), @@ -4642,7 +4651,7 @@ fieldDecl(hasParent(cxxRecordDecl(hasParent(classTemplateDecl()))))); auto *Spec = FirstDeclMatcher().match( - ToTU, classTemplateSpecializationDecl(hasName("X"))); + ToTU, traverse(TK_AsIs, classTemplateSpecializationDecl(hasName("X")))); FieldDecl *FieldInSpec = *Spec->field_begin(); ASSERT_TRUE(FieldInSpec); diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp --- a/clang/unittests/AST/ASTTraverserTest.cpp +++ b/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 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("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 +struct TemplStruct { + TemplStruct() {} + ~TemplStruct() {} + +private: + T m_t; +}; + +template +T timesTwo(T input) +{ + return input * 2; +} + +void instantiate() +{ + TemplStruct ti; + TemplStruct td; + (void)timesTwo(2); + (void)timesTwo(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("rec")), + R"cpp( +ClassTemplateDecl 'TemplStruct' +|-TemplateTypeParmDecl 'T' +`-CXXRecordDecl 'TemplStruct' + |-CXXRecordDecl 'TemplStruct' + |-CXXConstructorDecl 'TemplStruct' + | `-CompoundStmt + |-CXXDestructorDecl '~TemplStruct' + | `-CompoundStmt + |-AccessSpecDecl + `-FieldDecl 'm_t' +)cpp"); + + EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs("rec")), + R"cpp( +ClassTemplateDecl 'TemplStruct' +|-TemplateTypeParmDecl 'T' +|-CXXRecordDecl 'TemplStruct' +| |-CXXRecordDecl 'TemplStruct' +| |-CXXConstructorDecl 'TemplStruct' +| | `-CompoundStmt +| |-CXXDestructorDecl '~TemplStruct' +| | `-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("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("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 diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -269,10 +269,10 @@ TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) { RangeVerifier 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 Verifier; Verifier.expectRange(4, 3, 4, 35); - EXPECT_TRUE(Verifier.match( - "template class S;\n" - "template void operator+(S x);\n" - "template struct S {\n" - " friend void operator+<>(S src);\n" - "};\n" - "void test(S s) { +s; }", - friendDecl(hasParent(cxxRecordDecl(isTemplateInstantiation()))))); + EXPECT_TRUE( + Verifier.match("template class S;\n" + "template void operator+(S x);\n" + "template struct S {\n" + " friend void operator+<>(S src);\n" + "};\n" + "void test(S s) { +s; }", + traverse(TK_AsIs, friendDecl(hasParent(cxxRecordDecl( + isTemplateInstantiation())))))); } TEST(ObjCMessageExpr, ParenExprRange) { diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -933,7 +933,8 @@ // Instantiate with substitution Arg into P1. template class Templ ; )", - 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 ; )", - 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(Code, Code, Lang_CXX11, - functionTemplateDecl(hasName("f"))); + auto t = makeDecls( + Code, Code, Lang_CXX11, + traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_TRUE(testStructuralMatch(t)); } @@ -1005,22 +1008,22 @@ template struct enable_if; )"; - auto t = makeDecls(Code + R"( + auto t = makeDecls( + Code + R"( struct S { template >::type> void f(); }; )", - Code + R"( + Code + R"( struct S { template >::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(Code, Code, Lang_CXX11, - functionTemplateDecl(hasName("f"))); + auto t = makeDecls( + Code, Code, Lang_CXX11, + traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_TRUE(testStructuralMatch(t)); } @@ -1058,22 +1062,22 @@ template struct enable_if; )"; - auto t = makeDecls(Code + R"( + auto t = makeDecls( + Code + R"( struct S { template ::value>::type> void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ }; )", - Code + R"( + Code + R"( struct S { template ::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 struct enable_if; )"; - auto t = makeDecls(Code + R"( + auto t = makeDecls( + Code + R"( struct S { template ::value1>::type> void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ }; )", - Code + R"( + Code + R"( struct S { template ::value2>::type> void f(); }; )", - Lang_CXX03, - functionTemplateDecl(hasName("f"))); + Lang_CXX03, traverse(TK_AsIs, functionTemplateDecl(hasName("f")))); EXPECT_FALSE(testStructuralMatch(t)); } diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/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 struct C {}; C c;", - classTemplateSpecializationDecl(templateArgumentCountIs(1)))); - EXPECT_TRUE( - notMatches("template struct C {}; C c;", - classTemplateSpecializationDecl(templateArgumentCountIs(2)))); + EXPECT_TRUE(matches("template struct C {}; C c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + templateArgumentCountIs(1))))); + EXPECT_TRUE(notMatches("template struct C {}; C c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + templateArgumentCountIs(2))))); EXPECT_TRUE(matches("template struct C {}; C c;", - templateSpecializationType(templateArgumentCountIs(1)))); - EXPECT_TRUE( - notMatches("template struct C {}; C c;", - templateSpecializationType(templateArgumentCountIs(2)))); + traverse(TK_AsIs, templateSpecializationType( + templateArgumentCountIs(1))))); + EXPECT_TRUE(notMatches("template struct C {}; C c;", + traverse(TK_AsIs, templateSpecializationType( + templateArgumentCountIs(2))))); } TEST(IsIntegral, Matches) { - EXPECT_TRUE(matches("template struct C {}; C<42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(isIntegral())))); - EXPECT_TRUE(notMatches("template struct C {}; C c;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - templateArgument(isIntegral()))))); + EXPECT_TRUE( + matches("template struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl( + hasAnyTemplateArgument(isIntegral()))))); + EXPECT_TRUE(notMatches( + "template struct C {}; C c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + templateArgument(isIntegral())))))); } TEST(EqualsIntegralValue, Matches) { - EXPECT_TRUE(matches("template struct C {}; C<42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(equalsIntegralValue("42"))))); - EXPECT_TRUE(matches("template struct C {}; C<-42> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(equalsIntegralValue("-42"))))); - EXPECT_TRUE(matches("template struct C {}; C<-0042> c;", - classTemplateSpecializationDecl( - hasAnyTemplateArgument(equalsIntegralValue("-34"))))); - EXPECT_TRUE(notMatches("template struct C {}; C<42> c;", - classTemplateSpecializationDecl(hasAnyTemplateArgument( - equalsIntegralValue("0042"))))); + EXPECT_TRUE(matches( + "template struct C {}; C<42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("42")))))); + EXPECT_TRUE(matches( + "template struct C {}; C<-42> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("-42")))))); + EXPECT_TRUE(matches( + "template struct C {}; C<-0042> c;", + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("-34")))))); + EXPECT_TRUE(notMatches( + "template 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 class X {}; class A {}; X x;", - cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); + EXPECT_TRUE( + matches("template class X {}; class A {}; X x;", + traverse(TK_AsIs, cxxRecordDecl(hasName("::X"), + isTemplateInstantiation())))); EXPECT_TRUE(matches( - "template class X { T t; }; class A {}; X x;", - cxxRecordDecl(isTemplateInstantiation(), hasDescendant( - fieldDecl(hasType(recordDecl(hasName("A")))))))); + "template class X { T t; }; class A {}; X x;", + traverse(TK_AsIs, cxxRecordDecl(isTemplateInstantiation(), + hasDescendant(fieldDecl(hasType( + recordDecl(hasName("A"))))))))); } TEST(IsTemplateInstantiation, MatchesImplicitFunctionTemplateInstantiation) { EXPECT_TRUE(matches( - "template void f(T t) {} class A {}; void g() { f(A()); }", - functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))), - isTemplateInstantiation()))); + "template 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 class X { T t; }; class A {};" + "template class X { T t; }; class A {};" "template class X;", - 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 class X { void f() { T t; } };" - "extern template class X;", - cxxRecordDecl(isTemplateInstantiation(), - unless(hasDescendant(varDecl(hasName("t"))))))); + EXPECT_TRUE(matches( + "template class X { void f() { T t; } };" + "extern template class X;", + traverse(TK_AsIs, + cxxRecordDecl(isTemplateInstantiation(), + unless(hasDescendant(varDecl(hasName("t")))))))); } TEST(IsTemplateInstantiation, MatchesInstantiationOfPartiallySpecializedClassTemplate) { - EXPECT_TRUE(matches( - "template class X {};" - "template class X {}; class A {}; X x;", - cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); + EXPECT_TRUE( + matches("template class X {};" + "template class X {}; class A {}; X x;", + traverse(TK_AsIs, cxxRecordDecl(hasName("::X"), + isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, MatchesInstantiationOfClassTemplateNestedInNonTemplate) { - EXPECT_TRUE(matches( - "class A {};" - "class X {" - " template class Y { U u; };" - " Y y;" - "};", - cxxRecordDecl(hasName("::X::Y"), isTemplateInstantiation()))); + EXPECT_TRUE( + matches("class A {};" + "class X {" + " template class Y { U u; };" + " Y 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 class X {" " template class Y { U u; };" " Y y;" "}; X x;", - cxxRecordDecl(hasName("::X::Y"), unless(isTemplateInstantiation())))); + traverse(TK_AsIs, cxxRecordDecl(hasName("::X::Y"), + unless(isTemplateInstantiation()))))); } TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) { - EXPECT_TRUE(notMatches( - "template class X {}; class A {};" - "template <> class X {}; X x;", - cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("template class X {}; class A {};" + "template <> class X {}; X 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 class A { T i; }; class Y { A a; };", - cxxRecordDecl(isInstantiated()))); + matches("template class A { T i; }; class Y { A a; };", + traverse(TK_AsIs, cxxRecordDecl(isInstantiated())))); } TEST(IsInstantiated, NotMatchesDefinition) { EXPECT_TRUE(notMatches("template class A { T i; };", - cxxRecordDecl(isInstantiated()))); + traverse(TK_AsIs, cxxRecordDecl(isInstantiated())))); } TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { - EXPECT_TRUE(matches("template struct A { A() { T i; } };" - "class Y { A a; }; Y y;", - declStmt(isInTemplateInstantiation()))); + EXPECT_TRUE( + matches("template struct A { A() { T i; } };" + "class Y { A a; }; Y y;", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) { - EXPECT_TRUE(notMatches("template struct A { void x() { T i; } };", - declStmt(isInTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("template struct A { void x() { T i; } };", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInstantiated, MatchesFunctionInstantiation) { EXPECT_TRUE( - matches("template void A(T t) { T i; } void x() { A(0); }", - functionDecl(isInstantiated()))); + matches("template void A(T t) { T i; } void x() { A(0); }", + traverse(TK_AsIs, functionDecl(isInstantiated())))); } TEST(IsInstantiated, NotMatchesFunctionDefinition) { EXPECT_TRUE(notMatches("template void A(T t) { T i; }", - varDecl(isInstantiated()))); + traverse(TK_AsIs, varDecl(isInstantiated())))); } TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) { EXPECT_TRUE( - matches("template void A(T t) { T i; } void x() { A(0); }", - declStmt(isInTemplateInstantiation()))); + matches("template void A(T t) { T i; } void x() { A(0); }", + traverse(TK_AsIs, declStmt(isInTemplateInstantiation())))); } TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) { - EXPECT_TRUE(notMatches("template void A(T t) { T i; }", - declStmt(isInTemplateInstantiation()))); + EXPECT_TRUE( + notMatches("template 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( diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -561,12 +561,12 @@ TEST(Matcher, MatchesClassTemplateSpecialization) { EXPECT_TRUE(matches("template struct A {};" - "template<> struct A {};", - classTemplateSpecializationDecl())); + "template<> struct A {};", + traverse(TK_AsIs, classTemplateSpecializationDecl()))); EXPECT_TRUE(matches("template struct A {}; A a;", - classTemplateSpecializationDecl())); + traverse(TK_AsIs, classTemplateSpecializationDecl()))); EXPECT_TRUE(notMatches("template struct A {};", - classTemplateSpecializationDecl())); + traverse(TK_AsIs, classTemplateSpecializationDecl()))); } TEST(DeclaratorDecl, MatchesDeclaratorDecls) { @@ -1485,10 +1485,12 @@ " return 1 + T();" "}" "int i = F();"; - 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) { diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -26,13 +26,14 @@ } TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { - EXPECT_TRUE(matches( - "template struct A {" - " template struct F {};" - "};" - "template struct B : A::template F {};" - "B b;", - cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl())))); + EXPECT_TRUE( + matches("template struct A {" + " template struct F {};" + "};" + "template struct B : A::template F {};" + "B b;", + traverse(TK_AsIs, cxxRecordDecl(hasName("B"), + isDerivedFrom(recordDecl()))))); } TEST(DeclarationMatcher, hasDeclContext) { @@ -828,33 +829,35 @@ TEST(Matcher, MatchesTypeTemplateArgument) { EXPECT_TRUE(matches( - "template struct B {};" + "template struct B {};" "B b;", - classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( - asString("int")))))); + traverse(TK_AsIs, classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToType(asString("int"))))))); } TEST(Matcher, MatchesTemplateTemplateArgument) { - EXPECT_TRUE(matches("template