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