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