1 | //===- CIndexInclusionStack.cpp - Clang-C Source Indexing Library ---------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines a callback mechanism for clients to get the inclusion |
10 | // stack from a translation unit. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "CIndexer.h" |
15 | #include "CXFile.h" |
16 | #include "CXSourceLocation.h" |
17 | #include "CXTranslationUnit.h" |
18 | #include "clang/AST/DeclVisitor.h" |
19 | #include "clang/Frontend/ASTUnit.h" |
20 | using namespace clang; |
21 | |
22 | namespace { |
23 | void getInclusions(bool IsLocal, unsigned n, CXTranslationUnit TU, |
24 | CXInclusionVisitor CB, CXClientData clientData) { |
25 | ASTUnit *CXXUnit = cxtu::getASTUnit(TU); |
26 | SourceManager &SM = CXXUnit->getSourceManager(); |
27 | ASTContext &Ctx = CXXUnit->getASTContext(); |
28 | SmallVector<CXSourceLocation, 10> InclusionStack; |
29 | const bool HasPreamble = SM.getPreambleFileID().isValid(); |
30 | |
31 | for (unsigned i = 0 ; i < n ; ++i) { |
32 | bool Invalid = false; |
33 | const SrcMgr::SLocEntry &SL = |
34 | IsLocal ? SM.getLocalSLocEntry(Index: i) : SM.getLoadedSLocEntry(Index: i, Invalid: &Invalid); |
35 | if (!SL.isFile() || Invalid) |
36 | continue; |
37 | |
38 | const SrcMgr::FileInfo &FI = SL.getFile(); |
39 | if (!FI.getContentCache().OrigEntry) |
40 | continue; |
41 | |
42 | // If this is the main file, and there is a preamble, skip this SLoc. The |
43 | // inclusions of the preamble already showed it. |
44 | SourceLocation L = FI.getIncludeLoc(); |
45 | if (HasPreamble && CXXUnit->isInMainFileID(Loc: L)) |
46 | continue; |
47 | |
48 | // Build the inclusion stack. |
49 | InclusionStack.clear(); |
50 | while (L.isValid()) { |
51 | PresumedLoc PLoc = SM.getPresumedLoc(Loc: L); |
52 | InclusionStack.push_back(Elt: cxloc::translateSourceLocation(Context&: Ctx, Loc: L)); |
53 | L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation(); |
54 | } |
55 | |
56 | // If there is a preamble, the last entry is the "inclusion" of that |
57 | // preamble into the main file, which has the bogus entry of main.c:1:1 |
58 | if (HasPreamble && !InclusionStack.empty()) |
59 | InclusionStack.pop_back(); |
60 | |
61 | // Callback to the client. |
62 | CB(cxfile::makeCXFile(FE: *FI.getContentCache().OrigEntry), |
63 | InclusionStack.data(), InclusionStack.size(), clientData); |
64 | } |
65 | } |
66 | } // namespace |
67 | |
68 | void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, |
69 | CXClientData clientData) { |
70 | if (cxtu::isNotUsableTU(TU)) { |
71 | LOG_BAD_TU(TU); |
72 | return; |
73 | } |
74 | |
75 | SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); |
76 | const unsigned n = SM.local_sloc_entry_size(); |
77 | |
78 | // In the case where all the SLocEntries are in an external source, traverse |
79 | // those SLocEntries as well. This is the case where we are looking |
80 | // at the inclusion stack of an AST/PCH file. Also, if we are not looking at |
81 | // a AST/PCH file, but this file has a pre-compiled preamble, we also need |
82 | // to look in that file. |
83 | if (n == 1 || SM.getPreambleFileID().isValid()) { |
84 | getInclusions(/*IsLocal=*/false, n: SM.loaded_sloc_entry_size(), TU, CB, |
85 | clientData); |
86 | } |
87 | |
88 | // Not a PCH/AST file. Note, if there is a preamble, it could still be that |
89 | // there are #includes in this file (e.g. for any include after the first |
90 | // declaration). |
91 | if (n != 1) |
92 | getInclusions(/*IsLocal=*/true, n, TU, CB, clientData); |
93 | } |
94 | |