blob: 04699ccb01a5850d7def55472b0f155457dd5772 [file] [log] [blame]
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00001//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00006//
7//===----------------------------------------------------------------------===//
8
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +00009#include "CursorVisitor.h"
Chandler Carruth4b417452013-01-19 08:09:44 +000010#include "CLog.h"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000011#include "CXCursor.h"
12#include "CXSourceLocation.h"
13#include "CXTranslationUnit.h"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000014#include "clang/AST/DeclObjC.h"
Chandler Carruthcc0694c2012-12-04 09:25:21 +000015#include "clang/Frontend/ASTUnit.h"
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +000016#include "llvm/Support/Compiler.h"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000017
18using namespace clang;
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +000019using namespace cxcursor;
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +000020using namespace cxindex;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000021
22static void getTopOverriddenMethods(CXTranslationUnit TU,
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000023 const Decl *D,
24 SmallVectorImpl<const Decl *> &Methods) {
Argyrios Kyrtzidis173e9112011-12-10 02:36:25 +000025 if (!D)
26 return;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000027 if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
28 return;
29
30 SmallVector<CXCursor, 8> Overridden;
31 cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden);
32
33 if (Overridden.empty()) {
34 Methods.push_back(D->getCanonicalDecl());
35 return;
36 }
37
Craig Topper2341c0d2013-07-04 03:08:24 +000038 for (SmallVectorImpl<CXCursor>::iterator
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000039 I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
40 getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
41}
42
43namespace {
44
45struct FindFileIdRefVisitData {
46 CXTranslationUnit TU;
47 FileID FID;
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000048 const Decl *Dcl;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000049 int SelectorIdIdx;
50 CXCursorAndRangeVisitor visitor;
51
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000052 typedef SmallVector<const Decl *, 8> TopMethodsTy;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000053 TopMethodsTy TopMethods;
54
55 FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000056 const Decl *D, int selectorIdIdx,
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000057 CXCursorAndRangeVisitor visitor)
58 : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
59 Dcl = getCanonical(D);
60 getTopOverriddenMethods(TU, Dcl, TopMethods);
61 }
62
63 ASTContext &getASTContext() const {
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +000064 return cxtu::getASTUnit(TU)->getASTContext();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000065 }
66
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000067 /// We are looking to find all semantically relevant identifiers,
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000068 /// 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.
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000078 const Decl *getCanonical(const Decl *D) const {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000079 if (!D)
Craig Topper69186e72014-06-08 08:38:04 +000080 return nullptr;
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000081
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000082 D = D->getCanonicalDecl();
83
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000084 if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000085 if (ImplD->getClassInterface())
86 return getCanonical(ImplD->getClassInterface());
87
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000088 } else if (const CXXConstructorDecl *CXXCtorD =
89 dyn_cast<CXXConstructorDecl>(D)) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000090 return getCanonical(CXXCtorD->getParent());
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000091 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000092
93 return D;
94 }
95
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000096 bool isHit(const Decl *D) const {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000097 if (!D)
98 return false;
99
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000100 D = getCanonical(D);
101 if (D == Dcl)
102 return true;
103
104 if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
105 return isOverriddingMethod(D);
106
107 return false;
108 }
109
110private:
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000111 bool isOverriddingMethod(const Decl *D) const {
Fangrui Song75e74e02019-03-31 08:48:19 +0000112 if (llvm::find(TopMethods, D) != TopMethods.end())
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000113 return true;
114
115 TopMethodsTy methods;
116 getTopOverriddenMethods(TU, D, methods);
117 for (TopMethodsTy::iterator
118 I = methods.begin(), E = methods.end(); I != E; ++I) {
Fangrui Song75e74e02019-03-31 08:48:19 +0000119 if (llvm::find(TopMethods, *I) != TopMethods.end())
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000120 return true;
121 }
122
123 return false;
124 }
125};
126
127} // end anonymous namespace.
128
Adrian Prantl9fc8faf2018-05-09 01:00:01 +0000129/// For a macro \arg Loc, returns the file spelling location and sets
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000130/// to \arg isMacroArg whether the spelling resides inside a macro definition or
131/// a macro argument.
132static SourceLocation getFileSpellingLoc(SourceManager &SM,
133 SourceLocation Loc,
134 bool &isMacroArg) {
135 assert(Loc.isMacroID());
136 SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
137 if (SpellLoc.isMacroID())
138 return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
139
140 isMacroArg = SM.isMacroArgExpansion(Loc);
141 return SpellLoc;
142}
143
144static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
145 CXCursor parent,
146 CXClientData client_data) {
147 CXCursor declCursor = clang_getCursorReferenced(cursor);
148 if (!clang_isDeclaration(declCursor.kind))
149 return CXChildVisit_Recurse;
150
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000151 const Decl *D = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis173e9112011-12-10 02:36:25 +0000152 if (!D)
153 return CXChildVisit_Continue;
154
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000155 FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
156 if (data->isHit(D)) {
157 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 if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
162 cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
163 cxcursor::getSelectorIdentifierIndex(cursor) == -1)
164 return CXChildVisit_Recurse;
165
166 if (clang_isExpression(cursor.kind)) {
167 if (cursor.kind == CXCursor_DeclRefExpr ||
168 cursor.kind == CXCursor_MemberRefExpr) {
169 // continue..
170
171 } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
172 cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
173 // continue..
174
175 } else
176 return CXChildVisit_Recurse;
177 }
178
179 SourceLocation
180 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
181 SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
182 if (SelIdLoc.isValid())
183 Loc = SelIdLoc;
184
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000185 ASTContext &Ctx = data->getASTContext();
186 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000187 bool isInMacroDef = false;
188 if (Loc.isMacroID()) {
189 bool isMacroArg;
190 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
191 isInMacroDef = !isMacroArg;
192 }
193
194 // We are looking for identifiers in a specific file.
195 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
196 if (LocInfo.first != data->FID)
197 return CXChildVisit_Recurse;
198
199 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.
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000202 return CXChildVisit_Recurse;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000203 }
204
Argyrios Kyrtzidis73313692013-03-08 02:32:29 +0000205 if (data->visitor.visit(data->visitor.context, cursor,
206 cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
207 return CXChildVisit_Break;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000208 }
209 return CXChildVisit_Recurse;
210}
211
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000212static bool findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
213 const FileEntry *File,
214 CXCursorAndRangeVisitor Visitor) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000215 assert(clang_isDeclaration(declCursor.kind));
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000216 SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000217
218 FileID FID = SM.translateFile(File);
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000219 const Decl *Dcl = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +0000220 if (!Dcl)
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000221 return false;
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +0000222
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000223 FindFileIdRefVisitData data(TU, FID, Dcl,
224 cxcursor::getSelectorIdentifierIndex(declCursor),
225 Visitor);
226
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000227 if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000228 return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
229 findFileIdRefVisit, &data);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000230 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000231
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000232 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
233 CursorVisitor FindIdRefsVisitor(TU,
234 findFileIdRefVisit, &data,
235 /*VisitPreprocessorLast=*/true,
236 /*VisitIncludedEntities=*/false,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000237 Range,
238 /*VisitDeclsOnly=*/true);
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000239 return FindIdRefsVisitor.visitFileRegion();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000240}
241
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000242namespace {
243
244struct 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 : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
254
255 ASTContext &getASTContext() const {
256 return Unit.getASTContext();
257 }
258};
259
260} // anonymous namespace
261
262static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
263 CXCursor parent,
264 CXClientData client_data) {
Craig Topper69186e72014-06-08 08:38:04 +0000265 const IdentifierInfo *Macro = nullptr;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000266 if (cursor.kind == CXCursor_MacroDefinition)
267 Macro = getCursorMacroDefinition(cursor)->getName();
268 else if (cursor.kind == CXCursor_MacroExpansion)
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000269 Macro = getCursorMacroExpansion(cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000270 if (!Macro)
271 return CXChildVisit_Continue;
272
273 FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
274 if (data->Macro != Macro)
275 return CXChildVisit_Continue;
276
277 SourceLocation
278 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
279
280 ASTContext &Ctx = data->getASTContext();
281 SourceManager &SM = Ctx.getSourceManager();
282 bool isInMacroDef = false;
283 if (Loc.isMacroID()) {
284 bool isMacroArg;
285 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
286 isInMacroDef = !isMacroArg;
287 }
288
289 // We are looking for identifiers in a specific file.
290 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
291 if (SM.getFileEntryForID(LocInfo.first) != data->File)
292 return CXChildVisit_Continue;
293
294 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 return CXChildVisit_Continue;
298 }
299
Argyrios Kyrtzidis73313692013-03-08 02:32:29 +0000300 if (data->visitor.visit(data->visitor.context, cursor,
301 cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
302 return CXChildVisit_Break;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000303 return CXChildVisit_Continue;
304}
305
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000306static bool findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000307 const FileEntry *File,
308 CXCursorAndRangeVisitor Visitor) {
309 if (Cursor.kind != CXCursor_MacroDefinition &&
310 Cursor.kind != CXCursor_MacroExpansion)
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000311 return false;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000312
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000313 ASTUnit *Unit = cxtu::getASTUnit(TU);
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000314 SourceManager &SM = Unit->getSourceManager();
315
316 FileID FID = SM.translateFile(File);
Craig Topper69186e72014-06-08 08:38:04 +0000317 const IdentifierInfo *Macro = nullptr;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000318 if (Cursor.kind == CXCursor_MacroDefinition)
319 Macro = getCursorMacroDefinition(Cursor)->getName();
320 else
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000321 Macro = getCursorMacroExpansion(Cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000322 if (!Macro)
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000323 return false;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000324
325 FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
326
327 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
328 CursorVisitor FindMacroRefsVisitor(TU,
329 findFileMacroRefVisit, &data,
330 /*VisitPreprocessorLast=*/false,
331 /*VisitIncludedEntities=*/false,
332 Range);
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000333 return FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000334}
335
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000336namespace {
337
338struct FindFileIncludesVisitor {
339 ASTUnit &Unit;
340 const FileEntry *File;
341 CXCursorAndRangeVisitor visitor;
342
343 FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File,
344 CXCursorAndRangeVisitor visitor)
345 : Unit(Unit), File(File), visitor(visitor) { }
346
347 ASTContext &getASTContext() const {
348 return Unit.getASTContext();
349 }
350
351 enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) {
352 if (cursor.kind != CXCursor_InclusionDirective)
353 return CXChildVisit_Continue;
354
355 SourceLocation
356 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
357
358 ASTContext &Ctx = getASTContext();
359 SourceManager &SM = Ctx.getSourceManager();
360
361 // We are looking for includes in a specific file.
362 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
363 if (SM.getFileEntryForID(LocInfo.first) != File)
364 return CXChildVisit_Continue;
365
366 if (visitor.visit(visitor.context, cursor,
367 cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
368 return CXChildVisit_Break;
369 return CXChildVisit_Continue;
370 }
371
372 static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent,
373 CXClientData client_data) {
374 return static_cast<FindFileIncludesVisitor*>(client_data)->
375 visit(cursor, parent);
376 }
377};
378
379} // anonymous namespace
380
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000381static bool findIncludesInFile(CXTranslationUnit TU, const FileEntry *File,
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000382 CXCursorAndRangeVisitor Visitor) {
383 assert(TU && File && Visitor.visit);
384
385 ASTUnit *Unit = cxtu::getASTUnit(TU);
386 SourceManager &SM = Unit->getSourceManager();
387
388 FileID FID = SM.translateFile(File);
389
390 FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor);
391
392 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
393 CursorVisitor InclusionCursorsVisitor(TU,
394 FindFileIncludesVisitor::visit,
395 &IncludesVisitor,
396 /*VisitPreprocessorLast=*/false,
397 /*VisitIncludedEntities=*/false,
398 Range);
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000399 return InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion();
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000400}
401
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000402
403//===----------------------------------------------------------------------===//
404// libclang public APIs.
405//===----------------------------------------------------------------------===//
406
NAKAMURA Takumia01f4c32016-12-19 16:50:43 +0000407extern "C" {
408
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000409CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
410 CXCursorAndRangeVisitor visitor) {
Erik Pilkington53937db2016-10-20 02:46:22 +0000411 LogRef Log = Logger::make(__func__);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000412
413 if (clang_Cursor_isNull(cursor)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000414 if (Log)
415 *Log << "Null cursor";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000416 return CXResult_Invalid;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000417 }
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000418 if (cursor.kind == CXCursor_NoDeclFound) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000419 if (Log)
420 *Log << "Got CXCursor_NoDeclFound";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000421 return CXResult_Invalid;
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000422 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000423 if (!file) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000424 if (Log)
425 *Log << "Null file";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000426 return CXResult_Invalid;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000427 }
428 if (!visitor.visit) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000429 if (Log)
430 *Log << "Null visitor";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000431 return CXResult_Invalid;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000432 }
433
Argyrios Kyrtzidisba4b5f82013-03-08 02:32:26 +0000434 if (Log)
435 *Log << cursor << " @" << static_cast<const FileEntry *>(file);
436
Argyrios Kyrtzidisebbb2062011-11-29 23:21:50 +0000437 ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
438 if (!CXXUnit)
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000439 return CXResult_Invalid;
Argyrios Kyrtzidisebbb2062011-11-29 23:21:50 +0000440
441 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
442
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000443 if (cursor.kind == CXCursor_MacroDefinition ||
444 cursor.kind == CXCursor_MacroExpansion) {
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000445 if (findMacroRefsInFile(cxcursor::getCursorTU(cursor),
446 cursor,
447 static_cast<const FileEntry *>(file),
448 visitor))
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000449 return CXResult_VisitBreak;
450 return CXResult_Success;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000451 }
452
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000453 // 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 cursor = cxcursor::getTypeRefCursor(cursor);
461
462 CXCursor refCursor = clang_getCursorReferenced(cursor);
463
464 if (!clang_isDeclaration(refCursor.kind)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000465 if (Log)
466 *Log << "cursor is not referencing a declaration";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000467 return CXResult_Invalid;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000468 }
469
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000470 if (findIdRefsInFile(cxcursor::getCursorTU(cursor),
471 refCursor,
472 static_cast<const FileEntry *>(file),
473 visitor))
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000474 return CXResult_VisitBreak;
475 return CXResult_Success;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000476}
477
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000478CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file,
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000479 CXCursorAndRangeVisitor visitor) {
Dmitri Gribenko852d6222014-02-11 15:02:48 +0000480 if (cxtu::isNotUsableTU(TU)) {
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000481 LOG_BAD_TU(TU);
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000482 return CXResult_Invalid;
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000483 }
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000484
Erik Pilkington53937db2016-10-20 02:46:22 +0000485 LogRef Log = Logger::make(__func__);
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000486 if (!file) {
487 if (Log)
488 *Log << "Null file";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000489 return CXResult_Invalid;
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000490 }
491 if (!visitor.visit) {
492 if (Log)
493 *Log << "Null visitor";
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000494 return CXResult_Invalid;
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000495 }
496
497 if (Log)
498 *Log << TU << " @" << static_cast<const FileEntry *>(file);
499
500 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
501 if (!CXXUnit)
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000502 return CXResult_Invalid;
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000503
504 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
505
Argyrios Kyrtzidis951f61f2013-03-08 20:42:33 +0000506 if (findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor))
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000507 return CXResult_VisitBreak;
508 return CXResult_Success;
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000509}
510
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000511static enum CXVisitorResult _visitCursorAndRange(void *context,
512 CXCursor cursor,
513 CXSourceRange range) {
514 CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
515 return INVOKE_BLOCK2(block, cursor, range);
516}
517
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000518CXResult clang_findReferencesInFileWithBlock(CXCursor cursor,
519 CXFile file,
520 CXCursorAndRangeVisitorBlock block) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000521 CXCursorAndRangeVisitor visitor = { block,
Craig Topper69186e72014-06-08 08:38:04 +0000522 block ? _visitCursorAndRange : nullptr };
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000523 return clang_findReferencesInFile(cursor, file, visitor);
524}
525
Argyrios Kyrtzidis51c33182013-03-08 22:47:41 +0000526CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU,
527 CXFile file,
528 CXCursorAndRangeVisitorBlock block) {
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000529 CXCursorAndRangeVisitor visitor = { block,
Craig Topper69186e72014-06-08 08:38:04 +0000530 block ? _visitCursorAndRange : nullptr };
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +0000531 return clang_findIncludesInFile(TU, file, visitor);
532}
533
NAKAMURA Takumia01f4c32016-12-19 16:50:43 +0000534} // end: extern "C"