blob: 7e12386841941495dc2c531d2b788a8bbb8818a6 [file] [log] [blame]
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00001//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +000010#include "CursorVisitor.h"
Chandler Carruth4b417452013-01-19 08:09:44 +000011#include "CLog.h"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000012#include "CXCursor.h"
13#include "CXSourceLocation.h"
14#include "CXTranslationUnit.h"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000015#include "clang/AST/DeclObjC.h"
Chandler Carruthcc0694c2012-12-04 09:25:21 +000016#include "clang/Frontend/ASTUnit.h"
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +000017#include "llvm/Support/Compiler.h"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000018
19using namespace clang;
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +000020using namespace cxcursor;
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +000021using namespace cxindex;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000022
23static void getTopOverriddenMethods(CXTranslationUnit TU,
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000024 const Decl *D,
25 SmallVectorImpl<const Decl *> &Methods) {
Argyrios Kyrtzidis173e9112011-12-10 02:36:25 +000026 if (!D)
27 return;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000028 if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
29 return;
30
31 SmallVector<CXCursor, 8> Overridden;
32 cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden);
33
34 if (Overridden.empty()) {
35 Methods.push_back(D->getCanonicalDecl());
36 return;
37 }
38
39 for (SmallVector<CXCursor, 8>::iterator
40 I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
41 getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
42}
43
44namespace {
45
46struct FindFileIdRefVisitData {
47 CXTranslationUnit TU;
48 FileID FID;
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000049 const Decl *Dcl;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000050 int SelectorIdIdx;
51 CXCursorAndRangeVisitor visitor;
52
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000053 typedef SmallVector<const Decl *, 8> TopMethodsTy;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000054 TopMethodsTy TopMethods;
55
56 FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000057 const Decl *D, int selectorIdIdx,
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000058 CXCursorAndRangeVisitor visitor)
59 : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
60 Dcl = getCanonical(D);
61 getTopOverriddenMethods(TU, Dcl, TopMethods);
62 }
63
64 ASTContext &getASTContext() const {
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +000065 return cxtu::getASTUnit(TU)->getASTContext();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000066 }
67
68 /// \brief We are looking to find all semantically relevant identifiers,
69 /// so the definition of "canonical" here is different than in the AST, e.g.
70 ///
71 /// \code
72 /// class C {
73 /// C() {}
74 /// };
75 /// \endcode
76 ///
77 /// we consider the canonical decl of the constructor decl to be the class
78 /// itself, so both 'C' can be highlighted.
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000079 const Decl *getCanonical(const Decl *D) const {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000080 if (!D)
81 return 0;
82
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000083 D = D->getCanonicalDecl();
84
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000085 if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000086 if (ImplD->getClassInterface())
87 return getCanonical(ImplD->getClassInterface());
88
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000089 } else if (const CXXConstructorDecl *CXXCtorD =
90 dyn_cast<CXXConstructorDecl>(D)) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000091 return getCanonical(CXXCtorD->getParent());
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000092 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000093
94 return D;
95 }
96
Dmitri Gribenkod15bb302013-01-23 17:25:27 +000097 bool isHit(const Decl *D) const {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000098 if (!D)
99 return false;
100
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000101 D = getCanonical(D);
102 if (D == Dcl)
103 return true;
104
105 if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
106 return isOverriddingMethod(D);
107
108 return false;
109 }
110
111private:
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000112 bool isOverriddingMethod(const Decl *D) const {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000113 if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
114 TopMethods.end())
115 return true;
116
117 TopMethodsTy methods;
118 getTopOverriddenMethods(TU, D, methods);
119 for (TopMethodsTy::iterator
120 I = methods.begin(), E = methods.end(); I != E; ++I) {
121 if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
122 TopMethods.end())
123 return true;
124 }
125
126 return false;
127 }
128};
129
130} // end anonymous namespace.
131
132/// \brief For a macro \arg Loc, returns the file spelling location and sets
133/// to \arg isMacroArg whether the spelling resides inside a macro definition or
134/// a macro argument.
135static SourceLocation getFileSpellingLoc(SourceManager &SM,
136 SourceLocation Loc,
137 bool &isMacroArg) {
138 assert(Loc.isMacroID());
139 SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
140 if (SpellLoc.isMacroID())
141 return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
142
143 isMacroArg = SM.isMacroArgExpansion(Loc);
144 return SpellLoc;
145}
146
147static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
148 CXCursor parent,
149 CXClientData client_data) {
150 CXCursor declCursor = clang_getCursorReferenced(cursor);
151 if (!clang_isDeclaration(declCursor.kind))
152 return CXChildVisit_Recurse;
153
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000154 const Decl *D = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis173e9112011-12-10 02:36:25 +0000155 if (!D)
156 return CXChildVisit_Continue;
157
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000158 FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
159 if (data->isHit(D)) {
160 cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
161
162 // We are looking for identifiers to highlight so for objc methods (and
163 // not a parameter) we can only highlight the selector identifiers.
164 if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
165 cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
166 cxcursor::getSelectorIdentifierIndex(cursor) == -1)
167 return CXChildVisit_Recurse;
168
169 if (clang_isExpression(cursor.kind)) {
170 if (cursor.kind == CXCursor_DeclRefExpr ||
171 cursor.kind == CXCursor_MemberRefExpr) {
172 // continue..
173
174 } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
175 cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
176 // continue..
177
178 } else
179 return CXChildVisit_Recurse;
180 }
181
182 SourceLocation
183 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
184 SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
185 if (SelIdLoc.isValid())
186 Loc = SelIdLoc;
187
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000188 ASTContext &Ctx = data->getASTContext();
189 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000190 bool isInMacroDef = false;
191 if (Loc.isMacroID()) {
192 bool isMacroArg;
193 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
194 isInMacroDef = !isMacroArg;
195 }
196
197 // We are looking for identifiers in a specific file.
198 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
199 if (LocInfo.first != data->FID)
200 return CXChildVisit_Recurse;
201
202 if (isInMacroDef) {
203 // FIXME: For a macro definition make sure that all expansions
204 // of it expand to the same reference before allowing to point to it.
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000205 return CXChildVisit_Recurse;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000206 }
207
Argyrios Kyrtzidis73313692013-03-08 02:32:29 +0000208 if (data->visitor.visit(data->visitor.context, cursor,
209 cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
210 return CXChildVisit_Break;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000211 }
212 return CXChildVisit_Recurse;
213}
214
215static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
216 const FileEntry *File,
217 CXCursorAndRangeVisitor Visitor) {
218 assert(clang_isDeclaration(declCursor.kind));
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000219 SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000220
221 FileID FID = SM.translateFile(File);
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000222 const Decl *Dcl = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +0000223 if (!Dcl)
224 return;
225
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000226 FindFileIdRefVisitData data(TU, FID, Dcl,
227 cxcursor::getSelectorIdentifierIndex(declCursor),
228 Visitor);
229
Dmitri Gribenkod15bb302013-01-23 17:25:27 +0000230 if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000231 clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
232 findFileIdRefVisit, &data);
233 return;
234 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000235
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000236 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
237 CursorVisitor FindIdRefsVisitor(TU,
238 findFileIdRefVisit, &data,
239 /*VisitPreprocessorLast=*/true,
240 /*VisitIncludedEntities=*/false,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000241 Range,
242 /*VisitDeclsOnly=*/true);
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000243 FindIdRefsVisitor.visitFileRegion();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000244}
245
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000246namespace {
247
248struct FindFileMacroRefVisitData {
249 ASTUnit &Unit;
250 const FileEntry *File;
251 const IdentifierInfo *Macro;
252 CXCursorAndRangeVisitor visitor;
253
254 FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File,
255 const IdentifierInfo *Macro,
256 CXCursorAndRangeVisitor visitor)
257 : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
258
259 ASTContext &getASTContext() const {
260 return Unit.getASTContext();
261 }
262};
263
264} // anonymous namespace
265
266static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
267 CXCursor parent,
268 CXClientData client_data) {
269 const IdentifierInfo *Macro = 0;
270 if (cursor.kind == CXCursor_MacroDefinition)
271 Macro = getCursorMacroDefinition(cursor)->getName();
272 else if (cursor.kind == CXCursor_MacroExpansion)
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000273 Macro = getCursorMacroExpansion(cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000274 if (!Macro)
275 return CXChildVisit_Continue;
276
277 FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
278 if (data->Macro != Macro)
279 return CXChildVisit_Continue;
280
281 SourceLocation
282 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
283
284 ASTContext &Ctx = data->getASTContext();
285 SourceManager &SM = Ctx.getSourceManager();
286 bool isInMacroDef = false;
287 if (Loc.isMacroID()) {
288 bool isMacroArg;
289 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
290 isInMacroDef = !isMacroArg;
291 }
292
293 // We are looking for identifiers in a specific file.
294 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
295 if (SM.getFileEntryForID(LocInfo.first) != data->File)
296 return CXChildVisit_Continue;
297
298 if (isInMacroDef) {
299 // FIXME: For a macro definition make sure that all expansions
300 // of it expand to the same reference before allowing to point to it.
301 return CXChildVisit_Continue;
302 }
303
Argyrios Kyrtzidis73313692013-03-08 02:32:29 +0000304 if (data->visitor.visit(data->visitor.context, cursor,
305 cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
306 return CXChildVisit_Break;
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000307 return CXChildVisit_Continue;
308}
309
310static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
311 const FileEntry *File,
312 CXCursorAndRangeVisitor Visitor) {
313 if (Cursor.kind != CXCursor_MacroDefinition &&
314 Cursor.kind != CXCursor_MacroExpansion)
315 return;
316
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000317 ASTUnit *Unit = cxtu::getASTUnit(TU);
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000318 SourceManager &SM = Unit->getSourceManager();
319
320 FileID FID = SM.translateFile(File);
321 const IdentifierInfo *Macro = 0;
322 if (Cursor.kind == CXCursor_MacroDefinition)
323 Macro = getCursorMacroDefinition(Cursor)->getName();
324 else
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000325 Macro = getCursorMacroExpansion(Cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000326 if (!Macro)
327 return;
328
329 FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
330
331 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
332 CursorVisitor FindMacroRefsVisitor(TU,
333 findFileMacroRefVisit, &data,
334 /*VisitPreprocessorLast=*/false,
335 /*VisitIncludedEntities=*/false,
336 Range);
337 FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
338}
339
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000340
341//===----------------------------------------------------------------------===//
342// libclang public APIs.
343//===----------------------------------------------------------------------===//
344
345extern "C" {
346
347void clang_findReferencesInFile(CXCursor cursor, CXFile file,
348 CXCursorAndRangeVisitor visitor) {
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +0000349 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000350
351 if (clang_Cursor_isNull(cursor)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000352 if (Log)
353 *Log << "Null cursor";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000354 return;
355 }
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000356 if (cursor.kind == CXCursor_NoDeclFound) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000357 if (Log)
358 *Log << "Got CXCursor_NoDeclFound";
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000359 return;
360 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000361 if (!file) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000362 if (Log)
363 *Log << "Null file";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000364 return;
365 }
366 if (!visitor.visit) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000367 if (Log)
368 *Log << "Null visitor";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000369 return;
370 }
371
Argyrios Kyrtzidisba4b5f82013-03-08 02:32:26 +0000372 if (Log)
373 *Log << cursor << " @" << static_cast<const FileEntry *>(file);
374
Argyrios Kyrtzidisebbb2062011-11-29 23:21:50 +0000375 ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
376 if (!CXXUnit)
377 return;
378
379 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
380
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000381 if (cursor.kind == CXCursor_MacroDefinition ||
382 cursor.kind == CXCursor_MacroExpansion) {
383 findMacroRefsInFile(cxcursor::getCursorTU(cursor),
384 cursor,
385 static_cast<const FileEntry *>(file),
386 visitor);
387 return;
388 }
389
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000390 // We are interested in semantics of identifiers so for C++ constructor exprs
391 // prefer type references, e.g.:
392 //
393 // return MyStruct();
394 //
395 // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
396 // we are actually interested in the type declaration.
397 cursor = cxcursor::getTypeRefCursor(cursor);
398
399 CXCursor refCursor = clang_getCursorReferenced(cursor);
400
401 if (!clang_isDeclaration(refCursor.kind)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000402 if (Log)
403 *Log << "cursor is not referencing a declaration";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000404 return;
405 }
406
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000407 findIdRefsInFile(cxcursor::getCursorTU(cursor),
408 refCursor,
409 static_cast<const FileEntry *>(file),
410 visitor);
411}
412
413static enum CXVisitorResult _visitCursorAndRange(void *context,
414 CXCursor cursor,
415 CXSourceRange range) {
416 CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
417 return INVOKE_BLOCK2(block, cursor, range);
418}
419
420void clang_findReferencesInFileWithBlock(CXCursor cursor,
421 CXFile file,
422 CXCursorAndRangeVisitorBlock block) {
423 CXCursorAndRangeVisitor visitor = { block,
424 block ? _visitCursorAndRange : 0 };
425 return clang_findReferencesInFile(cursor, file, visitor);
426}
427
428} // end: extern "C"
429