//===- CursorVisitor.h - CursorVisitor interface ----------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H #define LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H #include "CXCursor.h" #include "CXTranslationUnit.h" #include "Index_Internal.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/TypeLocVisitor.h" #include namespace clang { class PreprocessingRecord; class ASTUnit; namespace concepts { class Requirement; } namespace cxcursor { class VisitorJob { public: enum Kind { DeclVisitKind, StmtVisitKind, MemberExprPartsKind, TypeLocVisitKind, OverloadExprPartsKind, DeclRefExprPartsKind, LabelRefVisitKind, ExplicitTemplateArgsVisitKind, NestedNameSpecifierLocVisitKind, DeclarationNameInfoVisitKind, MemberRefVisitKind, SizeOfPackExprPartsKind, LambdaExprPartsKind, ConceptSpecializationExprVisitKind, RequiresExprVisitKind, PostChildrenVisitKind }; protected: const void *data[3]; CXCursor parent; Kind K; VisitorJob(CXCursor C, Kind k, const void *d1, const void *d2 = nullptr, const void *d3 = nullptr) : parent(C), K(k) { data[0] = d1; data[1] = d2; data[2] = d3; } public: Kind getKind() const { return K; } const CXCursor &getParent() const { return parent; } }; typedef SmallVector VisitorWorkList; // Cursor visitor. class CursorVisitor : public DeclVisitor, public TypeLocVisitor { public: /// Callback called after child nodes of a cursor have been visited. /// Return true to break visitation or false to continue. typedef bool (*PostChildrenVisitorTy)(CXCursor cursor, CXClientData client_data); private: /// The translation unit we are traversing. CXTranslationUnit TU; ASTUnit *AU; /// The parent cursor whose children we are traversing. CXCursor Parent; /// The declaration that serves at the parent of any statement or /// expression nodes. const Decl *StmtParent; /// The visitor function. CXCursorVisitor Visitor; PostChildrenVisitorTy PostChildrenVisitor; /// The opaque client data, to be passed along to the visitor. CXClientData ClientData; /// Whether we should visit the preprocessing record entries last, /// after visiting other declarations. bool VisitPreprocessorLast; /// Whether we should visit declarations or preprocessing record /// entries that are #included inside the \arg RegionOfInterest. bool VisitIncludedEntities; /// When valid, a source range to which the cursor should restrict /// its search. SourceRange RegionOfInterest; /// Whether we should only visit declarations and not preprocessing /// record entries. bool VisitDeclsOnly; // FIXME: Eventually remove. This part of a hack to support proper // iteration over all Decls contained lexically within an ObjC container. DeclContext::decl_iterator *DI_current; DeclContext::decl_iterator DE_current; SmallVectorImpl::iterator *FileDI_current; SmallVectorImpl::iterator FileDE_current; // Cache of pre-allocated worklists for data-recursion walk of Stmts. SmallVector WorkListFreeList; SmallVector WorkListCache; using DeclVisitor::Visit; using TypeLocVisitor::Visit; /// Determine whether this particular source range comes before, comes /// after, or overlaps the region of interest. /// /// \param R a half-open source range retrieved from the abstract syntax tree. RangeComparisonResult CompareRegionOfInterest(SourceRange R); bool visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length); class SetParentRAII { CXCursor &Parent; const Decl *&StmtParent; CXCursor OldParent; public: SetParentRAII(CXCursor &Parent, const Decl *&StmtParent, CXCursor NewParent) : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) { Parent = NewParent; if (clang_isDeclaration(Parent.kind)) StmtParent = getCursorDecl(Parent); } ~SetParentRAII() { Parent = OldParent; if (clang_isDeclaration(Parent.kind)) StmtParent = getCursorDecl(Parent); } }; public: CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor, CXClientData ClientData, bool VisitPreprocessorLast, bool VisitIncludedPreprocessingEntries = false, SourceRange RegionOfInterest = SourceRange(), bool VisitDeclsOnly = false, PostChildrenVisitorTy PostChildrenVisitor = nullptr) : TU(TU), AU(cxtu::getASTUnit(TU)), Visitor(Visitor), PostChildrenVisitor(PostChildrenVisitor), ClientData(ClientData), VisitPreprocessorLast(VisitPreprocessorLast), VisitIncludedEntities(VisitIncludedPreprocessingEntries), RegionOfInterest(RegionOfInterest), VisitDeclsOnly(VisitDeclsOnly), DI_current(nullptr), FileDI_current(nullptr) { Parent.kind = CXCursor_NoDeclFound; Parent.data[0] = nullptr; Parent.data[1] = nullptr; Parent.data[2] = nullptr; StmtParent = nullptr; } ~CursorVisitor() { // Free the pre-allocated worklists for data-recursion. for (SmallVectorImpl::iterator I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) { delete *I; } } ASTUnit *getASTUnit() const { return AU; } CXTranslationUnit getTU() const { return TU; } bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); /// Visit declarations and preprocessed entities for the file region /// designated by \see RegionOfInterest. bool visitFileRegion(); bool visitPreprocessedEntitiesInRegion(); bool shouldVisitIncludedEntities() const { return VisitIncludedEntities; } template bool visitPreprocessedEntities(InputIterator First, InputIterator Last, PreprocessingRecord &PPRec, FileID FID = FileID()); bool VisitChildren(CXCursor Parent); // Declaration visitors bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); bool VisitTypeAliasDecl(TypeAliasDecl *D); bool VisitAttributes(Decl *D); bool VisitBlockDecl(BlockDecl *B); bool VisitCXXRecordDecl(CXXRecordDecl *D); std::optional shouldVisitCursor(CXCursor C); bool VisitDeclContext(DeclContext *DC); bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTypedefDecl(TypedefDecl *D); bool VisitTagDecl(TagDecl *D); bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); bool VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); bool VisitEnumConstantDecl(EnumConstantDecl *D); bool VisitDeclaratorDecl(DeclaratorDecl *DD); bool VisitFunctionDecl(FunctionDecl *ND); bool VisitFieldDecl(FieldDecl *D); bool VisitVarDecl(VarDecl *); bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); bool VisitClassTemplateDecl(ClassTemplateDecl *D); bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); bool VisitObjCMethodDecl(ObjCMethodDecl *ND); bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD); bool VisitLinkageSpecDecl(LinkageSpecDecl *D); bool VisitNamespaceDecl(NamespaceDecl *D); bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); bool VisitUsingDecl(UsingDecl *D); bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); bool VisitStaticAssertDecl(StaticAssertDecl *D); bool VisitFriendDecl(FriendDecl *D); bool VisitDecompositionDecl(DecompositionDecl *D); bool VisitConceptDecl(ConceptDecl *D); bool VisitTypeConstraint(const TypeConstraint &TC); bool VisitConceptRequirement(const concepts::Requirement &R); // Name visitor bool VisitDeclarationNameInfo(DeclarationNameInfo Name); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); // Template visitors bool VisitTemplateParameters(const TemplateParameterList *Params); bool VisitTemplateName(TemplateName Name, SourceLocation Loc); bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); // Type visitors #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); #include "clang/AST/TypeLocNodes.def" bool VisitTagTypeLoc(TagTypeLoc TL); bool VisitArrayTypeLoc(ArrayTypeLoc TL); bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); // Data-recursive visitor functions. bool IsInRegionOfInterest(CXCursor C); bool RunVisitorWorkList(VisitorWorkList &WL); void EnqueueWorkList(VisitorWorkList &WL, const Stmt *S); LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S); private: std::optional handleDeclForVisitation(const Decl *D); }; } // namespace cxcursor } // namespace clang #endif