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