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