13#include "llvm/ADT/STLExtras.h"
16using namespace ast_matchers;
21 return llvm::is_contained(
Node.capture_inits(), E);
25 ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) {
26 const DeclStmt *
const Range =
Node.getRangeStmt();
27 return InnerMatcher.matches(*Range, Finder, Builder);
30AST_MATCHER_P(Expr, maybeEvalCommaExpr, ast_matchers::internal::Matcher<Expr>,
33 while (
const auto *BOComma =
34 dyn_cast_or_null<BinaryOperator>(
Result->IgnoreParens())) {
35 if (!BOComma->isCommaOp())
37 Result = BOComma->getRHS();
39 return InnerMatcher.matches(*
Result, Finder, Builder);
42AST_MATCHER_P(Stmt, canResolveToExpr, ast_matchers::internal::Matcher<Stmt>,
44 auto *Exp = dyn_cast<Expr>(&
Node);
46 return stmt().matches(
Node, Finder, Builder);
49 auto DerivedToBase = [](
const ast_matchers::internal::Matcher<Expr> &Inner) {
51 hasCastKind(CK_UncheckedDerivedToBase)),
52 hasSourceExpression(Inner));
54 auto IgnoreDerivedToBase =
55 [&DerivedToBase](
const ast_matchers::internal::Matcher<Expr> &Inner) {
56 return ignoringParens(
expr(
anyOf(Inner, DerivedToBase(Inner))));
67 hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))),
68 hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher)))));
70 hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))),
71 hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher)))));
73 auto const ComplexMatcher = ignoringParens(
74 expr(
anyOf(IgnoreDerivedToBase(InnerMatcher),
75 maybeEvalCommaExpr(IgnoreDerivedToBase(InnerMatcher)),
76 IgnoreDerivedToBase(ConditionalOperator),
77 IgnoreDerivedToBase(ElvisOperator))));
79 return ComplexMatcher.matches(*Exp, Finder, Builder);
84AST_MATCHER_P(InitListExpr, hasAnyInit, ast_matchers::internal::Matcher<Expr>,
86 for (
const Expr *Arg :
Node.inits()) {
87 ast_matchers::internal::BoundNodesTreeBuilder
Result(*Builder);
88 if (InnerMatcher.matches(*Arg, Finder, &
Result)) {
89 *Builder = std::move(
Result);
96const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr>
100 return Node.isPotentiallyEvaluated();
104 const Decl *CalleeDecl =
Node.getCalleeDecl();
105 const auto *VD = dyn_cast_or_null<ValueDecl>(CalleeDecl);
108 const QualType T = VD->getType().getCanonicalType();
109 const auto *MPT = dyn_cast<MemberPointerType>(T);
110 const auto *FPT = MPT ? cast<FunctionProtoType>(MPT->getPointeeType())
111 : dyn_cast<FunctionProtoType>(T);
114 return FPT->isConst();
118 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
119 if (
Node.isTypePredicate())
121 return InnerMatcher.matches(*
Node.getControllingExpr(), Finder, Builder);
124const auto nonConstReferenceType = [] {
125 return hasUnqualifiedDesugaredType(
129const auto nonConstPointerType = [] {
130 return hasUnqualifiedDesugaredType(
134const auto isMoveOnly = [] {
144template <
class T>
struct NodeID;
145template <>
struct NodeID<Expr> {
static constexpr StringRef value =
"expr"; };
146template <>
struct NodeID<
Decl> {
static constexpr StringRef value =
"decl"; };
147constexpr StringRef NodeID<Expr>::value;
148constexpr StringRef NodeID<Decl>::value;
150template <
class T,
class F = const Stmt *(ExprMutationAnalyzer::*)(const T *)>
151const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,
152 ExprMutationAnalyzer *Analyzer, F Finder) {
153 const StringRef
ID = NodeID<T>::value;
154 for (
const auto &
Nodes : Matches) {
155 if (
const Stmt *S = (Analyzer->*Finder)(
Nodes.getNodeAs<T>(
ID)))
164 return findMutationMemoized(Exp,
165 {&ExprMutationAnalyzer::findDirectMutation,
166 &ExprMutationAnalyzer::findMemberMutation,
167 &ExprMutationAnalyzer::findArrayElementMutation,
168 &ExprMutationAnalyzer::findCastMutation,
169 &ExprMutationAnalyzer::findRangeLoopMutation,
170 &ExprMutationAnalyzer::findReferenceMutation,
171 &ExprMutationAnalyzer::findFunctionArgMutation},
180 return findMutationMemoized(Exp, {}, PointeeResults);
187const Stmt *ExprMutationAnalyzer::findMutationMemoized(
189 ResultMap &MemoizedResults) {
190 const auto Memoized = MemoizedResults.find(Exp);
191 if (Memoized != MemoizedResults.end())
192 return Memoized->second;
195 return MemoizedResults[Exp] =
nullptr;
197 for (
const auto &Finder : Finders) {
198 if (
const Stmt *S = (this->*Finder)(Exp))
199 return MemoizedResults[Exp] = S;
202 return MemoizedResults[Exp] =
nullptr;
205const Stmt *ExprMutationAnalyzer::tryEachDeclRef(
const Decl *Dec,
206 MutationFinder Finder) {
210 for (
const auto &RefNodes : Refs) {
211 const auto *E = RefNodes.getNodeAs<Expr>(NodeID<Expr>::value);
212 if ((this->*Finder)(E))
220 return selectFirst<Stmt>(
224 stmt(canResolveToExpr(equalsNode(Exp)),
240 unless(isPotentiallyEvaluated())),
246 .bind(NodeID<Expr>::value)),
247 Stm, Context)) !=
nullptr;
255ExprMutationAnalyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
260ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
264const Stmt *ExprMutationAnalyzer::findExprPointeeMutation(
265 ArrayRef<ast_matchers::BoundNodes> Matches) {
266 return tryEachMatch<Expr>(Matches,
this,
270const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation(
271 ArrayRef<ast_matchers::BoundNodes> Matches) {
272 return tryEachMatch<Decl>(Matches,
this,
276const Stmt *ExprMutationAnalyzer::findDirectMutation(
const Expr *Exp) {
279 isAssignmentOperator(), hasLHS(canResolveToExpr(equalsNode(Exp))));
282 const auto AsIncDecOperand =
284 hasUnaryOperand(canResolveToExpr(equalsNode(Exp))));
294 hasArgument(0, canResolveToExpr(equalsNode(Exp)))),
300 hasEitherOperand(ignoringImpCasts(canResolveToExpr(equalsNode(Exp)))),
307 canResolveToExpr(equalsNode(Exp)))),
309 canResolveToExpr(equalsNode(Exp)))))))),
314 hasObjectExpression(canResolveToExpr(
315 equalsNode(Exp)))))))));
321 const auto AsAmpersandOperand =
325 hasUnaryOperand(canResolveToExpr(equalsNode(Exp))));
326 const auto AsPointerFromArrayDecay =
327 castExpr(hasCastKind(CK_ArrayToPointerDecay),
329 has(canResolveToExpr(equalsNode(Exp))));
336 cxxMethodDecl(ofClass(isMoveOnly()), returns(nonConstPointerType()))),
337 argumentCountIs(1), hasArgument(0, canResolveToExpr(equalsNode(Exp))));
344 const auto NonConstRefParam = forEachArgumentWithParamType(
345 anyOf(canResolveToExpr(equalsNode(Exp)),
346 memberExpr(hasObjectExpression(canResolveToExpr(equalsNode(Exp))))),
347 nonConstReferenceType());
349 const auto TypeDependentCallee =
354 const auto AsNonConstRefArg =
anyOf(
355 callExpr(NonConstRefParam, NotInstantiated),
358 hasAnyArgument(canResolveToExpr(equalsNode(Exp)))),
360 hasAnyArgument(canResolveToExpr(equalsNode(Exp)))),
375 const auto AsLambdaRefCaptureInit =
lambdaExpr(hasCaptureInit(Exp));
382 const auto AsNonConstRefReturn =
383 returnStmt(hasReturnValue(canResolveToExpr(equalsNode(Exp))));
388 hasType(nonConstReferenceType())))));
390 const auto Matches =
match(
393 AsNonConstThis, AsAmpersandOperand,
394 AsPointerFromArrayDecay, AsOperatorArrowThis,
395 AsNonConstRefArg, AsLambdaRefCaptureInit,
396 AsNonConstRefReturn, AsNonConstRefRangeInit))
399 return selectFirst<Stmt>(
"stmt", Matches);
402const Stmt *ExprMutationAnalyzer::findMemberMutation(
const Expr *Exp) {
404 const auto MemberExprs =
406 canResolveToExpr(equalsNode(Exp)))),
408 canResolveToExpr(equalsNode(Exp)))),
410 hasLHS(equalsNode(Exp)))))
411 .bind(NodeID<Expr>::value)),
413 return findExprMutation(MemberExprs);
416const Stmt *ExprMutationAnalyzer::findArrayElementMutation(
const Expr *Exp) {
418 const auto SubscriptExprs =
420 anyOf(hasBase(canResolveToExpr(equalsNode(Exp))),
422 allOf(hasCastKind(CK_ArrayToPointerDecay),
423 hasSourceExpression(canResolveToExpr(
424 equalsNode(Exp))))))))
425 .bind(NodeID<Expr>::value)),
427 return findExprMutation(SubscriptExprs);
430const Stmt *ExprMutationAnalyzer::findCastMutation(
const Expr *Exp) {
433 const auto ExplicitCast =
match(
435 stmt(
castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))),
437 hasDestinationType(nonConstReferenceType()))))
441 if (
const auto *CastStmt = selectFirst<Stmt>(
"stmt", ExplicitCast))
445 const auto Casts =
match(
447 expr(
castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))),
449 hasDestinationType(nonConstReferenceType())),
451 nonConstReferenceType())))))
452 .bind(NodeID<Expr>::value)),
455 if (
const Stmt *S = findExprMutation(Casts))
460 hasAnyName(
"::std::move",
"::std::forward"))),
461 hasArgument(0, canResolveToExpr(equalsNode(Exp))))
464 return findExprMutation(Calls);
467const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(
const Expr *Exp) {
474 const auto DeclStmtToNonRefToArray =
declStmt(hasSingleDecl(
varDecl(hasType(
476 const auto RefToArrayRefToElements =
480 hasType(nonConstPointerType())))
481 .bind(NodeID<Decl>::value)),
482 hasRangeStmt(DeclStmtToNonRefToArray),
483 hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
487 if (
const auto *BadRangeInitFromArray =
488 selectFirst<Stmt>(
"stmt", RefToArrayRefToElements))
489 return BadRangeInitFromArray;
498 const auto HasAnyNonConstIterator =
504 const auto DeclStmtToNonConstIteratorContainer =
declStmt(
508 const auto RefToContainerBadIterators =
510 hasRangeStmt(DeclStmtToNonConstIteratorContainer),
511 hasRangeInit(canResolveToExpr(equalsNode(Exp))))))
515 if (
const auto *BadIteratorsContainer =
516 selectFirst<Stmt>(
"stmt", RefToContainerBadIterators))
517 return BadIteratorsContainer;
521 const auto LoopVars =
523 hasLoopVariable(
varDecl(hasType(nonConstReferenceType()))
524 .bind(NodeID<Decl>::value)),
525 hasRangeInit(canResolveToExpr(equalsNode(Exp))))),
527 return findDeclMutation(LoopVars);
530const Stmt *ExprMutationAnalyzer::findReferenceMutation(
const Expr *Exp) {
538 returns(nonConstReferenceType()))),
540 hasArgument(0, canResolveToExpr(equalsNode(Exp))))
541 .bind(NodeID<Expr>::value)),
543 if (
const Stmt *S = findExprMutation(Ref))
547 const auto Refs =
match(
550 hasType(nonConstReferenceType()),
551 hasInitializer(
anyOf(canResolveToExpr(equalsNode(Exp)),
553 canResolveToExpr(equalsNode(Exp)))))),
559 .bind(NodeID<Decl>::value))),
561 return findDeclMutation(Refs);
564const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(
const Expr *Exp) {
565 const auto NonConstRefParam = forEachArgumentWithParam(
566 canResolveToExpr(equalsNode(Exp)),
567 parmVarDecl(hasType(nonConstReferenceType())).bind(
"parm"));
570 const auto Matches =
match(
576 "::std::move",
"::std::forward"))))),
579 .bind(NodeID<Expr>::value))),
581 for (
const auto &
Nodes : Matches) {
582 const auto *Exp =
Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
583 const auto *
Func =
Nodes.getNodeAs<FunctionDecl>(
"func");
584 if (!
Func->getBody() || !
Func->getPrimaryTemplate())
587 const auto *Parm =
Nodes.getNodeAs<ParmVarDecl>(
"parm");
588 const ArrayRef<ParmVarDecl *> AllParams =
589 Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
591 AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
592 AllParams.size() - 1)]
594 if (
const auto *T = ParmType->getAs<PackExpansionType>())
595 ParmType = T->getPattern();
599 if (
const auto *RefType = ParmType->getAs<RValueReferenceType>()) {
600 if (!RefType->getPointeeType().getQualifiers() &&
601 RefType->getPointeeType()->getAs<TemplateTypeParmType>()) {
602 std::unique_ptr<FunctionParmMutationAnalyzer> &Analyzer =
603 FuncParmAnalyzer[
Func];
605 Analyzer.reset(
new FunctionParmMutationAnalyzer(*
Func, Context));
606 if (Analyzer->findMutation(Parm))
619 : BodyAnalyzer(*
Func.getBody(), Context) {
620 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(&
Func)) {
625 for (
const ParmVarDecl *Parm : Ctor->parameters()) {
626 if (Results.contains(Parm))
637 const auto Memoized = Results.find(Parm);
638 if (Memoized != Results.end())
639 return Memoized->second;
642 return Results[Parm] = S;
644 return Results[Parm] =
nullptr;
BoundNodesTreeBuilder Nodes
#define AST_MATCHER(Type, DefineMatcher)
AST_MATCHER(Type, DefineMatcher) { ... } defines a zero parameter function named DefineMatcher() that...
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)
AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... } defines a single-parameter function name...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Represents a C++ base or member initializer.
Decl - This represents one declaration (or definition), e.g.
Analyzes whether any mutative operations are applied to an expression within a given statement.
const Stmt * findMutation(const Expr *Exp)
const Stmt * findPointeeMutation(const Expr *Exp)
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, ASTContext &Context)
This represents one expression.
Represents a function declaration or definition.
const Stmt * findMutation(const ParmVarDecl *Parm)
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context)
Represents a parameter to a function.
Stmt - This represents one statement.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
const internal::VariadicDynCastAllOfMatcher< Stmt, ImplicitCastExpr > implicitCastExpr
Matches the implicit cast nodes of Clang's AST.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDependentScopeMemberExpr > cxxDependentScopeMemberExpr
Matches member expressions where the actual member referenced could not be resolved because the base ...
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnresolvedLookupExpr > unresolvedLookupExpr
Matches reference to a name that can be looked up during parsing but could not be resolved to a speci...
const internal::VariadicDynCastAllOfMatcher< Decl, ParmVarDecl > parmVarDecl
Matches parameter variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, GenericSelectionExpr > genericSelectionExpr
Matches C11 _Generic expression.
const internal::VariadicDynCastAllOfMatcher< Stmt, ReturnStmt > returnStmt
Matches return statements.
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, LambdaExpr > lambdaExpr
Matches lambda expressions.
const AstTypeMatcher< VariableArrayType > variableArrayType
Matches C arrays with a specified size that is not an integer-constant-expression.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryExprOrTypeTraitExpr > unaryExprOrTypeTraitExpr
Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicDynCastAllOfMatcher< Decl, NamedDecl > namedDecl
Matches a declaration of anything that could have a name.
const internal::VariadicAllOfMatcher< TypeLoc > typeLoc
Matches TypeLocs in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, ParenListExpr > parenListExpr
Matches paren list expressions.
const AstTypeMatcher< ArrayType > arrayType
Matches all kinds of arrays.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryOperator > unaryOperator
Matches unary operator expressions.
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
const internal::VariadicDynCastAllOfMatcher< Stmt, ArraySubscriptExpr > arraySubscriptExpr
Matches array subscript expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXForRangeStmt > cxxForRangeStmt
Matches range-based for statements.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXMemberCallExpr > cxxMemberCallExpr
Matches member call expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXConstructorDecl > cxxConstructorDecl
Matches C++ constructor declarations.
internal::BindableMatcher< Stmt > sizeOfExpr(const internal::Matcher< UnaryExprOrTypeTraitExpr > &InnerMatcher)
Same as unaryExprOrTypeTraitExpr, but only matching sizeof.
const internal::VariadicDynCastAllOfMatcher< Stmt, InitListExpr > initListExpr
Matches init list expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXNoexceptExpr > cxxNoexceptExpr
Matches noexcept expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryConditionalOperator > binaryConditionalOperator
Matches binary conditional operator expressions (GNU extension).
const internal::VariadicDynCastAllOfMatcher< Stmt, ExplicitCastExpr > explicitCastExpr
Matches explicit cast expressions.
const AstTypeMatcher< TemplateTypeParmType > templateTypeParmType
Matches template type parameter types.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXConstructExpr > cxxConstructExpr
Matches constructor call expressions (including implicit ones).
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXOperatorCallExpr > cxxOperatorCallExpr
Matches overloaded operator calls.
internal::PolymorphicMatcher< internal::HasOverloadedOperatorNameMatcher, AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl), std::vector< std::string > > hasOverloadedOperatorName(StringRef Name)
Matches overloaded operator names.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnresolvedMemberExpr > unresolvedMemberExpr
Matches unresolved member expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr
Matches member expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
internal::Matcher< T > traverse(TraversalKind TK, const internal::Matcher< T > &InnerMatcher)
Causes all nested matchers to be matched with the specified traversal kind.
const AstTypeMatcher< ReferenceType > referenceType
Matches both lvalue and rvalue reference types.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXUnresolvedConstructExpr > cxxUnresolvedConstructExpr
Matches unresolved constructor call expressions.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclStmt > declStmt
Matches declaration statements.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, ConditionalOperator > conditionalOperator
Matches conditional operator expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXMethodDecl > cxxMethodDecl
Matches method declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, CastExpr > castExpr
Matches any cast nodes of Clang's AST.
const internal::ArgumentAdaptingMatcherFunc< internal::HasAncestorMatcher, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr >, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr > > hasAncestor
Matches AST nodes that have an ancestor that matches the provided matcher.
const internal::ArgumentAdaptingMatcherFunc< internal::HasParentMatcher, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr >, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr > > hasParent
Matches AST nodes that have a parent that matches the provided matcher.
@ TK_AsIs
Will traverse all child nodes.
@ Result
The result type of a method or function.