//===--- ASTNodeTraverser.h - Traversal of AST nodes ----------------------===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// This file implements the AST traversal facilities.  Other users
 
// of this class may make use of the same traversal logic by inheriting it,
 
// similar to RecursiveASTVisitor.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_ASTNODETRAVERSER_H
 
#define LLVM_CLANG_AST_ASTNODETRAVERSER_H
 
 
 
#include "clang/AST/ASTTypeTraits.h"
 
#include "clang/AST/AttrVisitor.h"
 
#include "clang/AST/CommentVisitor.h"
 
#include "clang/AST/DeclVisitor.h"
 
#include "clang/AST/LocInfoType.h"
 
#include "clang/AST/StmtVisitor.h"
 
#include "clang/AST/TemplateArgumentVisitor.h"
 
#include "clang/AST/Type.h"
 
#include "clang/AST/TypeVisitor.h"
 
 
 
namespace clang {
 
 
 
class APValue;
 
 
 
/**
 
 
 
ASTNodeTraverser traverses the Clang AST for dumping purposes.
 
 
 
The `Derived::doGetNodeDelegate()` method is required to be an accessible member
 
which returns a reference of type `NodeDelegateType &` which implements the
 
following interface:
 
 
 
struct {
 
  template <typename Fn> void AddChild(Fn DoAddChild);
 
  template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild);
 
 
 
  void Visit(const comments::Comment *C, const comments::FullComment *FC);
 
  void Visit(const Attr *A);
 
  void Visit(const TemplateArgument &TA, SourceRange R = {},
 
             const Decl *From = nullptr, StringRef Label = {});
 
  void Visit(const Stmt *Node);
 
  void Visit(const Type *T);
 
  void Visit(QualType T);
 
  void Visit(const Decl *D);
 
  void Visit(const CXXCtorInitializer *Init);
 
  void Visit(const OMPClause *C);
 
  void Visit(const BlockDecl::Capture &C);
 
  void Visit(const GenericSelectionExpr::ConstAssociation &A);
 
  void Visit(const concepts::Requirement *R);
 
  void Visit(const APValue &Value, QualType Ty);
 
};
 
*/
 
template <typename Derived, typename NodeDelegateType>
 
class ASTNodeTraverser
 
    : public ConstDeclVisitor<Derived>,
 
      public ConstStmtVisitor<Derived>,
 
      public comments::ConstCommentVisitor<Derived, void,
 
                                           const comments::FullComment *>,
 
      public TypeVisitor<Derived>,
 
      public ConstAttrVisitor<Derived>,
 
      public ConstTemplateArgumentVisitor<Derived> {
 
 
 
  /// Indicates whether we should trigger deserialization of nodes that had
 
  /// not already been loaded.
 
  bool Deserialize = false;
 
 
 
  TraversalKind Traversal = TraversalKind::TK_AsIs;
 
 
 
  NodeDelegateType &getNodeDelegate() {
 
    return getDerived().doGetNodeDelegate();
 
  }
 
  Derived &getDerived() { return *static_cast<Derived *>(this); }
 
 
 
public:
 
  void setDeserialize(bool D) { Deserialize = D; }
 
  bool getDeserialize() const { return Deserialize; }
 
 
 
  void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
 
  TraversalKind GetTraversalKind() const { return Traversal; }
 
 
 
  void Visit(const Decl *D) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
 
      return;
 
 
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(D);
 
      if (!D)
 
        return;
 
 
 
      ConstDeclVisitor<Derived>::Visit(D);
 
 
 
      for (const auto &A : D->attrs())
 
        Visit(A);
 
 
 
      if (const comments::FullComment *Comment =
 
              D->getASTContext().getLocalCommentForDeclUncached(D))
 
        Visit(Comment, Comment);
 
 
 
      // Decls within functions are visited by the body.
 
      if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) {
 
        if (Traversal != TK_AsIs) {
 
          if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
 
            auto SK = CTSD->getSpecializationKind();
 
            if (SK == TSK_ExplicitInstantiationDeclaration ||
 
                SK == TSK_ExplicitInstantiationDefinition)
 
              return;
 
          }
 
        }
 
        if (const auto *DC = dyn_cast<DeclContext>(D))
 
          dumpDeclContext(DC);
 
      }
 
    });
 
  }
 
 
 
  void Visit(const Stmt *Node, StringRef Label = {}) {
 
    getNodeDelegate().AddChild(Label, [=] {
 
      const Stmt *S = Node;
 
 
 
      if (auto *E = dyn_cast_or_null<Expr>(S)) {
 
        switch (Traversal) {
 
        case TK_AsIs:
 
          break;
 
        case TK_IgnoreUnlessSpelledInSource:
 
          S = E->IgnoreUnlessSpelledInSource();
 
          break;
 
        }
 
      }
 
 
 
      getNodeDelegate().Visit(S);
 
 
 
      if (!S) {
 
        return;
 
      }
 
 
 
      ConstStmtVisitor<Derived>::Visit(S);
 
 
 
      // Some statements have custom mechanisms for dumping their children.
 
      if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) ||
 
          isa<RequiresExpr>(S))
 
        return;
 
 
 
      if (Traversal == TK_IgnoreUnlessSpelledInSource &&
 
          isa<LambdaExpr, CXXForRangeStmt, CallExpr,
 
              CXXRewrittenBinaryOperator>(S))
 
        return;
 
 
 
      for (const Stmt *SubStmt : S->children())
 
        Visit(SubStmt);
 
    });
 
  }
 
 
 
  void Visit(QualType T) {
 
    SplitQualType SQT = T.split();
 
    if (!SQT.Quals.hasQualifiers())
 
      return Visit(SQT.Ty);
 
 
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(T);
 
      Visit(T.split().Ty);
 
    });
 
  }
 
 
 
  void Visit(const Type *T) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(T);
 
      if (!T)
 
        return;
 
      TypeVisitor<Derived>::Visit(T);
 
 
 
      QualType SingleStepDesugar =
 
          T->getLocallyUnqualifiedSingleStepDesugaredType();
 
      if (SingleStepDesugar != QualType(T, 0))
 
        Visit(SingleStepDesugar);
 
    });
 
  }
 
 
 
  void Visit(const Attr *A) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(A);
 
      ConstAttrVisitor<Derived>::Visit(A);
 
    });
 
  }
 
 
 
  void Visit(const CXXCtorInitializer *Init) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource && !Init->isWritten())
 
      return;
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(Init);
 
      Visit(Init->getInit());
 
    });
 
  }
 
 
 
  void Visit(const TemplateArgument &A, SourceRange R = {},
 
             const Decl *From = nullptr, const char *Label = nullptr) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(A, R, From, Label);
 
      ConstTemplateArgumentVisitor<Derived>::Visit(A);
 
    });
 
  }
 
 
 
  void Visit(const BlockDecl::Capture &C) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(C);
 
      if (C.hasCopyExpr())
 
        Visit(C.getCopyExpr());
 
    });
 
  }
 
 
 
  void Visit(const OMPClause *C) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(C);
 
      for (const auto *S : C->children())
 
        Visit(S);
 
    });
 
  }
 
 
 
  void Visit(const GenericSelectionExpr::ConstAssociation &A) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(A);
 
      if (const TypeSourceInfo *TSI = A.getTypeSourceInfo())
 
        Visit(TSI->getType());
 
      Visit(A.getAssociationExpr());
 
    });
 
  }
 
 
 
  void Visit(const concepts::Requirement *R) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(R);
 
      if (!R)
 
        return;
 
      if (auto *TR = dyn_cast<concepts::TypeRequirement>(R)) {
 
        if (!TR->isSubstitutionFailure())
 
          Visit(TR->getType()->getType().getTypePtr());
 
      } else if (auto *ER = dyn_cast<concepts::ExprRequirement>(R)) {
 
        if (!ER->isExprSubstitutionFailure())
 
          Visit(ER->getExpr());
 
        if (!ER->getReturnTypeRequirement().isEmpty())
 
          Visit(ER->getReturnTypeRequirement()
 
                    .getTypeConstraint()
 
                    ->getImmediatelyDeclaredConstraint());
 
      } else if (auto *NR = dyn_cast<concepts::NestedRequirement>(R)) {
 
        if (!NR->hasInvalidConstraint())
 
          Visit(NR->getConstraintExpr());
 
      }
 
    });
 
  }
 
 
 
  void Visit(const APValue &Value, QualType Ty) {
 
    getNodeDelegate().AddChild([=] { getNodeDelegate().Visit(Value, Ty); });
 
  }
 
 
 
  void Visit(const comments::Comment *C, const comments::FullComment *FC) {
 
    getNodeDelegate().AddChild([=] {
 
      getNodeDelegate().Visit(C, FC);
 
      if (!C) {
 
        return;
 
      }
 
      comments::ConstCommentVisitor<Derived, void,
 
                                    const comments::FullComment *>::visit(C,
 
                                                                          FC);
 
      for (comments::Comment::child_iterator I = C->child_begin(),
 
                                             E = C->child_end();
 
           I != E; ++I)
 
        Visit(*I, FC);
 
    });
 
  }
 
 
 
  void Visit(const DynTypedNode &N) {
 
    // FIXME: Improve this with a switch or a visitor pattern.
 
    if (const auto *D = N.get<Decl>())
 
      Visit(D);
 
    else if (const auto *S = N.get<Stmt>())
 
      Visit(S);
 
    else if (const auto *QT = N.get<QualType>())
 
      Visit(*QT);
 
    else if (const auto *T = N.get<Type>())
 
      Visit(T);
 
    else if (const auto *C = N.get<CXXCtorInitializer>())
 
      Visit(C);
 
    else if (const auto *C = N.get<OMPClause>())
 
      Visit(C);
 
    else if (const auto *T = N.get<TemplateArgument>())
 
      Visit(*T);
 
  }
 
 
 
  void dumpDeclContext(const DeclContext *DC) {
 
    if (!DC)
 
      return;
 
 
 
    for (const auto *D : (Deserialize ? DC->decls() : DC->noload_decls()))
 
      Visit(D);
 
  }
 
 
 
  void dumpTemplateParameters(const TemplateParameterList *TPL) {
 
    if (!TPL)
 
      return;
 
 
 
    for (const auto &TP : *TPL)
 
      Visit(TP);
 
 
 
    if (const Expr *RC = TPL->getRequiresClause())
 
      Visit(RC);
 
  }
 
 
 
  void
 
  dumpASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *TALI) {
 
    if (!TALI)
 
      return;
 
 
 
    for (const auto &TA : TALI->arguments())
 
      dumpTemplateArgumentLoc(TA);
 
  }
 
 
 
  void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A,
 
                               const Decl *From = nullptr,
 
                               const char *Label = nullptr) {
 
    Visit(A.getArgument(), A.getSourceRange(), From, Label);
 
  }
 
 
 
  void dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
 
    for (unsigned i = 0, e = TAL.size(); i < e; ++i)
 
      Visit(TAL[i]);
 
  }
 
 
 
  void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
 
    if (!typeParams)
 
      return;
 
 
 
    for (const auto &typeParam : *typeParams) {
 
      Visit(typeParam);
 
    }
 
  }
 
 
 
  void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
 
  void VisitLocInfoType(const LocInfoType *T) {
 
    Visit(T->getTypeSourceInfo()->getType());
 
  }
 
  void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
 
  void VisitBlockPointerType(const BlockPointerType *T) {
 
    Visit(T->getPointeeType());
 
  }
 
  void VisitReferenceType(const ReferenceType *T) {
 
    Visit(T->getPointeeType());
 
  }
 
  void VisitMemberPointerType(const MemberPointerType *T) {
 
    Visit(T->getClass());
 
    Visit(T->getPointeeType());
 
  }
 
  void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); }
 
  void VisitVariableArrayType(const VariableArrayType *T) {
 
    VisitArrayType(T);
 
    Visit(T->getSizeExpr());
 
  }
 
  void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
 
    Visit(T->getElementType());
 
    Visit(T->getSizeExpr());
 
  }
 
  void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) {
 
    Visit(T->getElementType());
 
    Visit(T->getSizeExpr());
 
  }
 
  void VisitVectorType(const VectorType *T) { Visit(T->getElementType()); }
 
  void VisitFunctionType(const FunctionType *T) { Visit(T->getReturnType()); }
 
  void VisitFunctionProtoType(const FunctionProtoType *T) {
 
    VisitFunctionType(T);
 
    for (const QualType &PT : T->getParamTypes())
 
      Visit(PT);
 
  }
 
  void VisitTypeOfExprType(const TypeOfExprType *T) {
 
    Visit(T->getUnderlyingExpr());
 
  }
 
  void VisitDecltypeType(const DecltypeType *T) {
 
    Visit(T->getUnderlyingExpr());
 
  }
 
  void VisitUnaryTransformType(const UnaryTransformType *T) {
 
    Visit(T->getBaseType());
 
  }
 
  void VisitAttributedType(const AttributedType *T) {
 
    // FIXME: AttrKind
 
    Visit(T->getModifiedType());
 
  }
 
  void VisitBTFTagAttributedType(const BTFTagAttributedType *T) {
 
    Visit(T->getWrappedType());
 
  }
 
  void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *) {}
 
  void
 
  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
 
    Visit(T->getArgumentPack());
 
  }
 
  void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
 
    for (const auto &Arg : T->template_arguments())
 
      Visit(Arg);
 
  }
 
  void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
 
    Visit(T->getPointeeType());
 
  }
 
  void VisitAtomicType(const AtomicType *T) { Visit(T->getValueType()); }
 
  void VisitPipeType(const PipeType *T) { Visit(T->getElementType()); }
 
  void VisitAdjustedType(const AdjustedType *T) { Visit(T->getOriginalType()); }
 
  void VisitPackExpansionType(const PackExpansionType *T) {
 
    if (!T->isSugared())
 
      Visit(T->getPattern());
 
  }
 
  // FIXME: ElaboratedType, DependentNameType,
 
  // DependentTemplateSpecializationType, ObjCObjectType
 
 
 
  void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }
 
 
 
  void VisitEnumConstantDecl(const EnumConstantDecl *D) {
 
    if (const Expr *Init = D->getInitExpr())
 
      Visit(Init);
 
  }
 
 
 
  void VisitFunctionDecl(const FunctionDecl *D) {
 
    if (const auto *FTSI = D->getTemplateSpecializationInfo())
 
      dumpTemplateArgumentList(*FTSI->TemplateArguments);
 
 
 
    if (D->param_begin())
 
      for (const auto *Parameter : D->parameters())
 
        Visit(Parameter);
 
 
 
    if (const Expr *TRC = D->getTrailingRequiresClause())
 
      Visit(TRC);
 
 
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isDefaulted())
 
      return;
 
 
 
    if (const auto *C = dyn_cast<CXXConstructorDecl>(D))
 
      for (const auto *I : C->inits())
 
        Visit(I);
 
 
 
    if (D->doesThisDeclarationHaveABody())
 
      Visit(D->getBody());
 
  }
 
 
 
  void VisitFieldDecl(const FieldDecl *D) {
 
    if (D->isBitField())
 
      Visit(D->getBitWidth());
 
    if (Expr *Init = D->getInClassInitializer())
 
      Visit(Init);
 
  }
 
 
 
  void VisitVarDecl(const VarDecl *D) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl())
 
      return;
 
 
 
    if (D->hasInit())
 
      Visit(D->getInit());
 
  }
 
 
 
  void VisitDecompositionDecl(const DecompositionDecl *D) {
 
    VisitVarDecl(D);
 
    for (const auto *B : D->bindings())
 
      Visit(B);
 
  }
 
 
 
  void VisitBindingDecl(const BindingDecl *D) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource)
 
      return;
 
 
 
    if (const auto *V = D->getHoldingVar())
 
      Visit(V);
 
 
 
    if (const auto *E = D->getBinding())
 
      Visit(E);
 
  }
 
 
 
  void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
 
    Visit(D->getAsmString());
 
  }
 
 
 
  void VisitTopLevelStmtDecl(const TopLevelStmtDecl *D) { Visit(D->getStmt()); }
 
 
 
  void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); }
 
 
 
  void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
 
    for (const auto *E : D->varlists())
 
      Visit(E);
 
  }
 
 
 
  void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) {
 
    Visit(D->getCombiner());
 
    if (const auto *Initializer = D->getInitializer())
 
      Visit(Initializer);
 
  }
 
 
 
  void VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) {
 
    for (const auto *C : D->clauselists())
 
      Visit(C);
 
  }
 
 
 
  void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) {
 
    Visit(D->getInit());
 
  }
 
 
 
  void VisitOMPAllocateDecl(const OMPAllocateDecl *D) {
 
    for (const auto *E : D->varlists())
 
      Visit(E);
 
    for (const auto *C : D->clauselists())
 
      Visit(C);
 
  }
 
 
 
  template <typename SpecializationDecl>
 
  void dumpTemplateDeclSpecialization(const SpecializationDecl *D) {
 
    for (const auto *RedeclWithBadType : D->redecls()) {
 
      // FIXME: The redecls() range sometimes has elements of a less-specific
 
      // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
 
      // us TagDecls, and should give CXXRecordDecls).
 
      auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
 
      if (!Redecl) {
 
        // Found the injected-class-name for a class template. This will be
 
        // dumped as part of its surrounding class so we don't need to dump it
 
        // here.
 
        assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
 
               "expected an injected-class-name");
 
        continue;
 
      }
 
      Visit(Redecl);
 
    }
 
  }
 
 
 
  template <typename TemplateDecl>
 
  void dumpTemplateDecl(const TemplateDecl *D) {
 
    dumpTemplateParameters(D->getTemplateParameters());
 
 
 
    Visit(D->getTemplatedDecl());
 
 
 
    if (Traversal == TK_AsIs) {
 
      for (const auto *Child : D->specializations())
 
        dumpTemplateDeclSpecialization(Child);
 
    }
 
  }
 
 
 
  void VisitTypeAliasDecl(const TypeAliasDecl *D) {
 
    Visit(D->getUnderlyingType());
 
  }
 
 
 
  void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
 
    dumpTemplateParameters(D->getTemplateParameters());
 
    Visit(D->getTemplatedDecl());
 
  }
 
 
 
  void VisitStaticAssertDecl(const StaticAssertDecl *D) {
 
    Visit(D->getAssertExpr());
 
    Visit(D->getMessage());
 
  }
 
 
 
  void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
 
    dumpTemplateDecl(D);
 
  }
 
 
 
  void VisitClassTemplateDecl(const ClassTemplateDecl *D) {
 
    dumpTemplateDecl(D);
 
  }
 
 
 
  void VisitClassTemplateSpecializationDecl(
 
      const ClassTemplateSpecializationDecl *D) {
 
    dumpTemplateArgumentList(D->getTemplateArgs());
 
  }
 
 
 
  void VisitClassTemplatePartialSpecializationDecl(
 
      const ClassTemplatePartialSpecializationDecl *D) {
 
    VisitClassTemplateSpecializationDecl(D);
 
    dumpTemplateParameters(D->getTemplateParameters());
 
  }
 
 
 
  void VisitClassScopeFunctionSpecializationDecl(
 
      const ClassScopeFunctionSpecializationDecl *D) {
 
    Visit(D->getSpecialization());
 
    dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
 
  }
 
  void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); }
 
 
 
  void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
 
    dumpTemplateParameters(D->getTemplateParameters());
 
  }
 
 
 
  void
 
  VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *D) {
 
    dumpTemplateArgumentList(D->getTemplateArgs());
 
    VisitVarDecl(D);
 
  }
 
 
 
  void VisitVarTemplatePartialSpecializationDecl(
 
      const VarTemplatePartialSpecializationDecl *D) {
 
    dumpTemplateParameters(D->getTemplateParameters());
 
    VisitVarTemplateSpecializationDecl(D);
 
  }
 
 
 
  void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
 
    if (const auto *TC = D->getTypeConstraint())
 
      Visit(TC->getImmediatelyDeclaredConstraint());
 
    if (D->hasDefaultArgument())
 
      Visit(D->getDefaultArgument(), SourceRange(),
 
            D->getDefaultArgStorage().getInheritedFrom(),
 
            D->defaultArgumentWasInherited() ? "inherited from" : "previous");
 
  }
 
 
 
  void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
 
    if (const auto *E = D->getPlaceholderTypeConstraint())
 
      Visit(E);
 
    if (D->hasDefaultArgument())
 
      Visit(D->getDefaultArgument(), SourceRange(),
 
            D->getDefaultArgStorage().getInheritedFrom(),
 
            D->defaultArgumentWasInherited() ? "inherited from" : "previous");
 
  }
 
 
 
  void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
 
    dumpTemplateParameters(D->getTemplateParameters());
 
    if (D->hasDefaultArgument())
 
      dumpTemplateArgumentLoc(
 
          D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
 
          D->defaultArgumentWasInherited() ? "inherited from" : "previous");
 
  }
 
 
 
  void VisitConceptDecl(const ConceptDecl *D) {
 
    dumpTemplateParameters(D->getTemplateParameters());
 
    Visit(D->getConstraintExpr());
 
  }
 
 
 
  void VisitImplicitConceptSpecializationDecl(
 
      const ImplicitConceptSpecializationDecl *CSD) {
 
    for (const TemplateArgument &Arg : CSD->getTemplateArguments())
 
      Visit(Arg);
 
  }
 
 
 
  void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *CSE) {
 
    Visit(CSE->getSpecializationDecl());
 
    if (CSE->hasExplicitTemplateArgs())
 
      for (const auto &ArgLoc : CSE->getTemplateArgsAsWritten()->arguments())
 
        dumpTemplateArgumentLoc(ArgLoc);
 
  }
 
 
 
  void VisitUsingShadowDecl(const UsingShadowDecl *D) {
 
    if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
 
      Visit(TD->getTypeForDecl());
 
  }
 
 
 
  void VisitFriendDecl(const FriendDecl *D) {
 
    if (D->getFriendType()) {
 
      // Traverse any CXXRecordDecl owned by this type, since
 
      // it will not be in the parent context:
 
      if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>())
 
        if (auto *TD = ET->getOwnedTagDecl())
 
          Visit(TD);
 
    } else {
 
      Visit(D->getFriendDecl());
 
    }
 
  }
 
 
 
  void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
 
    if (D->isThisDeclarationADefinition())
 
      dumpDeclContext(D);
 
    else
 
      for (const ParmVarDecl *Parameter : D->parameters())
 
        Visit(Parameter);
 
 
 
    if (D->hasBody())
 
      Visit(D->getBody());
 
  }
 
 
 
  void VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
 
    dumpObjCTypeParamList(D->getTypeParamList());
 
  }
 
 
 
  void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
 
    dumpObjCTypeParamList(D->getTypeParamListAsWritten());
 
  }
 
 
 
  void VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
 
    for (const auto &I : D->inits())
 
      Visit(I);
 
  }
 
 
 
  void VisitBlockDecl(const BlockDecl *D) {
 
    for (const auto &I : D->parameters())
 
      Visit(I);
 
 
 
    for (const auto &I : D->captures())
 
      Visit(I);
 
    Visit(D->getBody());
 
  }
 
 
 
  void VisitDeclStmt(const DeclStmt *Node) {
 
    for (const auto &D : Node->decls())
 
      Visit(D);
 
  }
 
 
 
  void VisitAttributedStmt(const AttributedStmt *Node) {
 
    for (const auto *A : Node->getAttrs())
 
      Visit(A);
 
  }
 
 
 
  void VisitCXXCatchStmt(const CXXCatchStmt *Node) {
 
    Visit(Node->getExceptionDecl());
 
  }
 
 
 
  void VisitCapturedStmt(const CapturedStmt *Node) {
 
    Visit(Node->getCapturedDecl());
 
  }
 
 
 
  void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
 
    for (const auto *C : Node->clauses())
 
      Visit(C);
 
  }
 
 
 
  void VisitInitListExpr(const InitListExpr *ILE) {
 
    if (auto *Filler = ILE->getArrayFiller()) {
 
      Visit(Filler, "array_filler");
 
    }
 
  }
 
 
 
  void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) {
 
    if (auto *Filler = PLIE->getArrayFiller()) {
 
      Visit(Filler, "array_filler");
 
    }
 
  }
 
 
 
  void VisitBlockExpr(const BlockExpr *Node) { Visit(Node->getBlockDecl()); }
 
 
 
  void VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
 
    if (Expr *Source = Node->getSourceExpr())
 
      Visit(Source);
 
  }
 
 
 
  void VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
 
    Visit(E->getControllingExpr());
 
    Visit(E->getControllingExpr()->getType()); // FIXME: remove
 
 
 
    for (const auto Assoc : E->associations()) {
 
      Visit(Assoc);
 
    }
 
  }
 
 
 
  void VisitRequiresExpr(const RequiresExpr *E) {
 
    for (auto *D : E->getLocalParameters())
 
      Visit(D);
 
    for (auto *R : E->getRequirements())
 
      Visit(R);
 
  }
 
 
 
  void VisitLambdaExpr(const LambdaExpr *Node) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource) {
 
      for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
 
        const auto *C = Node->capture_begin() + I;
 
        if (!C->isExplicit())
 
          continue;
 
        if (Node->isInitCapture(C))
 
          Visit(C->getCapturedVar());
 
        else
 
          Visit(Node->capture_init_begin()[I]);
 
      }
 
      dumpTemplateParameters(Node->getTemplateParameterList());
 
      for (const auto *P : Node->getCallOperator()->parameters())
 
        Visit(P);
 
      Visit(Node->getBody());
 
    } else {
 
      return Visit(Node->getLambdaClass());
 
    }
 
  }
 
 
 
  void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
 
    if (Node->isPartiallySubstituted())
 
      for (const auto &A : Node->getPartialArguments())
 
        Visit(A);
 
  }
 
 
 
  void VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
 
    Visit(E->getParameter());
 
  }
 
  void VisitSubstNonTypeTemplateParmPackExpr(
 
      const SubstNonTypeTemplateParmPackExpr *E) {
 
    Visit(E->getParameterPack());
 
    Visit(E->getArgumentPack());
 
  }
 
 
 
  void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
 
    if (const VarDecl *CatchParam = Node->getCatchParamDecl())
 
      Visit(CatchParam);
 
  }
 
 
 
  void VisitCXXForRangeStmt(const CXXForRangeStmt *Node) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource) {
 
      Visit(Node->getInit());
 
      Visit(Node->getLoopVariable());
 
      Visit(Node->getRangeInit());
 
      Visit(Node->getBody());
 
    }
 
  }
 
 
 
  void VisitCallExpr(const CallExpr *Node) {
 
    for (const auto *Child :
 
         make_filter_range(Node->children(), [this](const Stmt *Child) {
 
           if (Traversal != TK_IgnoreUnlessSpelledInSource)
 
             return false;
 
           return !isa<CXXDefaultArgExpr>(Child);
 
         })) {
 
      Visit(Child);
 
    }
 
  }
 
 
 
  void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *Node) {
 
    if (Traversal == TK_IgnoreUnlessSpelledInSource) {
 
      Visit(Node->getLHS());
 
      Visit(Node->getRHS());
 
    } else {
 
      ConstStmtVisitor<Derived>::VisitCXXRewrittenBinaryOperator(Node);
 
    }
 
  }
 
 
 
  void VisitExpressionTemplateArgument(const TemplateArgument &TA) {
 
    Visit(TA.getAsExpr());
 
  }
 
 
 
  void VisitTypeTemplateArgument(const TemplateArgument &TA) {
 
    Visit(TA.getAsType());
 
  }
 
 
 
  void VisitPackTemplateArgument(const TemplateArgument &TA) {
 
    for (const auto &TArg : TA.pack_elements())
 
      Visit(TArg);
 
  }
 
 
 
  // Implements Visit methods for Attrs.
 
#include "clang/AST/AttrNodeTraverse.inc"
 
};
 
 
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_AST_ASTNODETRAVERSER_H