/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/libclang/CIndexHigh.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- CIndexHigh.cpp - Higher level API functions ------------------------===// |
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 | | #include "CursorVisitor.h" |
10 | | #include "CLog.h" |
11 | | #include "CXCursor.h" |
12 | | #include "CXSourceLocation.h" |
13 | | #include "CXTranslationUnit.h" |
14 | | #include "clang/AST/DeclObjC.h" |
15 | | #include "clang/Frontend/ASTUnit.h" |
16 | | #include "llvm/Support/Compiler.h" |
17 | | |
18 | | using namespace clang; |
19 | | using namespace cxcursor; |
20 | | using namespace cxindex; |
21 | | |
22 | | static void getTopOverriddenMethods(CXTranslationUnit TU, |
23 | | const Decl *D, |
24 | 146 | SmallVectorImpl<const Decl *> &Methods) { |
25 | 146 | if (!D) |
26 | 0 | return; |
27 | 146 | if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D)87 ) |
28 | 27 | return; |
29 | | |
30 | 119 | SmallVector<CXCursor, 8> Overridden; |
31 | 119 | cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden); |
32 | | |
33 | 119 | if (Overridden.empty()) { |
34 | 103 | Methods.push_back(D->getCanonicalDecl()); |
35 | 103 | return; |
36 | 103 | } |
37 | | |
38 | 16 | for (SmallVectorImpl<CXCursor>::iterator |
39 | 32 | I = Overridden.begin(), E = Overridden.end(); I != E; ++I16 ) |
40 | 16 | getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods); |
41 | 16 | } |
42 | | |
43 | | namespace { |
44 | | |
45 | | struct FindFileIdRefVisitData { |
46 | | CXTranslationUnit TU; |
47 | | FileID FID; |
48 | | const Decl *Dcl; |
49 | | int SelectorIdIdx; |
50 | | CXCursorAndRangeVisitor visitor; |
51 | | |
52 | | typedef SmallVector<const Decl *, 8> TopMethodsTy; |
53 | | TopMethodsTy TopMethods; |
54 | | |
55 | | FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID, |
56 | | const Decl *D, int selectorIdIdx, |
57 | | CXCursorAndRangeVisitor visitor) |
58 | 31 | : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) { |
59 | 31 | Dcl = getCanonical(D); |
60 | 31 | getTopOverriddenMethods(TU, Dcl, TopMethods); |
61 | 31 | } |
62 | | |
63 | 96 | ASTContext &getASTContext() const { |
64 | 96 | return cxtu::getASTUnit(TU)->getASTContext(); |
65 | 96 | } |
66 | | |
67 | | /// We are looking to find all semantically relevant identifiers, |
68 | | /// so the definition of "canonical" here is different than in the AST, e.g. |
69 | | /// |
70 | | /// \code |
71 | | /// class C { |
72 | | /// C() {} |
73 | | /// }; |
74 | | /// \endcode |
75 | | /// |
76 | | /// we consider the canonical decl of the constructor decl to be the class |
77 | | /// itself, so both 'C' can be highlighted. |
78 | 1.06k | const Decl *getCanonical(const Decl *D) const { |
79 | 1.06k | if (!D) |
80 | 0 | return nullptr; |
81 | | |
82 | 1.06k | D = D->getCanonicalDecl(); |
83 | | |
84 | 1.06k | if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) { |
85 | 13 | if (ImplD->getClassInterface()) |
86 | 13 | return getCanonical(ImplD->getClassInterface()); |
87 | | |
88 | 1.05k | } else if (const CXXConstructorDecl *CXXCtorD = |
89 | 1.05k | dyn_cast<CXXConstructorDecl>(D)) { |
90 | 48 | return getCanonical(CXXCtorD->getParent()); |
91 | 48 | } |
92 | | |
93 | 1.00k | return D; |
94 | 1.06k | } |
95 | | |
96 | 977 | bool isHit(const Decl *D) const { |
97 | 977 | if (!D) |
98 | 0 | return false; |
99 | | |
100 | 977 | D = getCanonical(D); |
101 | 977 | if (D == Dcl) |
102 | 115 | return true; |
103 | | |
104 | 862 | if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D)821 ) |
105 | 101 | return isOverriddingMethod(D); |
106 | | |
107 | 761 | return false; |
108 | 862 | } |
109 | | |
110 | | private: |
111 | 101 | bool isOverriddingMethod(const Decl *D) const { |
112 | 101 | if (llvm::is_contained(TopMethods, D)) |
113 | 2 | return true; |
114 | | |
115 | 99 | TopMethodsTy methods; |
116 | 99 | getTopOverriddenMethods(TU, D, methods); |
117 | 99 | for (TopMethodsTy::iterator |
118 | 195 | I = methods.begin(), E = methods.end(); I != E; ++I96 ) { |
119 | 99 | if (llvm::is_contained(TopMethods, *I)) |
120 | 3 | return true; |
121 | 99 | } |
122 | | |
123 | 96 | return false; |
124 | 99 | } |
125 | | }; |
126 | | |
127 | | } // end anonymous namespace. |
128 | | |
129 | | /// For a macro \arg Loc, returns the file spelling location and sets |
130 | | /// to \arg isMacroArg whether the spelling resides inside a macro definition or |
131 | | /// a macro argument. |
132 | | static SourceLocation getFileSpellingLoc(SourceManager &SM, |
133 | | SourceLocation Loc, |
134 | 0 | bool &isMacroArg) { |
135 | 0 | assert(Loc.isMacroID()); |
136 | 0 | SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc); |
137 | 0 | if (SpellLoc.isMacroID()) |
138 | 0 | return getFileSpellingLoc(SM, SpellLoc, isMacroArg); |
139 | | |
140 | 0 | isMacroArg = SM.isMacroArgExpansion(Loc); |
141 | 0 | return SpellLoc; |
142 | 0 | } |
143 | | |
144 | | static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor, |
145 | | CXCursor parent, |
146 | 1.28k | CXClientData client_data) { |
147 | 1.28k | CXCursor declCursor = clang_getCursorReferenced(cursor); |
148 | 1.28k | if (!clang_isDeclaration(declCursor.kind)) |
149 | 310 | return CXChildVisit_Recurse; |
150 | | |
151 | 977 | const Decl *D = cxcursor::getCursorDecl(declCursor); |
152 | 977 | if (!D) |
153 | 0 | return CXChildVisit_Continue; |
154 | | |
155 | 977 | FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data; |
156 | 977 | if (data->isHit(D)) { |
157 | 120 | cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor); |
158 | | |
159 | | // We are looking for identifiers to highlight so for objc methods (and |
160 | | // not a parameter) we can only highlight the selector identifiers. |
161 | 120 | if ((cursor.kind == CXCursor_ObjCClassMethodDecl || |
162 | 120 | cursor.kind == CXCursor_ObjCInstanceMethodDecl) && |
163 | 120 | cxcursor::getSelectorIdentifierIndex(cursor) == -110 ) |
164 | 0 | return CXChildVisit_Recurse; |
165 | | |
166 | 120 | if (clang_isExpression(cursor.kind)) { |
167 | 49 | if (cursor.kind == CXCursor_DeclRefExpr || |
168 | 49 | cursor.kind == CXCursor_MemberRefExpr35 ) { |
169 | | // continue.. |
170 | | |
171 | 32 | } else if (cursor.kind == CXCursor_ObjCMessageExpr && |
172 | 32 | cxcursor::getSelectorIdentifierIndex(cursor) != -18 ) { |
173 | | // continue.. |
174 | | |
175 | 8 | } else |
176 | 24 | return CXChildVisit_Recurse; |
177 | 49 | } |
178 | | |
179 | 96 | SourceLocation |
180 | 96 | Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); |
181 | 96 | SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor); |
182 | 96 | if (SelIdLoc.isValid()) |
183 | 18 | Loc = SelIdLoc; |
184 | | |
185 | 96 | ASTContext &Ctx = data->getASTContext(); |
186 | 96 | SourceManager &SM = Ctx.getSourceManager(); |
187 | 96 | bool isInMacroDef = false; |
188 | 96 | if (Loc.isMacroID()) { |
189 | 0 | bool isMacroArg; |
190 | 0 | Loc = getFileSpellingLoc(SM, Loc, isMacroArg); |
191 | 0 | isInMacroDef = !isMacroArg; |
192 | 0 | } |
193 | | |
194 | | // We are looking for identifiers in a specific file. |
195 | 96 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); |
196 | 96 | if (LocInfo.first != data->FID) |
197 | 0 | return CXChildVisit_Recurse; |
198 | | |
199 | 96 | if (isInMacroDef) { |
200 | | // FIXME: For a macro definition make sure that all expansions |
201 | | // of it expand to the same reference before allowing to point to it. |
202 | 0 | return CXChildVisit_Recurse; |
203 | 0 | } |
204 | | |
205 | 96 | if (data->visitor.visit(data->visitor.context, cursor, |
206 | 96 | cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) |
207 | 0 | return CXChildVisit_Break; |
208 | 96 | } |
209 | 953 | return CXChildVisit_Recurse; |
210 | 977 | } |
211 | | |
212 | | static bool findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor, |
213 | | const FileEntry *File, |
214 | 31 | CXCursorAndRangeVisitor Visitor) { |
215 | 31 | assert(clang_isDeclaration(declCursor.kind)); |
216 | 0 | SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); |
217 | | |
218 | 31 | FileID FID = SM.translateFile(File); |
219 | 31 | const Decl *Dcl = cxcursor::getCursorDecl(declCursor); |
220 | 31 | if (!Dcl) |
221 | 0 | return false; |
222 | | |
223 | 31 | FindFileIdRefVisitData data(TU, FID, Dcl, |
224 | 31 | cxcursor::getSelectorIdentifierIndex(declCursor), |
225 | 31 | Visitor); |
226 | | |
227 | 31 | if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) { |
228 | 7 | return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU), |
229 | 7 | findFileIdRefVisit, &data); |
230 | 7 | } |
231 | | |
232 | 24 | SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); |
233 | 24 | CursorVisitor FindIdRefsVisitor(TU, |
234 | 24 | findFileIdRefVisit, &data, |
235 | 24 | /*VisitPreprocessorLast=*/true, |
236 | 24 | /*VisitIncludedEntities=*/false, |
237 | 24 | Range, |
238 | 24 | /*VisitDeclsOnly=*/true); |
239 | 24 | return FindIdRefsVisitor.visitFileRegion(); |
240 | 31 | } |
241 | | |
242 | | namespace { |
243 | | |
244 | | struct FindFileMacroRefVisitData { |
245 | | ASTUnit &Unit; |
246 | | const FileEntry *File; |
247 | | const IdentifierInfo *Macro; |
248 | | CXCursorAndRangeVisitor visitor; |
249 | | |
250 | | FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File, |
251 | | const IdentifierInfo *Macro, |
252 | | CXCursorAndRangeVisitor visitor) |
253 | 2 | : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { } |
254 | | |
255 | 6 | ASTContext &getASTContext() const { |
256 | 6 | return Unit.getASTContext(); |
257 | 6 | } |
258 | | }; |
259 | | |
260 | | } // anonymous namespace |
261 | | |
262 | | static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor, |
263 | | CXCursor parent, |
264 | 6 | CXClientData client_data) { |
265 | 6 | const IdentifierInfo *Macro = nullptr; |
266 | 6 | if (cursor.kind == CXCursor_MacroDefinition) |
267 | 2 | Macro = getCursorMacroDefinition(cursor)->getName(); |
268 | 4 | else if (cursor.kind == CXCursor_MacroExpansion) |
269 | 4 | Macro = getCursorMacroExpansion(cursor).getName(); |
270 | 6 | if (!Macro) |
271 | 0 | return CXChildVisit_Continue; |
272 | | |
273 | 6 | FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data; |
274 | 6 | if (data->Macro != Macro) |
275 | 0 | return CXChildVisit_Continue; |
276 | | |
277 | 6 | SourceLocation |
278 | 6 | Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); |
279 | | |
280 | 6 | ASTContext &Ctx = data->getASTContext(); |
281 | 6 | SourceManager &SM = Ctx.getSourceManager(); |
282 | 6 | bool isInMacroDef = false; |
283 | 6 | if (Loc.isMacroID()) { |
284 | 0 | bool isMacroArg; |
285 | 0 | Loc = getFileSpellingLoc(SM, Loc, isMacroArg); |
286 | 0 | isInMacroDef = !isMacroArg; |
287 | 0 | } |
288 | | |
289 | | // We are looking for identifiers in a specific file. |
290 | 6 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); |
291 | 6 | if (SM.getFileEntryForID(LocInfo.first) != data->File) |
292 | 0 | return CXChildVisit_Continue; |
293 | | |
294 | 6 | if (isInMacroDef) { |
295 | | // FIXME: For a macro definition make sure that all expansions |
296 | | // of it expand to the same reference before allowing to point to it. |
297 | 0 | return CXChildVisit_Continue; |
298 | 0 | } |
299 | | |
300 | 6 | if (data->visitor.visit(data->visitor.context, cursor, |
301 | 6 | cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) |
302 | 0 | return CXChildVisit_Break; |
303 | 6 | return CXChildVisit_Continue; |
304 | 6 | } |
305 | | |
306 | | static bool findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor, |
307 | | const FileEntry *File, |
308 | 2 | CXCursorAndRangeVisitor Visitor) { |
309 | 2 | if (Cursor.kind != CXCursor_MacroDefinition && |
310 | 2 | Cursor.kind != CXCursor_MacroExpansion) |
311 | 0 | return false; |
312 | | |
313 | 2 | ASTUnit *Unit = cxtu::getASTUnit(TU); |
314 | 2 | SourceManager &SM = Unit->getSourceManager(); |
315 | | |
316 | 2 | FileID FID = SM.translateFile(File); |
317 | 2 | const IdentifierInfo *Macro = nullptr; |
318 | 2 | if (Cursor.kind == CXCursor_MacroDefinition) |
319 | 0 | Macro = getCursorMacroDefinition(Cursor)->getName(); |
320 | 2 | else |
321 | 2 | Macro = getCursorMacroExpansion(Cursor).getName(); |
322 | 2 | if (!Macro) |
323 | 0 | return false; |
324 | | |
325 | 2 | FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor); |
326 | | |
327 | 2 | SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); |
328 | 2 | CursorVisitor FindMacroRefsVisitor(TU, |
329 | 2 | findFileMacroRefVisit, &data, |
330 | 2 | /*VisitPreprocessorLast=*/false, |
331 | 2 | /*VisitIncludedEntities=*/false, |
332 | 2 | Range); |
333 | 2 | return FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion(); |
334 | 2 | } |
335 | | |
336 | | namespace { |
337 | | |
338 | | struct FindFileIncludesVisitor { |
339 | | ASTUnit &Unit; |
340 | | const FileEntry *File; |
341 | | CXCursorAndRangeVisitor visitor; |
342 | | |
343 | | FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File, |
344 | | CXCursorAndRangeVisitor visitor) |
345 | 9 | : Unit(Unit), File(File), visitor(visitor) { } |
346 | | |
347 | 16 | ASTContext &getASTContext() const { |
348 | 16 | return Unit.getASTContext(); |
349 | 16 | } |
350 | | |
351 | 20 | enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { |
352 | 20 | if (cursor.kind != CXCursor_InclusionDirective) |
353 | 4 | return CXChildVisit_Continue; |
354 | | |
355 | 16 | SourceLocation |
356 | 16 | Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); |
357 | | |
358 | 16 | ASTContext &Ctx = getASTContext(); |
359 | 16 | SourceManager &SM = Ctx.getSourceManager(); |
360 | | |
361 | | // We are looking for includes in a specific file. |
362 | 16 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); |
363 | 16 | if (SM.getFileEntryForID(LocInfo.first) != File) |
364 | 0 | return CXChildVisit_Continue; |
365 | | |
366 | 16 | if (visitor.visit(visitor.context, cursor, |
367 | 16 | cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) |
368 | 0 | return CXChildVisit_Break; |
369 | 16 | return CXChildVisit_Continue; |
370 | 16 | } |
371 | | |
372 | | static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent, |
373 | 20 | CXClientData client_data) { |
374 | 20 | return static_cast<FindFileIncludesVisitor*>(client_data)-> |
375 | 20 | visit(cursor, parent); |
376 | 20 | } |
377 | | }; |
378 | | |
379 | | } // anonymous namespace |
380 | | |
381 | | static bool findIncludesInFile(CXTranslationUnit TU, const FileEntry *File, |
382 | 9 | CXCursorAndRangeVisitor Visitor) { |
383 | 9 | assert(TU && File && Visitor.visit); |
384 | | |
385 | 0 | ASTUnit *Unit = cxtu::getASTUnit(TU); |
386 | 9 | SourceManager &SM = Unit->getSourceManager(); |
387 | | |
388 | 9 | FileID FID = SM.translateFile(File); |
389 | | |
390 | 9 | FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor); |
391 | | |
392 | 9 | SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); |
393 | 9 | CursorVisitor InclusionCursorsVisitor(TU, |
394 | 9 | FindFileIncludesVisitor::visit, |
395 | 9 | &IncludesVisitor, |
396 | 9 | /*VisitPreprocessorLast=*/false, |
397 | 9 | /*VisitIncludedEntities=*/false, |
398 | 9 | Range); |
399 | 9 | return InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion(); |
400 | 9 | } |
401 | | |
402 | | |
403 | | //===----------------------------------------------------------------------===// |
404 | | // libclang public APIs. |
405 | | //===----------------------------------------------------------------------===// |
406 | | |
407 | | extern "C" { |
408 | | |
409 | | CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file, |
410 | 33 | CXCursorAndRangeVisitor visitor) { |
411 | 33 | LogRef Log = Logger::make(__func__); |
412 | | |
413 | 33 | if (clang_Cursor_isNull(cursor)) { |
414 | 0 | if (Log) |
415 | 0 | *Log << "Null cursor"; |
416 | 0 | return CXResult_Invalid; |
417 | 0 | } |
418 | 33 | if (cursor.kind == CXCursor_NoDeclFound) { |
419 | 0 | if (Log) |
420 | 0 | *Log << "Got CXCursor_NoDeclFound"; |
421 | 0 | return CXResult_Invalid; |
422 | 0 | } |
423 | 33 | if (!file) { |
424 | 0 | if (Log) |
425 | 0 | *Log << "Null file"; |
426 | 0 | return CXResult_Invalid; |
427 | 0 | } |
428 | 33 | if (!visitor.visit) { |
429 | 0 | if (Log) |
430 | 0 | *Log << "Null visitor"; |
431 | 0 | return CXResult_Invalid; |
432 | 0 | } |
433 | | |
434 | 33 | if (Log) |
435 | 0 | *Log << cursor << " @" << static_cast<const FileEntry *>(file); |
436 | | |
437 | 33 | ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor); |
438 | 33 | if (!CXXUnit) |
439 | 0 | return CXResult_Invalid; |
440 | | |
441 | 33 | ASTUnit::ConcurrencyCheck Check(*CXXUnit); |
442 | | |
443 | 33 | if (cursor.kind == CXCursor_MacroDefinition || |
444 | 33 | cursor.kind == CXCursor_MacroExpansion) { |
445 | 2 | if (findMacroRefsInFile(cxcursor::getCursorTU(cursor), |
446 | 2 | cursor, |
447 | 2 | static_cast<const FileEntry *>(file), |
448 | 2 | visitor)) |
449 | 0 | return CXResult_VisitBreak; |
450 | 2 | return CXResult_Success; |
451 | 2 | } |
452 | | |
453 | | // We are interested in semantics of identifiers so for C++ constructor exprs |
454 | | // prefer type references, e.g.: |
455 | | // |
456 | | // return MyStruct(); |
457 | | // |
458 | | // for 'MyStruct' we'll have a cursor pointing at the constructor decl but |
459 | | // we are actually interested in the type declaration. |
460 | 31 | cursor = cxcursor::getTypeRefCursor(cursor); |
461 | | |
462 | 31 | CXCursor refCursor = clang_getCursorReferenced(cursor); |
463 | | |
464 | 31 | if (!clang_isDeclaration(refCursor.kind)) { |
465 | 0 | if (Log) |
466 | 0 | *Log << "cursor is not referencing a declaration"; |
467 | 0 | return CXResult_Invalid; |
468 | 0 | } |
469 | | |
470 | 31 | if (findIdRefsInFile(cxcursor::getCursorTU(cursor), |
471 | 31 | refCursor, |
472 | 31 | static_cast<const FileEntry *>(file), |
473 | 31 | visitor)) |
474 | 0 | return CXResult_VisitBreak; |
475 | 31 | return CXResult_Success; |
476 | 31 | } |
477 | | |
478 | | CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file, |
479 | 9 | CXCursorAndRangeVisitor visitor) { |
480 | 9 | if (cxtu::isNotUsableTU(TU)) { |
481 | 0 | LOG_BAD_TU(TU); |
482 | 0 | return CXResult_Invalid; |
483 | 0 | } |
484 | | |
485 | 9 | LogRef Log = Logger::make(__func__); |
486 | 9 | if (!file) { |
487 | 0 | if (Log) |
488 | 0 | *Log << "Null file"; |
489 | 0 | return CXResult_Invalid; |
490 | 0 | } |
491 | 9 | if (!visitor.visit) { |
492 | 0 | if (Log) |
493 | 0 | *Log << "Null visitor"; |
494 | 0 | return CXResult_Invalid; |
495 | 0 | } |
496 | | |
497 | 9 | if (Log) |
498 | 0 | *Log << TU << " @" << static_cast<const FileEntry *>(file); |
499 | | |
500 | 9 | ASTUnit *CXXUnit = cxtu::getASTUnit(TU); |
501 | 9 | if (!CXXUnit) |
502 | 0 | return CXResult_Invalid; |
503 | | |
504 | 9 | ASTUnit::ConcurrencyCheck Check(*CXXUnit); |
505 | | |
506 | 9 | if (findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor)) |
507 | 0 | return CXResult_VisitBreak; |
508 | 9 | return CXResult_Success; |
509 | 9 | } |
510 | | |
511 | | static enum CXVisitorResult _visitCursorAndRange(void *context, |
512 | | CXCursor cursor, |
513 | 0 | CXSourceRange range) { |
514 | 0 | CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context; |
515 | 0 | return INVOKE_BLOCK2(block, cursor, range); |
516 | 0 | } |
517 | | |
518 | | CXResult clang_findReferencesInFileWithBlock(CXCursor cursor, |
519 | | CXFile file, |
520 | 0 | CXCursorAndRangeVisitorBlock block) { |
521 | 0 | CXCursorAndRangeVisitor visitor = { block, |
522 | 0 | block ? _visitCursorAndRange : nullptr }; |
523 | 0 | return clang_findReferencesInFile(cursor, file, visitor); |
524 | 0 | } |
525 | | |
526 | | CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU, |
527 | | CXFile file, |
528 | 0 | CXCursorAndRangeVisitorBlock block) { |
529 | 0 | CXCursorAndRangeVisitor visitor = { block, |
530 | 0 | block ? _visitCursorAndRange : nullptr }; |
531 | 0 | return clang_findIncludesInFile(TU, file, visitor); |
532 | 0 | } |
533 | | |
534 | | } // end: extern "C" |