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