1 | //===- CursorVisitor.h - CursorVisitor interface ----------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H |
10 | #define LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H |
11 | |
12 | #include "CXCursor.h" |
13 | #include "CXTranslationUnit.h" |
14 | #include "Index_Internal.h" |
15 | #include "clang/AST/DeclVisitor.h" |
16 | #include "clang/AST/TypeLocVisitor.h" |
17 | #include <optional> |
18 | |
19 | namespace clang { |
20 | class PreprocessingRecord; |
21 | class ASTUnit; |
22 | |
23 | namespace concepts { |
24 | class Requirement; |
25 | } |
26 | |
27 | namespace cxcursor { |
28 | |
29 | class VisitorJob { |
30 | public: |
31 | enum Kind { |
32 | DeclVisitKind, |
33 | StmtVisitKind, |
34 | MemberExprPartsKind, |
35 | TypeLocVisitKind, |
36 | OverloadExprPartsKind, |
37 | DeclRefExprPartsKind, |
38 | LabelRefVisitKind, |
39 | ExplicitTemplateArgsVisitKind, |
40 | NestedNameSpecifierLocVisitKind, |
41 | DeclarationNameInfoVisitKind, |
42 | MemberRefVisitKind, |
43 | SizeOfPackExprPartsKind, |
44 | LambdaExprPartsKind, |
45 | ConceptSpecializationExprVisitKind, |
46 | RequiresExprVisitKind, |
47 | PostChildrenVisitKind |
48 | }; |
49 | |
50 | protected: |
51 | const void *data[3]; |
52 | CXCursor parent; |
53 | Kind K; |
54 | VisitorJob(CXCursor C, Kind k, const void *d1, const void *d2 = nullptr, |
55 | const void *d3 = nullptr) |
56 | : parent(C), K(k) { |
57 | data[0] = d1; |
58 | data[1] = d2; |
59 | data[2] = d3; |
60 | } |
61 | |
62 | public: |
63 | Kind getKind() const { return K; } |
64 | const CXCursor &getParent() const { return parent; } |
65 | }; |
66 | |
67 | typedef SmallVector<VisitorJob, 10> VisitorWorkList; |
68 | |
69 | // Cursor visitor. |
70 | class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, |
71 | public TypeLocVisitor<CursorVisitor, bool> { |
72 | public: |
73 | /// Callback called after child nodes of a cursor have been visited. |
74 | /// Return true to break visitation or false to continue. |
75 | typedef bool (*PostChildrenVisitorTy)(CXCursor cursor, |
76 | CXClientData client_data); |
77 | |
78 | private: |
79 | /// The translation unit we are traversing. |
80 | CXTranslationUnit TU; |
81 | ASTUnit *AU; |
82 | |
83 | /// The parent cursor whose children we are traversing. |
84 | CXCursor Parent; |
85 | |
86 | /// The declaration that serves at the parent of any statement or |
87 | /// expression nodes. |
88 | const Decl *StmtParent; |
89 | |
90 | /// The visitor function. |
91 | CXCursorVisitor Visitor; |
92 | |
93 | PostChildrenVisitorTy PostChildrenVisitor; |
94 | |
95 | /// The opaque client data, to be passed along to the visitor. |
96 | CXClientData ClientData; |
97 | |
98 | /// Whether we should visit the preprocessing record entries last, |
99 | /// after visiting other declarations. |
100 | bool VisitPreprocessorLast; |
101 | |
102 | /// Whether we should visit declarations or preprocessing record |
103 | /// entries that are #included inside the \arg RegionOfInterest. |
104 | bool VisitIncludedEntities; |
105 | |
106 | /// When valid, a source range to which the cursor should restrict |
107 | /// its search. |
108 | SourceRange RegionOfInterest; |
109 | |
110 | /// Whether we should only visit declarations and not preprocessing |
111 | /// record entries. |
112 | bool VisitDeclsOnly; |
113 | |
114 | // FIXME: Eventually remove. This part of a hack to support proper |
115 | // iteration over all Decls contained lexically within an ObjC container. |
116 | DeclContext::decl_iterator *DI_current; |
117 | DeclContext::decl_iterator DE_current; |
118 | SmallVectorImpl<Decl *>::iterator *FileDI_current; |
119 | SmallVectorImpl<Decl *>::iterator FileDE_current; |
120 | |
121 | // Cache of pre-allocated worklists for data-recursion walk of Stmts. |
122 | SmallVector<VisitorWorkList *, 5> WorkListFreeList; |
123 | SmallVector<VisitorWorkList *, 5> WorkListCache; |
124 | |
125 | using DeclVisitor<CursorVisitor, bool>::Visit; |
126 | using TypeLocVisitor<CursorVisitor, bool>::Visit; |
127 | |
128 | /// Determine whether this particular source range comes before, comes |
129 | /// after, or overlaps the region of interest. |
130 | /// |
131 | /// \param R a half-open source range retrieved from the abstract syntax tree. |
132 | RangeComparisonResult CompareRegionOfInterest(SourceRange R); |
133 | |
134 | bool visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length); |
135 | |
136 | class SetParentRAII { |
137 | CXCursor &Parent; |
138 | const Decl *&StmtParent; |
139 | CXCursor OldParent; |
140 | |
141 | public: |
142 | SetParentRAII(CXCursor &Parent, const Decl *&StmtParent, CXCursor NewParent) |
143 | : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) { |
144 | Parent = NewParent; |
145 | if (clang_isDeclaration(Parent.kind)) |
146 | StmtParent = getCursorDecl(Cursor: Parent); |
147 | } |
148 | |
149 | ~SetParentRAII() { |
150 | Parent = OldParent; |
151 | if (clang_isDeclaration(Parent.kind)) |
152 | StmtParent = getCursorDecl(Cursor: Parent); |
153 | } |
154 | }; |
155 | |
156 | public: |
157 | CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor, |
158 | CXClientData ClientData, bool VisitPreprocessorLast, |
159 | bool VisitIncludedPreprocessingEntries = false, |
160 | SourceRange RegionOfInterest = SourceRange(), |
161 | bool VisitDeclsOnly = false, |
162 | PostChildrenVisitorTy PostChildrenVisitor = nullptr) |
163 | : TU(TU), AU(cxtu::getASTUnit(TU)), Visitor(Visitor), |
164 | PostChildrenVisitor(PostChildrenVisitor), ClientData(ClientData), |
165 | VisitPreprocessorLast(VisitPreprocessorLast), |
166 | VisitIncludedEntities(VisitIncludedPreprocessingEntries), |
167 | RegionOfInterest(RegionOfInterest), VisitDeclsOnly(VisitDeclsOnly), |
168 | DI_current(nullptr), FileDI_current(nullptr) { |
169 | Parent.kind = CXCursor_NoDeclFound; |
170 | Parent.data[0] = nullptr; |
171 | Parent.data[1] = nullptr; |
172 | Parent.data[2] = nullptr; |
173 | StmtParent = nullptr; |
174 | } |
175 | |
176 | ~CursorVisitor() { |
177 | // Free the pre-allocated worklists for data-recursion. |
178 | for (SmallVectorImpl<VisitorWorkList *>::iterator I = WorkListCache.begin(), |
179 | E = WorkListCache.end(); |
180 | I != E; ++I) { |
181 | delete *I; |
182 | } |
183 | } |
184 | |
185 | ASTUnit *getASTUnit() const { return AU; } |
186 | CXTranslationUnit getTU() const { return TU; } |
187 | |
188 | bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); |
189 | |
190 | /// Visit declarations and preprocessed entities for the file region |
191 | /// designated by \see RegionOfInterest. |
192 | bool visitFileRegion(); |
193 | |
194 | bool visitPreprocessedEntitiesInRegion(); |
195 | |
196 | bool shouldVisitIncludedEntities() const { return VisitIncludedEntities; } |
197 | |
198 | template <typename InputIterator> |
199 | bool visitPreprocessedEntities(InputIterator First, InputIterator Last, |
200 | PreprocessingRecord &PPRec, |
201 | FileID FID = FileID()); |
202 | |
203 | bool VisitChildren(CXCursor Parent); |
204 | |
205 | // Declaration visitors |
206 | bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); |
207 | bool VisitTypeAliasDecl(TypeAliasDecl *D); |
208 | bool VisitAttributes(Decl *D); |
209 | bool VisitBlockDecl(BlockDecl *B); |
210 | bool VisitCXXRecordDecl(CXXRecordDecl *D); |
211 | std::optional<bool> shouldVisitCursor(CXCursor C); |
212 | bool VisitDeclContext(DeclContext *DC); |
213 | bool VisitTranslationUnitDecl(TranslationUnitDecl *D); |
214 | bool VisitTypedefDecl(TypedefDecl *D); |
215 | bool VisitTagDecl(TagDecl *D); |
216 | bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); |
217 | bool VisitClassTemplatePartialSpecializationDecl( |
218 | ClassTemplatePartialSpecializationDecl *D); |
219 | bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); |
220 | bool VisitEnumConstantDecl(EnumConstantDecl *D); |
221 | bool VisitDeclaratorDecl(DeclaratorDecl *DD); |
222 | bool VisitFunctionDecl(FunctionDecl *ND); |
223 | bool VisitFieldDecl(FieldDecl *D); |
224 | bool VisitVarDecl(VarDecl *); |
225 | bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); |
226 | bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); |
227 | bool VisitClassTemplateDecl(ClassTemplateDecl *D); |
228 | bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); |
229 | bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); |
230 | bool VisitObjCMethodDecl(ObjCMethodDecl *ND); |
231 | bool VisitObjCContainerDecl(ObjCContainerDecl *D); |
232 | bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); |
233 | bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); |
234 | bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); |
235 | bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList); |
236 | bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); |
237 | bool VisitObjCImplDecl(ObjCImplDecl *D); |
238 | bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); |
239 | bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); |
240 | // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. |
241 | bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD); |
242 | bool VisitLinkageSpecDecl(LinkageSpecDecl *D); |
243 | bool VisitNamespaceDecl(NamespaceDecl *D); |
244 | bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); |
245 | bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); |
246 | bool VisitUsingDecl(UsingDecl *D); |
247 | bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); |
248 | bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); |
249 | bool VisitStaticAssertDecl(StaticAssertDecl *D); |
250 | bool VisitFriendDecl(FriendDecl *D); |
251 | bool VisitDecompositionDecl(DecompositionDecl *D); |
252 | bool VisitConceptDecl(ConceptDecl *D); |
253 | bool VisitTypeConstraint(const TypeConstraint &TC); |
254 | bool VisitConceptRequirement(const concepts::Requirement &R); |
255 | |
256 | // Name visitor |
257 | bool VisitDeclarationNameInfo(DeclarationNameInfo Name); |
258 | bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); |
259 | bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); |
260 | |
261 | // Template visitors |
262 | bool VisitTemplateParameters(const TemplateParameterList *Params); |
263 | bool VisitTemplateName(TemplateName Name, SourceLocation Loc); |
264 | bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); |
265 | |
266 | // Type visitors |
267 | #define ABSTRACT_TYPELOC(CLASS, PARENT) |
268 | #define TYPELOC(CLASS, PARENT) bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); |
269 | #include "clang/AST/TypeLocNodes.def" |
270 | |
271 | bool VisitTagTypeLoc(TagTypeLoc TL); |
272 | bool VisitArrayTypeLoc(ArrayTypeLoc TL); |
273 | bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); |
274 | |
275 | // Data-recursive visitor functions. |
276 | bool IsInRegionOfInterest(CXCursor C); |
277 | bool RunVisitorWorkList(VisitorWorkList &WL); |
278 | void EnqueueWorkList(VisitorWorkList &WL, const Stmt *S); |
279 | void EnqueueWorkList(VisitorWorkList &WL, const Attr *A); |
280 | LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S); |
281 | LLVM_ATTRIBUTE_NOINLINE bool Visit(const Attr *A); |
282 | |
283 | private: |
284 | std::optional<bool> handleDeclForVisitation(const Decl *D); |
285 | }; |
286 | |
287 | } // namespace cxcursor |
288 | } // namespace clang |
289 | |
290 | #endif |
291 | |