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