blob: 4f8a252993990e95671076d7aee229e00f6b1a6d [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"
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000011#include "CXCursor.h"
12#include "CXSourceLocation.h"
13#include "CXTranslationUnit.h"
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +000014#include "CLog.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"
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,
23 Decl *D,
24 SmallVectorImpl<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
38 for (SmallVector<CXCursor, 8>::iterator
39 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;
48 Decl *Dcl;
49 int SelectorIdIdx;
50 CXCursorAndRangeVisitor visitor;
51
52 typedef SmallVector<Decl *, 8> TopMethodsTy;
53 TopMethodsTy TopMethods;
54
55 FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
56 Decl *D, int selectorIdIdx,
57 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 {
64 return static_cast<ASTUnit *>(TU->TUData)->getASTContext();
65 }
66
67 /// \brief 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 Decl *getCanonical(Decl *D) const {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000079 if (!D)
80 return 0;
81
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000082 D = D->getCanonicalDecl();
83
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000084 if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
85 if (ImplD->getClassInterface())
86 return getCanonical(ImplD->getClassInterface());
87
88 } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000089 return getCanonical(CXXCtorD->getParent());
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000090 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000091
92 return D;
93 }
94
95 bool isHit(Decl *D) const {
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +000096 if (!D)
97 return false;
98
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +000099 D = getCanonical(D);
100 if (D == Dcl)
101 return true;
102
103 if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
104 return isOverriddingMethod(D);
105
106 return false;
107 }
108
109private:
110 bool isOverriddingMethod(Decl *D) const {
111 if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
112 TopMethods.end())
113 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) {
119 if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
120 TopMethods.end())
121 return true;
122 }
123
124 return false;
125 }
126};
127
128} // end anonymous namespace.
129
130/// \brief For a macro \arg Loc, returns the file spelling location and sets
131/// to \arg isMacroArg whether the spelling resides inside a macro definition or
132/// a macro argument.
133static SourceLocation getFileSpellingLoc(SourceManager &SM,
134 SourceLocation Loc,
135 bool &isMacroArg) {
136 assert(Loc.isMacroID());
137 SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
138 if (SpellLoc.isMacroID())
139 return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
140
141 isMacroArg = SM.isMacroArgExpansion(Loc);
142 return SpellLoc;
143}
144
145static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
146 CXCursor parent,
147 CXClientData client_data) {
148 CXCursor declCursor = clang_getCursorReferenced(cursor);
149 if (!clang_isDeclaration(declCursor.kind))
150 return CXChildVisit_Recurse;
151
152 Decl *D = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis173e9112011-12-10 02:36:25 +0000153 if (!D)
154 return CXChildVisit_Continue;
155
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000156 FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
157 if (data->isHit(D)) {
158 cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
159
160 // We are looking for identifiers to highlight so for objc methods (and
161 // not a parameter) we can only highlight the selector identifiers.
162 if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
163 cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
164 cxcursor::getSelectorIdentifierIndex(cursor) == -1)
165 return CXChildVisit_Recurse;
166
167 if (clang_isExpression(cursor.kind)) {
168 if (cursor.kind == CXCursor_DeclRefExpr ||
169 cursor.kind == CXCursor_MemberRefExpr) {
170 // continue..
171
172 } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
173 cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
174 // continue..
175
176 } else
177 return CXChildVisit_Recurse;
178 }
179
180 SourceLocation
181 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
182 SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
183 if (SelIdLoc.isValid())
184 Loc = SelIdLoc;
185
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000186 ASTContext &Ctx = data->getASTContext();
187 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000188 bool isInMacroDef = false;
189 if (Loc.isMacroID()) {
190 bool isMacroArg;
191 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
192 isInMacroDef = !isMacroArg;
193 }
194
195 // We are looking for identifiers in a specific file.
196 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
197 if (LocInfo.first != data->FID)
198 return CXChildVisit_Recurse;
199
200 if (isInMacroDef) {
201 // FIXME: For a macro definition make sure that all expansions
202 // of it expand to the same reference before allowing to point to it.
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000203 return CXChildVisit_Recurse;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000204 }
205
206 data->visitor.visit(data->visitor.context, cursor,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000207 cxloc::translateSourceRange(Ctx, Loc));
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000208 }
209 return CXChildVisit_Recurse;
210}
211
212static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
213 const FileEntry *File,
214 CXCursorAndRangeVisitor Visitor) {
215 assert(clang_isDeclaration(declCursor.kind));
216 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000217 SourceManager &SM = Unit->getSourceManager();
218
219 FileID FID = SM.translateFile(File);
220 Decl *Dcl = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis831411f2011-12-08 01:56:07 +0000221 if (!Dcl)
222 return;
223
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000224 FindFileIdRefVisitData data(TU, FID, Dcl,
225 cxcursor::getSelectorIdentifierIndex(declCursor),
226 Visitor);
227
228 if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
229 clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
230 findFileIdRefVisit, &data);
231 return;
232 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000233
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000234 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
235 CursorVisitor FindIdRefsVisitor(TU,
236 findFileIdRefVisit, &data,
237 /*VisitPreprocessorLast=*/true,
238 /*VisitIncludedEntities=*/false,
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000239 Range,
240 /*VisitDeclsOnly=*/true);
Argyrios Kyrtzidisc504eb32011-11-16 08:58:54 +0000241 FindIdRefsVisitor.visitFileRegion();
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000242}
243
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000244namespace {
245
246struct FindFileMacroRefVisitData {
247 ASTUnit &Unit;
248 const FileEntry *File;
249 const IdentifierInfo *Macro;
250 CXCursorAndRangeVisitor visitor;
251
252 FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File,
253 const IdentifierInfo *Macro,
254 CXCursorAndRangeVisitor visitor)
255 : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
256
257 ASTContext &getASTContext() const {
258 return Unit.getASTContext();
259 }
260};
261
262} // anonymous namespace
263
264static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
265 CXCursor parent,
266 CXClientData client_data) {
267 const IdentifierInfo *Macro = 0;
268 if (cursor.kind == CXCursor_MacroDefinition)
269 Macro = getCursorMacroDefinition(cursor)->getName();
270 else if (cursor.kind == CXCursor_MacroExpansion)
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000271 Macro = getCursorMacroExpansion(cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000272 if (!Macro)
273 return CXChildVisit_Continue;
274
275 FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
276 if (data->Macro != Macro)
277 return CXChildVisit_Continue;
278
279 SourceLocation
280 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
281
282 ASTContext &Ctx = data->getASTContext();
283 SourceManager &SM = Ctx.getSourceManager();
284 bool isInMacroDef = false;
285 if (Loc.isMacroID()) {
286 bool isMacroArg;
287 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
288 isInMacroDef = !isMacroArg;
289 }
290
291 // We are looking for identifiers in a specific file.
292 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
293 if (SM.getFileEntryForID(LocInfo.first) != data->File)
294 return CXChildVisit_Continue;
295
296 if (isInMacroDef) {
297 // FIXME: For a macro definition make sure that all expansions
298 // of it expand to the same reference before allowing to point to it.
299 return CXChildVisit_Continue;
300 }
301
302 data->visitor.visit(data->visitor.context, cursor,
303 cxloc::translateSourceRange(Ctx, Loc));
304 return CXChildVisit_Continue;
305}
306
307static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
308 const FileEntry *File,
309 CXCursorAndRangeVisitor Visitor) {
310 if (Cursor.kind != CXCursor_MacroDefinition &&
311 Cursor.kind != CXCursor_MacroExpansion)
312 return;
313
314 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
315 SourceManager &SM = Unit->getSourceManager();
316
317 FileID FID = SM.translateFile(File);
318 const IdentifierInfo *Macro = 0;
319 if (Cursor.kind == CXCursor_MacroDefinition)
320 Macro = getCursorMacroDefinition(Cursor)->getName();
321 else
Argyrios Kyrtzidis579825a2013-01-07 19:16:25 +0000322 Macro = getCursorMacroExpansion(Cursor).getName();
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000323 if (!Macro)
324 return;
325
326 FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
327
328 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
329 CursorVisitor FindMacroRefsVisitor(TU,
330 findFileMacroRefVisit, &data,
331 /*VisitPreprocessorLast=*/false,
332 /*VisitIncludedEntities=*/false,
333 Range);
334 FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
335}
336
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000337
338//===----------------------------------------------------------------------===//
339// libclang public APIs.
340//===----------------------------------------------------------------------===//
341
342extern "C" {
343
344void clang_findReferencesInFile(CXCursor cursor, CXFile file,
345 CXCursorAndRangeVisitor visitor) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000346 LogRef Log = Logger::make(__func__);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000347
348 if (clang_Cursor_isNull(cursor)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000349 if (Log)
350 *Log << "Null cursor";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000351 return;
352 }
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000353 if (cursor.kind == CXCursor_NoDeclFound) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000354 if (Log)
355 *Log << "Got CXCursor_NoDeclFound";
Argyrios Kyrtzidisfa469d02011-12-09 00:17:49 +0000356 return;
357 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000358 if (!file) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000359 if (Log)
360 *Log << "Null file";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000361 return;
362 }
363 if (!visitor.visit) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000364 if (Log)
365 *Log << "Null visitor";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000366 return;
367 }
368
Argyrios Kyrtzidisebbb2062011-11-29 23:21:50 +0000369 ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
370 if (!CXXUnit)
371 return;
372
373 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
374
Argyrios Kyrtzidis1ddb97ec2011-11-29 03:14:11 +0000375 if (cursor.kind == CXCursor_MacroDefinition ||
376 cursor.kind == CXCursor_MacroExpansion) {
377 findMacroRefsInFile(cxcursor::getCursorTU(cursor),
378 cursor,
379 static_cast<const FileEntry *>(file),
380 visitor);
381 return;
382 }
383
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000384 // We are interested in semantics of identifiers so for C++ constructor exprs
385 // prefer type references, e.g.:
386 //
387 // return MyStruct();
388 //
389 // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
390 // we are actually interested in the type declaration.
391 cursor = cxcursor::getTypeRefCursor(cursor);
392
393 CXCursor refCursor = clang_getCursorReferenced(cursor);
394
395 if (!clang_isDeclaration(refCursor.kind)) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000396 if (Log)
397 *Log << "cursor is not referencing a declaration";
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000398 return;
399 }
400
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000401 findIdRefsInFile(cxcursor::getCursorTU(cursor),
402 refCursor,
403 static_cast<const FileEntry *>(file),
404 visitor);
405}
406
407static enum CXVisitorResult _visitCursorAndRange(void *context,
408 CXCursor cursor,
409 CXSourceRange range) {
410 CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
411 return INVOKE_BLOCK2(block, cursor, range);
412}
413
414void clang_findReferencesInFileWithBlock(CXCursor cursor,
415 CXFile file,
416 CXCursorAndRangeVisitorBlock block) {
417 CXCursorAndRangeVisitor visitor = { block,
418 block ? _visitCursorAndRange : 0 };
419 return clang_findReferencesInFile(cursor, file, visitor);
420}
421
422} // end: extern "C"
423