1*67e74705SXin Li //===- CIndexHigh.cpp - Higher level API functions ------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "CursorVisitor.h"
11*67e74705SXin Li #include "CLog.h"
12*67e74705SXin Li #include "CXCursor.h"
13*67e74705SXin Li #include "CXSourceLocation.h"
14*67e74705SXin Li #include "CXTranslationUnit.h"
15*67e74705SXin Li #include "clang/AST/DeclObjC.h"
16*67e74705SXin Li #include "clang/Frontend/ASTUnit.h"
17*67e74705SXin Li #include "llvm/Support/Compiler.h"
18*67e74705SXin Li
19*67e74705SXin Li using namespace clang;
20*67e74705SXin Li using namespace cxcursor;
21*67e74705SXin Li using namespace cxindex;
22*67e74705SXin Li
getTopOverriddenMethods(CXTranslationUnit TU,const Decl * D,SmallVectorImpl<const Decl * > & Methods)23*67e74705SXin Li static void getTopOverriddenMethods(CXTranslationUnit TU,
24*67e74705SXin Li const Decl *D,
25*67e74705SXin Li SmallVectorImpl<const Decl *> &Methods) {
26*67e74705SXin Li if (!D)
27*67e74705SXin Li return;
28*67e74705SXin Li if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
29*67e74705SXin Li return;
30*67e74705SXin Li
31*67e74705SXin Li SmallVector<CXCursor, 8> Overridden;
32*67e74705SXin Li cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden);
33*67e74705SXin Li
34*67e74705SXin Li if (Overridden.empty()) {
35*67e74705SXin Li Methods.push_back(D->getCanonicalDecl());
36*67e74705SXin Li return;
37*67e74705SXin Li }
38*67e74705SXin Li
39*67e74705SXin Li for (SmallVectorImpl<CXCursor>::iterator
40*67e74705SXin Li I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
41*67e74705SXin Li getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
42*67e74705SXin Li }
43*67e74705SXin Li
44*67e74705SXin Li namespace {
45*67e74705SXin Li
46*67e74705SXin Li struct FindFileIdRefVisitData {
47*67e74705SXin Li CXTranslationUnit TU;
48*67e74705SXin Li FileID FID;
49*67e74705SXin Li const Decl *Dcl;
50*67e74705SXin Li int SelectorIdIdx;
51*67e74705SXin Li CXCursorAndRangeVisitor visitor;
52*67e74705SXin Li
53*67e74705SXin Li typedef SmallVector<const Decl *, 8> TopMethodsTy;
54*67e74705SXin Li TopMethodsTy TopMethods;
55*67e74705SXin Li
FindFileIdRefVisitData__anone61684520111::FindFileIdRefVisitData56*67e74705SXin Li FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
57*67e74705SXin Li const Decl *D, int selectorIdIdx,
58*67e74705SXin Li CXCursorAndRangeVisitor visitor)
59*67e74705SXin Li : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
60*67e74705SXin Li Dcl = getCanonical(D);
61*67e74705SXin Li getTopOverriddenMethods(TU, Dcl, TopMethods);
62*67e74705SXin Li }
63*67e74705SXin Li
getASTContext__anone61684520111::FindFileIdRefVisitData64*67e74705SXin Li ASTContext &getASTContext() const {
65*67e74705SXin Li return cxtu::getASTUnit(TU)->getASTContext();
66*67e74705SXin Li }
67*67e74705SXin Li
68*67e74705SXin Li /// \brief We are looking to find all semantically relevant identifiers,
69*67e74705SXin Li /// so the definition of "canonical" here is different than in the AST, e.g.
70*67e74705SXin Li ///
71*67e74705SXin Li /// \code
72*67e74705SXin Li /// class C {
73*67e74705SXin Li /// C() {}
74*67e74705SXin Li /// };
75*67e74705SXin Li /// \endcode
76*67e74705SXin Li ///
77*67e74705SXin Li /// we consider the canonical decl of the constructor decl to be the class
78*67e74705SXin Li /// itself, so both 'C' can be highlighted.
getCanonical__anone61684520111::FindFileIdRefVisitData79*67e74705SXin Li const Decl *getCanonical(const Decl *D) const {
80*67e74705SXin Li if (!D)
81*67e74705SXin Li return nullptr;
82*67e74705SXin Li
83*67e74705SXin Li D = D->getCanonicalDecl();
84*67e74705SXin Li
85*67e74705SXin Li if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
86*67e74705SXin Li if (ImplD->getClassInterface())
87*67e74705SXin Li return getCanonical(ImplD->getClassInterface());
88*67e74705SXin Li
89*67e74705SXin Li } else if (const CXXConstructorDecl *CXXCtorD =
90*67e74705SXin Li dyn_cast<CXXConstructorDecl>(D)) {
91*67e74705SXin Li return getCanonical(CXXCtorD->getParent());
92*67e74705SXin Li }
93*67e74705SXin Li
94*67e74705SXin Li return D;
95*67e74705SXin Li }
96*67e74705SXin Li
isHit__anone61684520111::FindFileIdRefVisitData97*67e74705SXin Li bool isHit(const Decl *D) const {
98*67e74705SXin Li if (!D)
99*67e74705SXin Li return false;
100*67e74705SXin Li
101*67e74705SXin Li D = getCanonical(D);
102*67e74705SXin Li if (D == Dcl)
103*67e74705SXin Li return true;
104*67e74705SXin Li
105*67e74705SXin Li if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
106*67e74705SXin Li return isOverriddingMethod(D);
107*67e74705SXin Li
108*67e74705SXin Li return false;
109*67e74705SXin Li }
110*67e74705SXin Li
111*67e74705SXin Li private:
isOverriddingMethod__anone61684520111::FindFileIdRefVisitData112*67e74705SXin Li bool isOverriddingMethod(const Decl *D) const {
113*67e74705SXin Li if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
114*67e74705SXin Li TopMethods.end())
115*67e74705SXin Li return true;
116*67e74705SXin Li
117*67e74705SXin Li TopMethodsTy methods;
118*67e74705SXin Li getTopOverriddenMethods(TU, D, methods);
119*67e74705SXin Li for (TopMethodsTy::iterator
120*67e74705SXin Li I = methods.begin(), E = methods.end(); I != E; ++I) {
121*67e74705SXin Li if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
122*67e74705SXin Li TopMethods.end())
123*67e74705SXin Li return true;
124*67e74705SXin Li }
125*67e74705SXin Li
126*67e74705SXin Li return false;
127*67e74705SXin Li }
128*67e74705SXin Li };
129*67e74705SXin Li
130*67e74705SXin Li } // end anonymous namespace.
131*67e74705SXin Li
132*67e74705SXin Li /// \brief For a macro \arg Loc, returns the file spelling location and sets
133*67e74705SXin Li /// to \arg isMacroArg whether the spelling resides inside a macro definition or
134*67e74705SXin Li /// a macro argument.
getFileSpellingLoc(SourceManager & SM,SourceLocation Loc,bool & isMacroArg)135*67e74705SXin Li static SourceLocation getFileSpellingLoc(SourceManager &SM,
136*67e74705SXin Li SourceLocation Loc,
137*67e74705SXin Li bool &isMacroArg) {
138*67e74705SXin Li assert(Loc.isMacroID());
139*67e74705SXin Li SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
140*67e74705SXin Li if (SpellLoc.isMacroID())
141*67e74705SXin Li return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
142*67e74705SXin Li
143*67e74705SXin Li isMacroArg = SM.isMacroArgExpansion(Loc);
144*67e74705SXin Li return SpellLoc;
145*67e74705SXin Li }
146*67e74705SXin Li
findFileIdRefVisit(CXCursor cursor,CXCursor parent,CXClientData client_data)147*67e74705SXin Li static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
148*67e74705SXin Li CXCursor parent,
149*67e74705SXin Li CXClientData client_data) {
150*67e74705SXin Li CXCursor declCursor = clang_getCursorReferenced(cursor);
151*67e74705SXin Li if (!clang_isDeclaration(declCursor.kind))
152*67e74705SXin Li return CXChildVisit_Recurse;
153*67e74705SXin Li
154*67e74705SXin Li const Decl *D = cxcursor::getCursorDecl(declCursor);
155*67e74705SXin Li if (!D)
156*67e74705SXin Li return CXChildVisit_Continue;
157*67e74705SXin Li
158*67e74705SXin Li FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
159*67e74705SXin Li if (data->isHit(D)) {
160*67e74705SXin Li cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
161*67e74705SXin Li
162*67e74705SXin Li // We are looking for identifiers to highlight so for objc methods (and
163*67e74705SXin Li // not a parameter) we can only highlight the selector identifiers.
164*67e74705SXin Li if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
165*67e74705SXin Li cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
166*67e74705SXin Li cxcursor::getSelectorIdentifierIndex(cursor) == -1)
167*67e74705SXin Li return CXChildVisit_Recurse;
168*67e74705SXin Li
169*67e74705SXin Li if (clang_isExpression(cursor.kind)) {
170*67e74705SXin Li if (cursor.kind == CXCursor_DeclRefExpr ||
171*67e74705SXin Li cursor.kind == CXCursor_MemberRefExpr) {
172*67e74705SXin Li // continue..
173*67e74705SXin Li
174*67e74705SXin Li } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
175*67e74705SXin Li cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
176*67e74705SXin Li // continue..
177*67e74705SXin Li
178*67e74705SXin Li } else
179*67e74705SXin Li return CXChildVisit_Recurse;
180*67e74705SXin Li }
181*67e74705SXin Li
182*67e74705SXin Li SourceLocation
183*67e74705SXin Li Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
184*67e74705SXin Li SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
185*67e74705SXin Li if (SelIdLoc.isValid())
186*67e74705SXin Li Loc = SelIdLoc;
187*67e74705SXin Li
188*67e74705SXin Li ASTContext &Ctx = data->getASTContext();
189*67e74705SXin Li SourceManager &SM = Ctx.getSourceManager();
190*67e74705SXin Li bool isInMacroDef = false;
191*67e74705SXin Li if (Loc.isMacroID()) {
192*67e74705SXin Li bool isMacroArg;
193*67e74705SXin Li Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
194*67e74705SXin Li isInMacroDef = !isMacroArg;
195*67e74705SXin Li }
196*67e74705SXin Li
197*67e74705SXin Li // We are looking for identifiers in a specific file.
198*67e74705SXin Li std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
199*67e74705SXin Li if (LocInfo.first != data->FID)
200*67e74705SXin Li return CXChildVisit_Recurse;
201*67e74705SXin Li
202*67e74705SXin Li if (isInMacroDef) {
203*67e74705SXin Li // FIXME: For a macro definition make sure that all expansions
204*67e74705SXin Li // of it expand to the same reference before allowing to point to it.
205*67e74705SXin Li return CXChildVisit_Recurse;
206*67e74705SXin Li }
207*67e74705SXin Li
208*67e74705SXin Li if (data->visitor.visit(data->visitor.context, cursor,
209*67e74705SXin Li cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
210*67e74705SXin Li return CXChildVisit_Break;
211*67e74705SXin Li }
212*67e74705SXin Li return CXChildVisit_Recurse;
213*67e74705SXin Li }
214*67e74705SXin Li
findIdRefsInFile(CXTranslationUnit TU,CXCursor declCursor,const FileEntry * File,CXCursorAndRangeVisitor Visitor)215*67e74705SXin Li static bool findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
216*67e74705SXin Li const FileEntry *File,
217*67e74705SXin Li CXCursorAndRangeVisitor Visitor) {
218*67e74705SXin Li assert(clang_isDeclaration(declCursor.kind));
219*67e74705SXin Li SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
220*67e74705SXin Li
221*67e74705SXin Li FileID FID = SM.translateFile(File);
222*67e74705SXin Li const Decl *Dcl = cxcursor::getCursorDecl(declCursor);
223*67e74705SXin Li if (!Dcl)
224*67e74705SXin Li return false;
225*67e74705SXin Li
226*67e74705SXin Li FindFileIdRefVisitData data(TU, FID, Dcl,
227*67e74705SXin Li cxcursor::getSelectorIdentifierIndex(declCursor),
228*67e74705SXin Li Visitor);
229*67e74705SXin Li
230*67e74705SXin Li if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
231*67e74705SXin Li return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
232*67e74705SXin Li findFileIdRefVisit, &data);
233*67e74705SXin Li }
234*67e74705SXin Li
235*67e74705SXin Li SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
236*67e74705SXin Li CursorVisitor FindIdRefsVisitor(TU,
237*67e74705SXin Li findFileIdRefVisit, &data,
238*67e74705SXin Li /*VisitPreprocessorLast=*/true,
239*67e74705SXin Li /*VisitIncludedEntities=*/false,
240*67e74705SXin Li Range,
241*67e74705SXin Li /*VisitDeclsOnly=*/true);
242*67e74705SXin Li return FindIdRefsVisitor.visitFileRegion();
243*67e74705SXin Li }
244*67e74705SXin Li
245*67e74705SXin Li namespace {
246*67e74705SXin Li
247*67e74705SXin Li struct FindFileMacroRefVisitData {
248*67e74705SXin Li ASTUnit &Unit;
249*67e74705SXin Li const FileEntry *File;
250*67e74705SXin Li const IdentifierInfo *Macro;
251*67e74705SXin Li CXCursorAndRangeVisitor visitor;
252*67e74705SXin Li
FindFileMacroRefVisitData__anone61684520211::FindFileMacroRefVisitData253*67e74705SXin Li FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File,
254*67e74705SXin Li const IdentifierInfo *Macro,
255*67e74705SXin Li CXCursorAndRangeVisitor visitor)
256*67e74705SXin Li : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
257*67e74705SXin Li
getASTContext__anone61684520211::FindFileMacroRefVisitData258*67e74705SXin Li ASTContext &getASTContext() const {
259*67e74705SXin Li return Unit.getASTContext();
260*67e74705SXin Li }
261*67e74705SXin Li };
262*67e74705SXin Li
263*67e74705SXin Li } // anonymous namespace
264*67e74705SXin Li
findFileMacroRefVisit(CXCursor cursor,CXCursor parent,CXClientData client_data)265*67e74705SXin Li static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
266*67e74705SXin Li CXCursor parent,
267*67e74705SXin Li CXClientData client_data) {
268*67e74705SXin Li const IdentifierInfo *Macro = nullptr;
269*67e74705SXin Li if (cursor.kind == CXCursor_MacroDefinition)
270*67e74705SXin Li Macro = getCursorMacroDefinition(cursor)->getName();
271*67e74705SXin Li else if (cursor.kind == CXCursor_MacroExpansion)
272*67e74705SXin Li Macro = getCursorMacroExpansion(cursor).getName();
273*67e74705SXin Li if (!Macro)
274*67e74705SXin Li return CXChildVisit_Continue;
275*67e74705SXin Li
276*67e74705SXin Li FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
277*67e74705SXin Li if (data->Macro != Macro)
278*67e74705SXin Li return CXChildVisit_Continue;
279*67e74705SXin Li
280*67e74705SXin Li SourceLocation
281*67e74705SXin Li Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
282*67e74705SXin Li
283*67e74705SXin Li ASTContext &Ctx = data->getASTContext();
284*67e74705SXin Li SourceManager &SM = Ctx.getSourceManager();
285*67e74705SXin Li bool isInMacroDef = false;
286*67e74705SXin Li if (Loc.isMacroID()) {
287*67e74705SXin Li bool isMacroArg;
288*67e74705SXin Li Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
289*67e74705SXin Li isInMacroDef = !isMacroArg;
290*67e74705SXin Li }
291*67e74705SXin Li
292*67e74705SXin Li // We are looking for identifiers in a specific file.
293*67e74705SXin Li std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
294*67e74705SXin Li if (SM.getFileEntryForID(LocInfo.first) != data->File)
295*67e74705SXin Li return CXChildVisit_Continue;
296*67e74705SXin Li
297*67e74705SXin Li if (isInMacroDef) {
298*67e74705SXin Li // FIXME: For a macro definition make sure that all expansions
299*67e74705SXin Li // of it expand to the same reference before allowing to point to it.
300*67e74705SXin Li return CXChildVisit_Continue;
301*67e74705SXin Li }
302*67e74705SXin Li
303*67e74705SXin Li if (data->visitor.visit(data->visitor.context, cursor,
304*67e74705SXin Li cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
305*67e74705SXin Li return CXChildVisit_Break;
306*67e74705SXin Li return CXChildVisit_Continue;
307*67e74705SXin Li }
308*67e74705SXin Li
findMacroRefsInFile(CXTranslationUnit TU,CXCursor Cursor,const FileEntry * File,CXCursorAndRangeVisitor Visitor)309*67e74705SXin Li static bool findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
310*67e74705SXin Li const FileEntry *File,
311*67e74705SXin Li CXCursorAndRangeVisitor Visitor) {
312*67e74705SXin Li if (Cursor.kind != CXCursor_MacroDefinition &&
313*67e74705SXin Li Cursor.kind != CXCursor_MacroExpansion)
314*67e74705SXin Li return false;
315*67e74705SXin Li
316*67e74705SXin Li ASTUnit *Unit = cxtu::getASTUnit(TU);
317*67e74705SXin Li SourceManager &SM = Unit->getSourceManager();
318*67e74705SXin Li
319*67e74705SXin Li FileID FID = SM.translateFile(File);
320*67e74705SXin Li const IdentifierInfo *Macro = nullptr;
321*67e74705SXin Li if (Cursor.kind == CXCursor_MacroDefinition)
322*67e74705SXin Li Macro = getCursorMacroDefinition(Cursor)->getName();
323*67e74705SXin Li else
324*67e74705SXin Li Macro = getCursorMacroExpansion(Cursor).getName();
325*67e74705SXin Li if (!Macro)
326*67e74705SXin Li return false;
327*67e74705SXin Li
328*67e74705SXin Li FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
329*67e74705SXin Li
330*67e74705SXin Li SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
331*67e74705SXin Li CursorVisitor FindMacroRefsVisitor(TU,
332*67e74705SXin Li findFileMacroRefVisit, &data,
333*67e74705SXin Li /*VisitPreprocessorLast=*/false,
334*67e74705SXin Li /*VisitIncludedEntities=*/false,
335*67e74705SXin Li Range);
336*67e74705SXin Li return FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
337*67e74705SXin Li }
338*67e74705SXin Li
339*67e74705SXin Li namespace {
340*67e74705SXin Li
341*67e74705SXin Li struct FindFileIncludesVisitor {
342*67e74705SXin Li ASTUnit &Unit;
343*67e74705SXin Li const FileEntry *File;
344*67e74705SXin Li CXCursorAndRangeVisitor visitor;
345*67e74705SXin Li
FindFileIncludesVisitor__anone61684520311::FindFileIncludesVisitor346*67e74705SXin Li FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File,
347*67e74705SXin Li CXCursorAndRangeVisitor visitor)
348*67e74705SXin Li : Unit(Unit), File(File), visitor(visitor) { }
349*67e74705SXin Li
getASTContext__anone61684520311::FindFileIncludesVisitor350*67e74705SXin Li ASTContext &getASTContext() const {
351*67e74705SXin Li return Unit.getASTContext();
352*67e74705SXin Li }
353*67e74705SXin Li
visit__anone61684520311::FindFileIncludesVisitor354*67e74705SXin Li enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) {
355*67e74705SXin Li if (cursor.kind != CXCursor_InclusionDirective)
356*67e74705SXin Li return CXChildVisit_Continue;
357*67e74705SXin Li
358*67e74705SXin Li SourceLocation
359*67e74705SXin Li Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
360*67e74705SXin Li
361*67e74705SXin Li ASTContext &Ctx = getASTContext();
362*67e74705SXin Li SourceManager &SM = Ctx.getSourceManager();
363*67e74705SXin Li
364*67e74705SXin Li // We are looking for includes in a specific file.
365*67e74705SXin Li std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
366*67e74705SXin Li if (SM.getFileEntryForID(LocInfo.first) != File)
367*67e74705SXin Li return CXChildVisit_Continue;
368*67e74705SXin Li
369*67e74705SXin Li if (visitor.visit(visitor.context, cursor,
370*67e74705SXin Li cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
371*67e74705SXin Li return CXChildVisit_Break;
372*67e74705SXin Li return CXChildVisit_Continue;
373*67e74705SXin Li }
374*67e74705SXin Li
visit__anone61684520311::FindFileIncludesVisitor375*67e74705SXin Li static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent,
376*67e74705SXin Li CXClientData client_data) {
377*67e74705SXin Li return static_cast<FindFileIncludesVisitor*>(client_data)->
378*67e74705SXin Li visit(cursor, parent);
379*67e74705SXin Li }
380*67e74705SXin Li };
381*67e74705SXin Li
382*67e74705SXin Li } // anonymous namespace
383*67e74705SXin Li
findIncludesInFile(CXTranslationUnit TU,const FileEntry * File,CXCursorAndRangeVisitor Visitor)384*67e74705SXin Li static bool findIncludesInFile(CXTranslationUnit TU, const FileEntry *File,
385*67e74705SXin Li CXCursorAndRangeVisitor Visitor) {
386*67e74705SXin Li assert(TU && File && Visitor.visit);
387*67e74705SXin Li
388*67e74705SXin Li ASTUnit *Unit = cxtu::getASTUnit(TU);
389*67e74705SXin Li SourceManager &SM = Unit->getSourceManager();
390*67e74705SXin Li
391*67e74705SXin Li FileID FID = SM.translateFile(File);
392*67e74705SXin Li
393*67e74705SXin Li FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor);
394*67e74705SXin Li
395*67e74705SXin Li SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
396*67e74705SXin Li CursorVisitor InclusionCursorsVisitor(TU,
397*67e74705SXin Li FindFileIncludesVisitor::visit,
398*67e74705SXin Li &IncludesVisitor,
399*67e74705SXin Li /*VisitPreprocessorLast=*/false,
400*67e74705SXin Li /*VisitIncludedEntities=*/false,
401*67e74705SXin Li Range);
402*67e74705SXin Li return InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion();
403*67e74705SXin Li }
404*67e74705SXin Li
405*67e74705SXin Li
406*67e74705SXin Li //===----------------------------------------------------------------------===//
407*67e74705SXin Li // libclang public APIs.
408*67e74705SXin Li //===----------------------------------------------------------------------===//
409*67e74705SXin Li
410*67e74705SXin Li extern "C" {
411*67e74705SXin Li
clang_findReferencesInFile(CXCursor cursor,CXFile file,CXCursorAndRangeVisitor visitor)412*67e74705SXin Li CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
413*67e74705SXin Li CXCursorAndRangeVisitor visitor) {
414*67e74705SXin Li LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
415*67e74705SXin Li
416*67e74705SXin Li if (clang_Cursor_isNull(cursor)) {
417*67e74705SXin Li if (Log)
418*67e74705SXin Li *Log << "Null cursor";
419*67e74705SXin Li return CXResult_Invalid;
420*67e74705SXin Li }
421*67e74705SXin Li if (cursor.kind == CXCursor_NoDeclFound) {
422*67e74705SXin Li if (Log)
423*67e74705SXin Li *Log << "Got CXCursor_NoDeclFound";
424*67e74705SXin Li return CXResult_Invalid;
425*67e74705SXin Li }
426*67e74705SXin Li if (!file) {
427*67e74705SXin Li if (Log)
428*67e74705SXin Li *Log << "Null file";
429*67e74705SXin Li return CXResult_Invalid;
430*67e74705SXin Li }
431*67e74705SXin Li if (!visitor.visit) {
432*67e74705SXin Li if (Log)
433*67e74705SXin Li *Log << "Null visitor";
434*67e74705SXin Li return CXResult_Invalid;
435*67e74705SXin Li }
436*67e74705SXin Li
437*67e74705SXin Li if (Log)
438*67e74705SXin Li *Log << cursor << " @" << static_cast<const FileEntry *>(file);
439*67e74705SXin Li
440*67e74705SXin Li ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
441*67e74705SXin Li if (!CXXUnit)
442*67e74705SXin Li return CXResult_Invalid;
443*67e74705SXin Li
444*67e74705SXin Li ASTUnit::ConcurrencyCheck Check(*CXXUnit);
445*67e74705SXin Li
446*67e74705SXin Li if (cursor.kind == CXCursor_MacroDefinition ||
447*67e74705SXin Li cursor.kind == CXCursor_MacroExpansion) {
448*67e74705SXin Li if (findMacroRefsInFile(cxcursor::getCursorTU(cursor),
449*67e74705SXin Li cursor,
450*67e74705SXin Li static_cast<const FileEntry *>(file),
451*67e74705SXin Li visitor))
452*67e74705SXin Li return CXResult_VisitBreak;
453*67e74705SXin Li return CXResult_Success;
454*67e74705SXin Li }
455*67e74705SXin Li
456*67e74705SXin Li // We are interested in semantics of identifiers so for C++ constructor exprs
457*67e74705SXin Li // prefer type references, e.g.:
458*67e74705SXin Li //
459*67e74705SXin Li // return MyStruct();
460*67e74705SXin Li //
461*67e74705SXin Li // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
462*67e74705SXin Li // we are actually interested in the type declaration.
463*67e74705SXin Li cursor = cxcursor::getTypeRefCursor(cursor);
464*67e74705SXin Li
465*67e74705SXin Li CXCursor refCursor = clang_getCursorReferenced(cursor);
466*67e74705SXin Li
467*67e74705SXin Li if (!clang_isDeclaration(refCursor.kind)) {
468*67e74705SXin Li if (Log)
469*67e74705SXin Li *Log << "cursor is not referencing a declaration";
470*67e74705SXin Li return CXResult_Invalid;
471*67e74705SXin Li }
472*67e74705SXin Li
473*67e74705SXin Li if (findIdRefsInFile(cxcursor::getCursorTU(cursor),
474*67e74705SXin Li refCursor,
475*67e74705SXin Li static_cast<const FileEntry *>(file),
476*67e74705SXin Li visitor))
477*67e74705SXin Li return CXResult_VisitBreak;
478*67e74705SXin Li return CXResult_Success;
479*67e74705SXin Li }
480*67e74705SXin Li
clang_findIncludesInFile(CXTranslationUnit TU,CXFile file,CXCursorAndRangeVisitor visitor)481*67e74705SXin Li CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file,
482*67e74705SXin Li CXCursorAndRangeVisitor visitor) {
483*67e74705SXin Li if (cxtu::isNotUsableTU(TU)) {
484*67e74705SXin Li LOG_BAD_TU(TU);
485*67e74705SXin Li return CXResult_Invalid;
486*67e74705SXin Li }
487*67e74705SXin Li
488*67e74705SXin Li LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
489*67e74705SXin Li if (!file) {
490*67e74705SXin Li if (Log)
491*67e74705SXin Li *Log << "Null file";
492*67e74705SXin Li return CXResult_Invalid;
493*67e74705SXin Li }
494*67e74705SXin Li if (!visitor.visit) {
495*67e74705SXin Li if (Log)
496*67e74705SXin Li *Log << "Null visitor";
497*67e74705SXin Li return CXResult_Invalid;
498*67e74705SXin Li }
499*67e74705SXin Li
500*67e74705SXin Li if (Log)
501*67e74705SXin Li *Log << TU << " @" << static_cast<const FileEntry *>(file);
502*67e74705SXin Li
503*67e74705SXin Li ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
504*67e74705SXin Li if (!CXXUnit)
505*67e74705SXin Li return CXResult_Invalid;
506*67e74705SXin Li
507*67e74705SXin Li ASTUnit::ConcurrencyCheck Check(*CXXUnit);
508*67e74705SXin Li
509*67e74705SXin Li if (findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor))
510*67e74705SXin Li return CXResult_VisitBreak;
511*67e74705SXin Li return CXResult_Success;
512*67e74705SXin Li }
513*67e74705SXin Li
_visitCursorAndRange(void * context,CXCursor cursor,CXSourceRange range)514*67e74705SXin Li static enum CXVisitorResult _visitCursorAndRange(void *context,
515*67e74705SXin Li CXCursor cursor,
516*67e74705SXin Li CXSourceRange range) {
517*67e74705SXin Li CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
518*67e74705SXin Li return INVOKE_BLOCK2(block, cursor, range);
519*67e74705SXin Li }
520*67e74705SXin Li
clang_findReferencesInFileWithBlock(CXCursor cursor,CXFile file,CXCursorAndRangeVisitorBlock block)521*67e74705SXin Li CXResult clang_findReferencesInFileWithBlock(CXCursor cursor,
522*67e74705SXin Li CXFile file,
523*67e74705SXin Li CXCursorAndRangeVisitorBlock block) {
524*67e74705SXin Li CXCursorAndRangeVisitor visitor = { block,
525*67e74705SXin Li block ? _visitCursorAndRange : nullptr };
526*67e74705SXin Li return clang_findReferencesInFile(cursor, file, visitor);
527*67e74705SXin Li }
528*67e74705SXin Li
clang_findIncludesInFileWithBlock(CXTranslationUnit TU,CXFile file,CXCursorAndRangeVisitorBlock block)529*67e74705SXin Li CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU,
530*67e74705SXin Li CXFile file,
531*67e74705SXin Li CXCursorAndRangeVisitorBlock block) {
532*67e74705SXin Li CXCursorAndRangeVisitor visitor = { block,
533*67e74705SXin Li block ? _visitCursorAndRange : nullptr };
534*67e74705SXin Li return clang_findIncludesInFile(TU, file, visitor);
535*67e74705SXin Li }
536*67e74705SXin Li
537*67e74705SXin Li } // end: extern "C"
538*67e74705SXin Li
539