blob: a2c32fe050088d971c139d187df49e9bd91f76a6 [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,
24 Decl *D,
25 SmallVectorImpl<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;
49 Decl *Dcl;
50 int SelectorIdIdx;
51 CXCursorAndRangeVisitor visitor;
52
53 typedef SmallVector<Decl *, 8> TopMethodsTy;
54 TopMethodsTy TopMethods;
55
56 FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
57 Decl *D, int selectorIdIdx,
58 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 {
65 return static_cast<ASTUnit *>(TU->TUData)->getASTContext();
66 }
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.
79 Decl *getCanonical(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
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000085 if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
86 if (ImplD->getClassInterface())
87 return getCanonical(ImplD->getClassInterface());
88
89 } else if (CXXConstructorDecl *CXXCtorD = 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
96 bool isHit(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:
111 bool isOverriddingMethod(Decl *D) const {
112 if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
113 TopMethods.end())
114 return true;
115
116 TopMethodsTy methods;
117 getTopOverriddenMethods(TU, D, methods);
118 for (TopMethodsTy::iterator
119 I = methods.begin(), E = methods.end(); I != E; ++I) {
120 if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
121 TopMethods.end())
122 return true;
123 }
124
125 return false;
126 }
127};
128
129} // end anonymous namespace.
130
131/// \brief For a macro \arg Loc, returns the file spelling location and sets
132/// to \arg isMacroArg whether the spelling resides inside a macro definition or
133/// a macro argument.
134static SourceLocation getFileSpellingLoc(SourceManager &SM,
135 SourceLocation Loc,
136 bool &isMacroArg) {
137 assert(Loc.isMacroID());
138 SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
139 if (SpellLoc.isMacroID())
140 return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
141
142 isMacroArg = SM.isMacroArgExpansion(Loc);
143 return SpellLoc;
144}
145
146static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
147 CXCursor parent,
148 CXClientData client_data) {
149 CXCursor declCursor = clang_getCursorReferenced(cursor);
150 if (!clang_isDeclaration(declCursor.kind))
151 return CXChildVisit_Recurse;
152
153 Decl *D = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis173e9112011-12-10 02:36:25 +0000154 if (!D)
155 return CXChildVisit_Continue;
156
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000157 FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
158 if (data->isHit(D)) {
159 cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
160
161 // We are looking for identifiers to highlight so for objc methods (and
162 // not a parameter) we can only highlight the selector identifiers.
163 if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
164 cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
165 cxcursor::getSelectorIdentifierIndex(cursor) == -1)
166 return CXChildVisit_Recurse;
167
168 if (clang_isExpression(cursor.kind)) {
169 if (cursor.kind == CXCursor_DeclRefExpr ||
170 cursor.kind == CXCursor_MemberRefExpr) {
171 // continue..
172
173 } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
174 cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
175 // continue..
176
177 } else
178 return CXChildVisit_Recurse;
179 }
180
181 SourceLocation
182 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
183 SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
184 if (SelIdLoc.isValid())
185 Loc = SelIdLoc;
186
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000187 ASTContext &Ctx = data->getASTContext();
188 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000189 bool isInMacroDef = false;
190 if (Loc.isMacroID()) {
191 bool isMacroArg;
192 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
193 isInMacroDef = !isMacroArg;
194 }
195
196 // We are looking for identifiers in a specific file.
197 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
198 if (LocInfo.first != data->FID)
199 return CXChildVisit_Recurse;
200
201 if (isInMacroDef) {
202 // FIXME: For a macro definition make sure that all expansions
203 // of it expand to the same reference before allowing to point to it.
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000204 return CXChildVisit_Recurse;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000205 }
206
207 data->visitor.visit(data->visitor.context, cursor,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000208 cxloc::translateSourceRange(Ctx, Loc));
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000209 }
210 return CXChildVisit_Recurse;
211}
212
213static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
214 const FileEntry *File,
215 CXCursorAndRangeVisitor Visitor) {
216 assert(clang_isDeclaration(declCursor.kind));
217 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000218 SourceManager &SM = Unit->getSourceManager();
219
220 FileID FID = SM.translateFile(File);
221 Decl *Dcl = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +0000222 if (!Dcl)
223 return;
224
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000225 FindFileIdRefVisitData data(TU, FID, Dcl,
226 cxcursor::getSelectorIdentifierIndex(declCursor),
227 Visitor);
228
229 if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
230 clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
231 findFileIdRefVisit, &data);
232 return;
233 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000234
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000235 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
236 CursorVisitor FindIdRefsVisitor(TU,
237 findFileIdRefVisit, &data,
238 /*VisitPreprocessorLast=*/true,
239 /*VisitIncludedEntities=*/false,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000240 Range,
241 /*VisitDeclsOnly=*/true);
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000242 FindIdRefsVisitor.visitFileRegion();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000243}
244
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000245namespace {
246
247struct FindFileMacroRefVisitData {
248 ASTUnit &Unit;
249 const FileEntry *File;
250 const IdentifierInfo *Macro;
251 CXCursorAndRangeVisitor visitor;
252
253 FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File,
254 const IdentifierInfo *Macro,
255 CXCursorAndRangeVisitor visitor)
256 : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
257
258 ASTContext &getASTContext() const {
259 return Unit.getASTContext();
260 }
261};
262
263} // anonymous namespace
264
265static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
266 CXCursor parent,
267 CXClientData client_data) {
268 const IdentifierInfo *Macro = 0;
269 if (cursor.kind == CXCursor_MacroDefinition)
270 Macro = getCursorMacroDefinition(cursor)->getName();
271 else if (cursor.kind == CXCursor_MacroExpansion)
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000272 Macro = getCursorMacroExpansion(cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000273 if (!Macro)
274 return CXChildVisit_Continue;
275
276 FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
277 if (data->Macro != Macro)
278 return CXChildVisit_Continue;
279
280 SourceLocation
281 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
282
283 ASTContext &Ctx = data->getASTContext();
284 SourceManager &SM = Ctx.getSourceManager();
285 bool isInMacroDef = false;
286 if (Loc.isMacroID()) {
287 bool isMacroArg;
288 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
289 isInMacroDef = !isMacroArg;
290 }
291
292 // We are looking for identifiers in a specific file.
293 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
294 if (SM.getFileEntryForID(LocInfo.first) != data->File)
295 return CXChildVisit_Continue;
296
297 if (isInMacroDef) {
298 // FIXME: For a macro definition make sure that all expansions
299 // of it expand to the same reference before allowing to point to it.
300 return CXChildVisit_Continue;
301 }
302
303 data->visitor.visit(data->visitor.context, cursor,
304 cxloc::translateSourceRange(Ctx, Loc));
305 return CXChildVisit_Continue;
306}
307
308static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
309 const FileEntry *File,
310 CXCursorAndRangeVisitor Visitor) {
311 if (Cursor.kind != CXCursor_MacroDefinition &&
312 Cursor.kind != CXCursor_MacroExpansion)
313 return;
314
315 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
316 SourceManager &SM = Unit->getSourceManager();
317
318 FileID FID = SM.translateFile(File);
319 const IdentifierInfo *Macro = 0;
320 if (Cursor.kind == CXCursor_MacroDefinition)
321 Macro = getCursorMacroDefinition(Cursor)->getName();
322 else
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000323 Macro = getCursorMacroExpansion(Cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000324 if (!Macro)
325 return;
326
327 FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
328
329 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
330 CursorVisitor FindMacroRefsVisitor(TU,
331 findFileMacroRefVisit, &data,
332 /*VisitPreprocessorLast=*/false,
333 /*VisitIncludedEntities=*/false,
334 Range);
335 FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
336}
337
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000338
339//===----------------------------------------------------------------------===//
340// libclang public APIs.
341//===----------------------------------------------------------------------===//
342
343extern "C" {
344
345void clang_findReferencesInFile(CXCursor cursor, CXFile file,
346 CXCursorAndRangeVisitor visitor) {
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +0000347 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000348
349 if (clang_Cursor_isNull(cursor)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000350 if (Log)
351 *Log << "Null cursor";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000352 return;
353 }
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000354 if (cursor.kind == CXCursor_NoDeclFound) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000355 if (Log)
356 *Log << "Got CXCursor_NoDeclFound";
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000357 return;
358 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000359 if (!file) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000360 if (Log)
361 *Log << "Null file";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000362 return;
363 }
364 if (!visitor.visit) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000365 if (Log)
366 *Log << "Null visitor";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000367 return;
368 }
369
Argyrios Kyrtzidisebbb2062011-11-29 23:21:50 +0000370 ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
371 if (!CXXUnit)
372 return;
373
374 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
375
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000376 if (cursor.kind == CXCursor_MacroDefinition ||
377 cursor.kind == CXCursor_MacroExpansion) {
378 findMacroRefsInFile(cxcursor::getCursorTU(cursor),
379 cursor,
380 static_cast<const FileEntry *>(file),
381 visitor);
382 return;
383 }
384
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000385 // We are interested in semantics of identifiers so for C++ constructor exprs
386 // prefer type references, e.g.:
387 //
388 // return MyStruct();
389 //
390 // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
391 // we are actually interested in the type declaration.
392 cursor = cxcursor::getTypeRefCursor(cursor);
393
394 CXCursor refCursor = clang_getCursorReferenced(cursor);
395
396 if (!clang_isDeclaration(refCursor.kind)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000397 if (Log)
398 *Log << "cursor is not referencing a declaration";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000399 return;
400 }
401
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000402 findIdRefsInFile(cxcursor::getCursorTU(cursor),
403 refCursor,
404 static_cast<const FileEntry *>(file),
405 visitor);
406}
407
408static enum CXVisitorResult _visitCursorAndRange(void *context,
409 CXCursor cursor,
410 CXSourceRange range) {
411 CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
412 return INVOKE_BLOCK2(block, cursor, range);
413}
414
415void clang_findReferencesInFileWithBlock(CXCursor cursor,
416 CXFile file,
417 CXCursorAndRangeVisitorBlock block) {
418 CXCursorAndRangeVisitor visitor = { block,
419 block ? _visitCursorAndRange : 0 };
420 return clang_findReferencesInFile(cursor, file, visitor);
421}
422
423} // end: extern "C"
424