blob: f4d6bc564e00edf1e9ca9f588490820a6a219fa6 [file] [log] [blame]
Argyrios Kyrtzidisaed123e2011-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 Kyrtzidise2079cf2011-11-16 08:58:54 +000010#include "CursorVisitor.h"
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000011#include "CXCursor.h"
12#include "CXSourceLocation.h"
13#include "CXTranslationUnit.h"
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000014#include "clang/AST/DeclObjC.h"
Chandler Carruthf59edb92012-12-04 09:25:21 +000015#include "clang/Frontend/ASTUnit.h"
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000016
17using namespace clang;
Argyrios Kyrtzidise2079cf2011-11-16 08:58:54 +000018using namespace cxcursor;
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000019
20static void getTopOverriddenMethods(CXTranslationUnit TU,
21 Decl *D,
22 SmallVectorImpl<Decl *> &Methods) {
Argyrios Kyrtzidis16ed0e62011-12-10 02:36:25 +000023 if (!D)
24 return;
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000025 if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
26 return;
27
28 SmallVector<CXCursor, 8> Overridden;
29 cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden);
30
31 if (Overridden.empty()) {
32 Methods.push_back(D->getCanonicalDecl());
33 return;
34 }
35
36 for (SmallVector<CXCursor, 8>::iterator
37 I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
38 getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
39}
40
41namespace {
42
43struct FindFileIdRefVisitData {
44 CXTranslationUnit TU;
45 FileID FID;
46 Decl *Dcl;
47 int SelectorIdIdx;
48 CXCursorAndRangeVisitor visitor;
49
50 typedef SmallVector<Decl *, 8> TopMethodsTy;
51 TopMethodsTy TopMethods;
52
53 FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
54 Decl *D, int selectorIdIdx,
55 CXCursorAndRangeVisitor visitor)
56 : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
57 Dcl = getCanonical(D);
58 getTopOverriddenMethods(TU, Dcl, TopMethods);
59 }
60
61 ASTContext &getASTContext() const {
62 return static_cast<ASTUnit *>(TU->TUData)->getASTContext();
63 }
64
65 /// \brief We are looking to find all semantically relevant identifiers,
66 /// so the definition of "canonical" here is different than in the AST, e.g.
67 ///
68 /// \code
69 /// class C {
70 /// C() {}
71 /// };
72 /// \endcode
73 ///
74 /// we consider the canonical decl of the constructor decl to be the class
75 /// itself, so both 'C' can be highlighted.
76 Decl *getCanonical(Decl *D) const {
Argyrios Kyrtzidise368a642011-12-08 01:56:07 +000077 if (!D)
78 return 0;
79
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000080 D = D->getCanonicalDecl();
81
Argyrios Kyrtzidise368a642011-12-08 01:56:07 +000082 if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
83 if (ImplD->getClassInterface())
84 return getCanonical(ImplD->getClassInterface());
85
86 } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) {
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000087 return getCanonical(CXXCtorD->getParent());
Argyrios Kyrtzidise368a642011-12-08 01:56:07 +000088 }
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000089
90 return D;
91 }
92
93 bool isHit(Decl *D) const {
Argyrios Kyrtzidise368a642011-12-08 01:56:07 +000094 if (!D)
95 return false;
96
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +000097 D = getCanonical(D);
98 if (D == Dcl)
99 return true;
100
101 if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
102 return isOverriddingMethod(D);
103
104 return false;
105 }
106
107private:
108 bool isOverriddingMethod(Decl *D) const {
109 if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
110 TopMethods.end())
111 return true;
112
113 TopMethodsTy methods;
114 getTopOverriddenMethods(TU, D, methods);
115 for (TopMethodsTy::iterator
116 I = methods.begin(), E = methods.end(); I != E; ++I) {
117 if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
118 TopMethods.end())
119 return true;
120 }
121
122 return false;
123 }
124};
125
126} // end anonymous namespace.
127
128/// \brief For a macro \arg Loc, returns the file spelling location and sets
129/// to \arg isMacroArg whether the spelling resides inside a macro definition or
130/// a macro argument.
131static SourceLocation getFileSpellingLoc(SourceManager &SM,
132 SourceLocation Loc,
133 bool &isMacroArg) {
134 assert(Loc.isMacroID());
135 SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
136 if (SpellLoc.isMacroID())
137 return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
138
139 isMacroArg = SM.isMacroArgExpansion(Loc);
140 return SpellLoc;
141}
142
143static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
144 CXCursor parent,
145 CXClientData client_data) {
146 CXCursor declCursor = clang_getCursorReferenced(cursor);
147 if (!clang_isDeclaration(declCursor.kind))
148 return CXChildVisit_Recurse;
149
150 Decl *D = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidis16ed0e62011-12-10 02:36:25 +0000151 if (!D)
152 return CXChildVisit_Continue;
153
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000154 FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
155 if (data->isHit(D)) {
156 cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
157
158 // We are looking for identifiers to highlight so for objc methods (and
159 // not a parameter) we can only highlight the selector identifiers.
160 if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
161 cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
162 cxcursor::getSelectorIdentifierIndex(cursor) == -1)
163 return CXChildVisit_Recurse;
164
165 if (clang_isExpression(cursor.kind)) {
166 if (cursor.kind == CXCursor_DeclRefExpr ||
167 cursor.kind == CXCursor_MemberRefExpr) {
168 // continue..
169
170 } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
171 cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
172 // continue..
173
174 } else
175 return CXChildVisit_Recurse;
176 }
177
178 SourceLocation
179 Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
180 SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
181 if (SelIdLoc.isValid())
182 Loc = SelIdLoc;
183
Argyrios Kyrtzidisb49e7282011-11-29 03:14:11 +0000184 ASTContext &Ctx = data->getASTContext();
185 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000186 bool isInMacroDef = false;
187 if (Loc.isMacroID()) {
188 bool isMacroArg;
189 Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
190 isInMacroDef = !isMacroArg;
191 }
192
193 // We are looking for identifiers in a specific file.
194 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
195 if (LocInfo.first != data->FID)
196 return CXChildVisit_Recurse;
197
198 if (isInMacroDef) {
199 // FIXME: For a macro definition make sure that all expansions
200 // of it expand to the same reference before allowing to point to it.
Argyrios Kyrtzidisb49e7282011-11-29 03:14:11 +0000201 return CXChildVisit_Recurse;
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000202 }
203
204 data->visitor.visit(data->visitor.context, cursor,
Argyrios Kyrtzidisb49e7282011-11-29 03:14:11 +0000205 cxloc::translateSourceRange(Ctx, Loc));
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000206 }
207 return CXChildVisit_Recurse;
208}
209
210static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
211 const FileEntry *File,
212 CXCursorAndRangeVisitor Visitor) {
213 assert(clang_isDeclaration(declCursor.kind));
214 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000215 SourceManager &SM = Unit->getSourceManager();
216
217 FileID FID = SM.translateFile(File);
218 Decl *Dcl = cxcursor::getCursorDecl(declCursor);
Argyrios Kyrtzidise368a642011-12-08 01:56:07 +0000219 if (!Dcl)
220 return;
221
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000222 FindFileIdRefVisitData data(TU, FID, Dcl,
223 cxcursor::getSelectorIdentifierIndex(declCursor),
224 Visitor);
225
226 if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
227 clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
228 findFileIdRefVisit, &data);
229 return;
230 }
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000231
Argyrios Kyrtzidise2079cf2011-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 Kyrtzidisb49e7282011-11-29 03:14:11 +0000237 Range,
238 /*VisitDeclsOnly=*/true);
Argyrios Kyrtzidise2079cf2011-11-16 08:58:54 +0000239 FindIdRefsVisitor.visitFileRegion();
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000240}
241
Argyrios Kyrtzidisb49e7282011-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) {
265 const IdentifierInfo *Macro = 0;
266 if (cursor.kind == CXCursor_MacroDefinition)
267 Macro = getCursorMacroDefinition(cursor)->getName();
268 else if (cursor.kind == CXCursor_MacroExpansion)
Argyrios Kyrtzidis664b06f2013-01-07 19:16:25 +0000269 Macro = getCursorMacroExpansion(cursor).getName();
Argyrios Kyrtzidisb49e7282011-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
300 data->visitor.visit(data->visitor.context, cursor,
301 cxloc::translateSourceRange(Ctx, Loc));
302 return CXChildVisit_Continue;
303}
304
305static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
306 const FileEntry *File,
307 CXCursorAndRangeVisitor Visitor) {
308 if (Cursor.kind != CXCursor_MacroDefinition &&
309 Cursor.kind != CXCursor_MacroExpansion)
310 return;
311
312 ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
313 SourceManager &SM = Unit->getSourceManager();
314
315 FileID FID = SM.translateFile(File);
316 const IdentifierInfo *Macro = 0;
317 if (Cursor.kind == CXCursor_MacroDefinition)
318 Macro = getCursorMacroDefinition(Cursor)->getName();
319 else
Argyrios Kyrtzidis664b06f2013-01-07 19:16:25 +0000320 Macro = getCursorMacroExpansion(Cursor).getName();
Argyrios Kyrtzidisb49e7282011-11-29 03:14:11 +0000321 if (!Macro)
322 return;
323
324 FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
325
326 SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
327 CursorVisitor FindMacroRefsVisitor(TU,
328 findFileMacroRefVisit, &data,
329 /*VisitPreprocessorLast=*/false,
330 /*VisitIncludedEntities=*/false,
331 Range);
332 FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
333}
334
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000335
336//===----------------------------------------------------------------------===//
337// libclang public APIs.
338//===----------------------------------------------------------------------===//
339
340extern "C" {
341
342void clang_findReferencesInFile(CXCursor cursor, CXFile file,
343 CXCursorAndRangeVisitor visitor) {
344 bool Logging = ::getenv("LIBCLANG_LOGGING");
345
346 if (clang_Cursor_isNull(cursor)) {
347 if (Logging)
348 llvm::errs() << "clang_findReferencesInFile: Null cursor\n";
349 return;
350 }
Argyrios Kyrtzidis44517462011-12-09 00:17:49 +0000351 if (cursor.kind == CXCursor_NoDeclFound) {
352 if (Logging)
353 llvm::errs() << "clang_findReferencesInFile: Got CXCursor_NoDeclFound\n";
354 return;
355 }
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000356 if (!file) {
357 if (Logging)
358 llvm::errs() << "clang_findReferencesInFile: Null file\n";
359 return;
360 }
361 if (!visitor.visit) {
362 if (Logging)
363 llvm::errs() << "clang_findReferencesInFile: Null visitor\n";
364 return;
365 }
366
Argyrios Kyrtzidis5c2a1f72011-11-29 23:21:50 +0000367 ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
368 if (!CXXUnit)
369 return;
370
371 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
372
Argyrios Kyrtzidisb49e7282011-11-29 03:14:11 +0000373 if (cursor.kind == CXCursor_MacroDefinition ||
374 cursor.kind == CXCursor_MacroExpansion) {
375 findMacroRefsInFile(cxcursor::getCursorTU(cursor),
376 cursor,
377 static_cast<const FileEntry *>(file),
378 visitor);
379 return;
380 }
381
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000382 // We are interested in semantics of identifiers so for C++ constructor exprs
383 // prefer type references, e.g.:
384 //
385 // return MyStruct();
386 //
387 // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
388 // we are actually interested in the type declaration.
389 cursor = cxcursor::getTypeRefCursor(cursor);
390
391 CXCursor refCursor = clang_getCursorReferenced(cursor);
392
393 if (!clang_isDeclaration(refCursor.kind)) {
394 if (Logging)
395 llvm::errs() << "clang_findReferencesInFile: cursor is not referencing a "
396 "declaration\n";
397 return;
398 }
399
Argyrios Kyrtzidisaed123e2011-10-06 07:00:54 +0000400 findIdRefsInFile(cxcursor::getCursorTU(cursor),
401 refCursor,
402 static_cast<const FileEntry *>(file),
403 visitor);
404}
405
406static enum CXVisitorResult _visitCursorAndRange(void *context,
407 CXCursor cursor,
408 CXSourceRange range) {
409 CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
410 return INVOKE_BLOCK2(block, cursor, range);
411}
412
413void clang_findReferencesInFileWithBlock(CXCursor cursor,
414 CXFile file,
415 CXCursorAndRangeVisitorBlock block) {
416 CXCursorAndRangeVisitor visitor = { block,
417 block ? _visitCursorAndRange : 0 };
418 return clang_findReferencesInFile(cursor, file, visitor);
419}
420
421} // end: extern "C"
422