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