1e5dd7070Spatrick //===- Indexing.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 "CIndexDiagnostic.h"
10e5dd7070Spatrick #include "CIndexer.h"
11e5dd7070Spatrick #include "CLog.h"
12e5dd7070Spatrick #include "CXCursor.h"
13e5dd7070Spatrick #include "CXIndexDataConsumer.h"
14e5dd7070Spatrick #include "CXSourceLocation.h"
15e5dd7070Spatrick #include "CXString.h"
16e5dd7070Spatrick #include "CXTranslationUnit.h"
17e5dd7070Spatrick #include "clang/AST/ASTConsumer.h"
18e5dd7070Spatrick #include "clang/Frontend/ASTUnit.h"
19e5dd7070Spatrick #include "clang/Frontend/CompilerInstance.h"
20e5dd7070Spatrick #include "clang/Frontend/CompilerInvocation.h"
21e5dd7070Spatrick #include "clang/Frontend/FrontendAction.h"
22e5dd7070Spatrick #include "clang/Frontend/MultiplexConsumer.h"
23e5dd7070Spatrick #include "clang/Frontend/Utils.h"
24e5dd7070Spatrick #include "clang/Index/IndexingAction.h"
25e5dd7070Spatrick #include "clang/Lex/HeaderSearch.h"
26e5dd7070Spatrick #include "clang/Lex/PPCallbacks.h"
27e5dd7070Spatrick #include "clang/Lex/PPConditionalDirectiveRecord.h"
28e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
29e5dd7070Spatrick #include "clang/Lex/PreprocessorOptions.h"
30e5dd7070Spatrick #include "llvm/Support/CrashRecoveryContext.h"
31e5dd7070Spatrick #include "llvm/Support/MemoryBuffer.h"
32e5dd7070Spatrick #include <cstdio>
33e5dd7070Spatrick #include <mutex>
34e5dd7070Spatrick #include <utility>
35e5dd7070Spatrick
36e5dd7070Spatrick using namespace clang;
37e5dd7070Spatrick using namespace clang::index;
38e5dd7070Spatrick using namespace cxtu;
39e5dd7070Spatrick using namespace cxindex;
40e5dd7070Spatrick
41e5dd7070Spatrick namespace {
42e5dd7070Spatrick
43e5dd7070Spatrick //===----------------------------------------------------------------------===//
44e5dd7070Spatrick // Skip Parsed Bodies
45e5dd7070Spatrick //===----------------------------------------------------------------------===//
46e5dd7070Spatrick
47e5dd7070Spatrick /// A "region" in source code identified by the file/offset of the
48e5dd7070Spatrick /// preprocessor conditional directive that it belongs to.
49e5dd7070Spatrick /// Multiple, non-consecutive ranges can be parts of the same region.
50e5dd7070Spatrick ///
51e5dd7070Spatrick /// As an example of different regions separated by preprocessor directives:
52e5dd7070Spatrick ///
53e5dd7070Spatrick /// \code
54e5dd7070Spatrick /// #1
55e5dd7070Spatrick /// #ifdef BLAH
56e5dd7070Spatrick /// #2
57e5dd7070Spatrick /// #ifdef CAKE
58e5dd7070Spatrick /// #3
59e5dd7070Spatrick /// #endif
60e5dd7070Spatrick /// #2
61e5dd7070Spatrick /// #endif
62e5dd7070Spatrick /// #1
63e5dd7070Spatrick /// \endcode
64e5dd7070Spatrick ///
65e5dd7070Spatrick /// There are 3 regions, with non-consecutive parts:
66e5dd7070Spatrick /// #1 is identified as the beginning of the file
67e5dd7070Spatrick /// #2 is identified as the location of "#ifdef BLAH"
68e5dd7070Spatrick /// #3 is identified as the location of "#ifdef CAKE"
69e5dd7070Spatrick ///
70e5dd7070Spatrick class PPRegion {
71e5dd7070Spatrick llvm::sys::fs::UniqueID UniqueID;
72e5dd7070Spatrick time_t ModTime;
73e5dd7070Spatrick unsigned Offset;
74e5dd7070Spatrick public:
PPRegion()75e5dd7070Spatrick PPRegion() : UniqueID(0, 0), ModTime(), Offset() {}
PPRegion(llvm::sys::fs::UniqueID UniqueID,unsigned offset,time_t modTime)76e5dd7070Spatrick PPRegion(llvm::sys::fs::UniqueID UniqueID, unsigned offset, time_t modTime)
77e5dd7070Spatrick : UniqueID(UniqueID), ModTime(modTime), Offset(offset) {}
78e5dd7070Spatrick
getUniqueID() const79e5dd7070Spatrick const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
getOffset() const80e5dd7070Spatrick unsigned getOffset() const { return Offset; }
getModTime() const81e5dd7070Spatrick time_t getModTime() const { return ModTime; }
82e5dd7070Spatrick
isInvalid() const83e5dd7070Spatrick bool isInvalid() const { return *this == PPRegion(); }
84e5dd7070Spatrick
operator ==(const PPRegion & lhs,const PPRegion & rhs)85e5dd7070Spatrick friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) {
86e5dd7070Spatrick return lhs.UniqueID == rhs.UniqueID && lhs.Offset == rhs.Offset &&
87e5dd7070Spatrick lhs.ModTime == rhs.ModTime;
88e5dd7070Spatrick }
89e5dd7070Spatrick };
90e5dd7070Spatrick
91e5dd7070Spatrick } // end anonymous namespace
92e5dd7070Spatrick
93e5dd7070Spatrick namespace llvm {
94e5dd7070Spatrick
95e5dd7070Spatrick template <>
96e5dd7070Spatrick struct DenseMapInfo<PPRegion> {
getEmptyKeyllvm::DenseMapInfo97e5dd7070Spatrick static inline PPRegion getEmptyKey() {
98e5dd7070Spatrick return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-1), 0);
99e5dd7070Spatrick }
getTombstoneKeyllvm::DenseMapInfo100e5dd7070Spatrick static inline PPRegion getTombstoneKey() {
101e5dd7070Spatrick return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-2), 0);
102e5dd7070Spatrick }
103e5dd7070Spatrick
getHashValuellvm::DenseMapInfo104e5dd7070Spatrick static unsigned getHashValue(const PPRegion &S) {
105e5dd7070Spatrick llvm::FoldingSetNodeID ID;
106e5dd7070Spatrick const llvm::sys::fs::UniqueID &UniqueID = S.getUniqueID();
107e5dd7070Spatrick ID.AddInteger(UniqueID.getFile());
108e5dd7070Spatrick ID.AddInteger(UniqueID.getDevice());
109e5dd7070Spatrick ID.AddInteger(S.getOffset());
110e5dd7070Spatrick ID.AddInteger(S.getModTime());
111e5dd7070Spatrick return ID.ComputeHash();
112e5dd7070Spatrick }
113e5dd7070Spatrick
isEqualllvm::DenseMapInfo114e5dd7070Spatrick static bool isEqual(const PPRegion &LHS, const PPRegion &RHS) {
115e5dd7070Spatrick return LHS == RHS;
116e5dd7070Spatrick }
117e5dd7070Spatrick };
118e5dd7070Spatrick }
119e5dd7070Spatrick
120e5dd7070Spatrick namespace {
121e5dd7070Spatrick
122e5dd7070Spatrick /// Keeps track of function bodies that have already been parsed.
123e5dd7070Spatrick ///
124e5dd7070Spatrick /// Is thread-safe.
125e5dd7070Spatrick class ThreadSafeParsedRegions {
126e5dd7070Spatrick mutable std::mutex Mutex;
127e5dd7070Spatrick llvm::DenseSet<PPRegion> ParsedRegions;
128e5dd7070Spatrick
129e5dd7070Spatrick public:
130e5dd7070Spatrick ~ThreadSafeParsedRegions() = default;
131e5dd7070Spatrick
getParsedRegions() const132e5dd7070Spatrick llvm::DenseSet<PPRegion> getParsedRegions() const {
133e5dd7070Spatrick std::lock_guard<std::mutex> MG(Mutex);
134e5dd7070Spatrick return ParsedRegions;
135e5dd7070Spatrick }
136e5dd7070Spatrick
addParsedRegions(ArrayRef<PPRegion> Regions)137e5dd7070Spatrick void addParsedRegions(ArrayRef<PPRegion> Regions) {
138e5dd7070Spatrick std::lock_guard<std::mutex> MG(Mutex);
139e5dd7070Spatrick ParsedRegions.insert(Regions.begin(), Regions.end());
140e5dd7070Spatrick }
141e5dd7070Spatrick };
142e5dd7070Spatrick
143e5dd7070Spatrick /// Provides information whether source locations have already been parsed in
144e5dd7070Spatrick /// another FrontendAction.
145e5dd7070Spatrick ///
146e5dd7070Spatrick /// Is NOT thread-safe.
147e5dd7070Spatrick class ParsedSrcLocationsTracker {
148e5dd7070Spatrick ThreadSafeParsedRegions &ParsedRegionsStorage;
149e5dd7070Spatrick PPConditionalDirectiveRecord &PPRec;
150e5dd7070Spatrick Preprocessor &PP;
151e5dd7070Spatrick
152e5dd7070Spatrick /// Snapshot of the shared state at the point when this instance was
153e5dd7070Spatrick /// constructed.
154e5dd7070Spatrick llvm::DenseSet<PPRegion> ParsedRegionsSnapshot;
155e5dd7070Spatrick /// Regions that were queried during this instance lifetime.
156e5dd7070Spatrick SmallVector<PPRegion, 32> NewParsedRegions;
157e5dd7070Spatrick
158e5dd7070Spatrick /// Caching the last queried region.
159e5dd7070Spatrick PPRegion LastRegion;
160e5dd7070Spatrick bool LastIsParsed;
161e5dd7070Spatrick
162e5dd7070Spatrick public:
163e5dd7070Spatrick /// Creates snapshot of \p ParsedRegionsStorage.
ParsedSrcLocationsTracker(ThreadSafeParsedRegions & ParsedRegionsStorage,PPConditionalDirectiveRecord & ppRec,Preprocessor & pp)164e5dd7070Spatrick ParsedSrcLocationsTracker(ThreadSafeParsedRegions &ParsedRegionsStorage,
165e5dd7070Spatrick PPConditionalDirectiveRecord &ppRec,
166e5dd7070Spatrick Preprocessor &pp)
167e5dd7070Spatrick : ParsedRegionsStorage(ParsedRegionsStorage), PPRec(ppRec), PP(pp),
168e5dd7070Spatrick ParsedRegionsSnapshot(ParsedRegionsStorage.getParsedRegions()) {}
169e5dd7070Spatrick
170e5dd7070Spatrick /// \returns true iff \p Loc has already been parsed.
171e5dd7070Spatrick ///
172e5dd7070Spatrick /// Can provide false-negative in case the location was parsed after this
173e5dd7070Spatrick /// instance had been constructed.
hasAlredyBeenParsed(SourceLocation Loc,FileID FID,const FileEntry * FE)174e5dd7070Spatrick bool hasAlredyBeenParsed(SourceLocation Loc, FileID FID,
175e5dd7070Spatrick const FileEntry *FE) {
176e5dd7070Spatrick assert(FE);
177e5dd7070Spatrick PPRegion region = getRegion(Loc, FID, FE);
178e5dd7070Spatrick if (region.isInvalid())
179e5dd7070Spatrick return false;
180e5dd7070Spatrick
181e5dd7070Spatrick // Check common case, consecutive functions in the same region.
182e5dd7070Spatrick if (LastRegion == region)
183e5dd7070Spatrick return LastIsParsed;
184e5dd7070Spatrick
185e5dd7070Spatrick LastRegion = region;
186e5dd7070Spatrick // Source locations can't be revisited during single TU parsing.
187e5dd7070Spatrick // That means if we hit the same region again, it's a different location in
188e5dd7070Spatrick // the same region and so the "is parsed" value from the snapshot is still
189e5dd7070Spatrick // correct.
190e5dd7070Spatrick LastIsParsed = ParsedRegionsSnapshot.count(region);
191e5dd7070Spatrick if (!LastIsParsed)
192e5dd7070Spatrick NewParsedRegions.emplace_back(std::move(region));
193e5dd7070Spatrick return LastIsParsed;
194e5dd7070Spatrick }
195e5dd7070Spatrick
196e5dd7070Spatrick /// Updates ParsedRegionsStorage with newly parsed regions.
syncWithStorage()197e5dd7070Spatrick void syncWithStorage() {
198e5dd7070Spatrick ParsedRegionsStorage.addParsedRegions(NewParsedRegions);
199e5dd7070Spatrick }
200e5dd7070Spatrick
201e5dd7070Spatrick private:
getRegion(SourceLocation Loc,FileID FID,const FileEntry * FE)202e5dd7070Spatrick PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) {
203e5dd7070Spatrick assert(FE);
204e5dd7070Spatrick auto Bail = [this, FE]() {
205e5dd7070Spatrick if (isParsedOnceInclude(FE)) {
206e5dd7070Spatrick const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
207e5dd7070Spatrick return PPRegion(ID, 0, FE->getModificationTime());
208e5dd7070Spatrick }
209e5dd7070Spatrick return PPRegion();
210e5dd7070Spatrick };
211e5dd7070Spatrick
212e5dd7070Spatrick SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc);
213e5dd7070Spatrick assert(RegionLoc.isFileID());
214e5dd7070Spatrick if (RegionLoc.isInvalid())
215e5dd7070Spatrick return Bail();
216e5dd7070Spatrick
217e5dd7070Spatrick FileID RegionFID;
218e5dd7070Spatrick unsigned RegionOffset;
219e5dd7070Spatrick std::tie(RegionFID, RegionOffset) =
220e5dd7070Spatrick PPRec.getSourceManager().getDecomposedLoc(RegionLoc);
221e5dd7070Spatrick
222e5dd7070Spatrick if (RegionFID != FID)
223e5dd7070Spatrick return Bail();
224e5dd7070Spatrick
225e5dd7070Spatrick const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
226e5dd7070Spatrick return PPRegion(ID, RegionOffset, FE->getModificationTime());
227e5dd7070Spatrick }
228e5dd7070Spatrick
isParsedOnceInclude(const FileEntry * FE)229e5dd7070Spatrick bool isParsedOnceInclude(const FileEntry *FE) {
230ec727ea7Spatrick return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE) ||
231ec727ea7Spatrick PP.getHeaderSearchInfo().hasFileBeenImported(FE);
232e5dd7070Spatrick }
233e5dd7070Spatrick };
234e5dd7070Spatrick
235e5dd7070Spatrick //===----------------------------------------------------------------------===//
236e5dd7070Spatrick // IndexPPCallbacks
237e5dd7070Spatrick //===----------------------------------------------------------------------===//
238e5dd7070Spatrick
239e5dd7070Spatrick class IndexPPCallbacks : public PPCallbacks {
240e5dd7070Spatrick Preprocessor &PP;
241e5dd7070Spatrick CXIndexDataConsumer &DataConsumer;
242e5dd7070Spatrick bool IsMainFileEntered;
243e5dd7070Spatrick
244e5dd7070Spatrick public:
IndexPPCallbacks(Preprocessor & PP,CXIndexDataConsumer & dataConsumer)245e5dd7070Spatrick IndexPPCallbacks(Preprocessor &PP, CXIndexDataConsumer &dataConsumer)
246e5dd7070Spatrick : PP(PP), DataConsumer(dataConsumer), IsMainFileEntered(false) { }
247e5dd7070Spatrick
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)248e5dd7070Spatrick void FileChanged(SourceLocation Loc, FileChangeReason Reason,
249e5dd7070Spatrick SrcMgr::CharacteristicKind FileType, FileID PrevFID) override {
250e5dd7070Spatrick if (IsMainFileEntered)
251e5dd7070Spatrick return;
252e5dd7070Spatrick
253e5dd7070Spatrick SourceManager &SM = PP.getSourceManager();
254e5dd7070Spatrick SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID());
255e5dd7070Spatrick
256e5dd7070Spatrick if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) {
257e5dd7070Spatrick IsMainFileEntered = true;
258e5dd7070Spatrick DataConsumer.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID()));
259e5dd7070Spatrick }
260e5dd7070Spatrick }
261e5dd7070Spatrick
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)262e5dd7070Spatrick void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
263e5dd7070Spatrick StringRef FileName, bool IsAngled,
264*12c85518Srobert CharSourceRange FilenameRange,
265*12c85518Srobert OptionalFileEntryRef File, StringRef SearchPath,
266*12c85518Srobert StringRef RelativePath, const Module *Imported,
267e5dd7070Spatrick SrcMgr::CharacteristicKind FileType) override {
268e5dd7070Spatrick bool isImport = (IncludeTok.is(tok::identifier) &&
269e5dd7070Spatrick IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
270e5dd7070Spatrick DataConsumer.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled,
271e5dd7070Spatrick Imported);
272e5dd7070Spatrick }
273e5dd7070Spatrick
274e5dd7070Spatrick /// MacroDefined - This hook is called whenever a macro definition is seen.
MacroDefined(const Token & Id,const MacroDirective * MD)275e5dd7070Spatrick void MacroDefined(const Token &Id, const MacroDirective *MD) override {}
276e5dd7070Spatrick
277e5dd7070Spatrick /// MacroUndefined - This hook is called whenever a macro #undef is seen.
278e5dd7070Spatrick /// MI is released immediately following this callback.
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * UD)279e5dd7070Spatrick void MacroUndefined(const Token &MacroNameTok,
280e5dd7070Spatrick const MacroDefinition &MD,
281e5dd7070Spatrick const MacroDirective *UD) override {}
282e5dd7070Spatrick
283e5dd7070Spatrick /// MacroExpands - This is called by when a macro invocation is found.
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)284e5dd7070Spatrick void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
285e5dd7070Spatrick SourceRange Range, const MacroArgs *Args) override {}
286e5dd7070Spatrick
287e5dd7070Spatrick /// SourceRangeSkipped - This hook is called when a source range is skipped.
288e5dd7070Spatrick /// \param Range The SourceRange that was skipped. The range begins at the
289e5dd7070Spatrick /// #if/#else directive and ends after the #endif/#else directive.
SourceRangeSkipped(SourceRange Range,SourceLocation EndifLoc)290e5dd7070Spatrick void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override {
291e5dd7070Spatrick }
292e5dd7070Spatrick };
293e5dd7070Spatrick
294e5dd7070Spatrick //===----------------------------------------------------------------------===//
295e5dd7070Spatrick // IndexingConsumer
296e5dd7070Spatrick //===----------------------------------------------------------------------===//
297e5dd7070Spatrick
298e5dd7070Spatrick class IndexingConsumer : public ASTConsumer {
299e5dd7070Spatrick CXIndexDataConsumer &DataConsumer;
300e5dd7070Spatrick
301e5dd7070Spatrick public:
IndexingConsumer(CXIndexDataConsumer & dataConsumer,ParsedSrcLocationsTracker * parsedLocsTracker)302e5dd7070Spatrick IndexingConsumer(CXIndexDataConsumer &dataConsumer,
303e5dd7070Spatrick ParsedSrcLocationsTracker *parsedLocsTracker)
304e5dd7070Spatrick : DataConsumer(dataConsumer) {}
305e5dd7070Spatrick
Initialize(ASTContext & Context)306e5dd7070Spatrick void Initialize(ASTContext &Context) override {
307e5dd7070Spatrick DataConsumer.setASTContext(Context);
308e5dd7070Spatrick DataConsumer.startedTranslationUnit();
309e5dd7070Spatrick }
310e5dd7070Spatrick
HandleTopLevelDecl(DeclGroupRef DG)311e5dd7070Spatrick bool HandleTopLevelDecl(DeclGroupRef DG) override {
312e5dd7070Spatrick return !DataConsumer.shouldAbort();
313e5dd7070Spatrick }
314e5dd7070Spatrick };
315e5dd7070Spatrick
316e5dd7070Spatrick //===----------------------------------------------------------------------===//
317e5dd7070Spatrick // CaptureDiagnosticConsumer
318e5dd7070Spatrick //===----------------------------------------------------------------------===//
319e5dd7070Spatrick
320e5dd7070Spatrick class CaptureDiagnosticConsumer : public DiagnosticConsumer {
321e5dd7070Spatrick SmallVector<StoredDiagnostic, 4> Errors;
322e5dd7070Spatrick public:
323e5dd7070Spatrick
HandleDiagnostic(DiagnosticsEngine::Level level,const Diagnostic & Info)324e5dd7070Spatrick void HandleDiagnostic(DiagnosticsEngine::Level level,
325e5dd7070Spatrick const Diagnostic &Info) override {
326e5dd7070Spatrick if (level >= DiagnosticsEngine::Error)
327e5dd7070Spatrick Errors.push_back(StoredDiagnostic(level, Info));
328e5dd7070Spatrick }
329e5dd7070Spatrick };
330e5dd7070Spatrick
331e5dd7070Spatrick //===----------------------------------------------------------------------===//
332e5dd7070Spatrick // IndexingFrontendAction
333e5dd7070Spatrick //===----------------------------------------------------------------------===//
334e5dd7070Spatrick
335e5dd7070Spatrick class IndexingFrontendAction : public ASTFrontendAction {
336e5dd7070Spatrick std::shared_ptr<CXIndexDataConsumer> DataConsumer;
337e5dd7070Spatrick IndexingOptions Opts;
338e5dd7070Spatrick
339e5dd7070Spatrick ThreadSafeParsedRegions *SKData;
340e5dd7070Spatrick std::unique_ptr<ParsedSrcLocationsTracker> ParsedLocsTracker;
341e5dd7070Spatrick
342e5dd7070Spatrick public:
IndexingFrontendAction(std::shared_ptr<CXIndexDataConsumer> dataConsumer,const IndexingOptions & Opts,ThreadSafeParsedRegions * skData)343e5dd7070Spatrick IndexingFrontendAction(std::shared_ptr<CXIndexDataConsumer> dataConsumer,
344e5dd7070Spatrick const IndexingOptions &Opts,
345e5dd7070Spatrick ThreadSafeParsedRegions *skData)
346e5dd7070Spatrick : DataConsumer(std::move(dataConsumer)), Opts(Opts), SKData(skData) {}
347e5dd7070Spatrick
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)348e5dd7070Spatrick std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
349e5dd7070Spatrick StringRef InFile) override {
350e5dd7070Spatrick PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
351e5dd7070Spatrick
352e5dd7070Spatrick if (!PPOpts.ImplicitPCHInclude.empty()) {
353e5dd7070Spatrick auto File = CI.getFileManager().getFile(PPOpts.ImplicitPCHInclude);
354e5dd7070Spatrick if (File)
355e5dd7070Spatrick DataConsumer->importedPCH(*File);
356e5dd7070Spatrick }
357e5dd7070Spatrick
358e5dd7070Spatrick DataConsumer->setASTContext(CI.getASTContext());
359e5dd7070Spatrick Preprocessor &PP = CI.getPreprocessor();
360e5dd7070Spatrick PP.addPPCallbacks(std::make_unique<IndexPPCallbacks>(PP, *DataConsumer));
361e5dd7070Spatrick DataConsumer->setPreprocessor(CI.getPreprocessorPtr());
362e5dd7070Spatrick
363e5dd7070Spatrick if (SKData) {
364e5dd7070Spatrick auto *PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager());
365e5dd7070Spatrick PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
366e5dd7070Spatrick ParsedLocsTracker =
367e5dd7070Spatrick std::make_unique<ParsedSrcLocationsTracker>(*SKData, *PPRec, PP);
368e5dd7070Spatrick }
369e5dd7070Spatrick
370e5dd7070Spatrick std::vector<std::unique_ptr<ASTConsumer>> Consumers;
371e5dd7070Spatrick Consumers.push_back(std::make_unique<IndexingConsumer>(
372e5dd7070Spatrick *DataConsumer, ParsedLocsTracker.get()));
373e5dd7070Spatrick Consumers.push_back(createIndexingASTConsumer(
374e5dd7070Spatrick DataConsumer, Opts, CI.getPreprocessorPtr(),
375e5dd7070Spatrick [this](const Decl *D) { return this->shouldSkipFunctionBody(D); }));
376e5dd7070Spatrick return std::make_unique<MultiplexConsumer>(std::move(Consumers));
377e5dd7070Spatrick }
378e5dd7070Spatrick
shouldSkipFunctionBody(const Decl * D)379e5dd7070Spatrick bool shouldSkipFunctionBody(const Decl *D) {
380e5dd7070Spatrick if (!ParsedLocsTracker) {
381e5dd7070Spatrick // Always skip bodies.
382e5dd7070Spatrick return true;
383e5dd7070Spatrick }
384e5dd7070Spatrick
385e5dd7070Spatrick const SourceManager &SM = D->getASTContext().getSourceManager();
386e5dd7070Spatrick SourceLocation Loc = D->getLocation();
387e5dd7070Spatrick if (Loc.isMacroID())
388e5dd7070Spatrick return false;
389e5dd7070Spatrick if (SM.isInSystemHeader(Loc))
390e5dd7070Spatrick return true; // always skip bodies from system headers.
391e5dd7070Spatrick
392e5dd7070Spatrick FileID FID;
393e5dd7070Spatrick unsigned Offset;
394e5dd7070Spatrick std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
395e5dd7070Spatrick // Don't skip bodies from main files; this may be revisited.
396e5dd7070Spatrick if (SM.getMainFileID() == FID)
397e5dd7070Spatrick return false;
398e5dd7070Spatrick const FileEntry *FE = SM.getFileEntryForID(FID);
399e5dd7070Spatrick if (!FE)
400e5dd7070Spatrick return false;
401e5dd7070Spatrick
402e5dd7070Spatrick return ParsedLocsTracker->hasAlredyBeenParsed(Loc, FID, FE);
403e5dd7070Spatrick }
404e5dd7070Spatrick
getTranslationUnitKind()405e5dd7070Spatrick TranslationUnitKind getTranslationUnitKind() override {
406e5dd7070Spatrick if (DataConsumer->shouldIndexImplicitTemplateInsts())
407e5dd7070Spatrick return TU_Complete;
408e5dd7070Spatrick else
409e5dd7070Spatrick return TU_Prefix;
410e5dd7070Spatrick }
hasCodeCompletionSupport() const411e5dd7070Spatrick bool hasCodeCompletionSupport() const override { return false; }
412e5dd7070Spatrick
EndSourceFileAction()413e5dd7070Spatrick void EndSourceFileAction() override {
414e5dd7070Spatrick if (ParsedLocsTracker)
415e5dd7070Spatrick ParsedLocsTracker->syncWithStorage();
416e5dd7070Spatrick }
417e5dd7070Spatrick };
418e5dd7070Spatrick
419e5dd7070Spatrick //===----------------------------------------------------------------------===//
420e5dd7070Spatrick // clang_indexSourceFileUnit Implementation
421e5dd7070Spatrick //===----------------------------------------------------------------------===//
422e5dd7070Spatrick
getIndexingOptionsFromCXOptions(unsigned index_options)423e5dd7070Spatrick static IndexingOptions getIndexingOptionsFromCXOptions(unsigned index_options) {
424e5dd7070Spatrick IndexingOptions IdxOpts;
425e5dd7070Spatrick if (index_options & CXIndexOpt_IndexFunctionLocalSymbols)
426e5dd7070Spatrick IdxOpts.IndexFunctionLocals = true;
427e5dd7070Spatrick if (index_options & CXIndexOpt_IndexImplicitTemplateInstantiations)
428e5dd7070Spatrick IdxOpts.IndexImplicitInstantiation = true;
429e5dd7070Spatrick return IdxOpts;
430e5dd7070Spatrick }
431e5dd7070Spatrick
432e5dd7070Spatrick struct IndexSessionData {
433e5dd7070Spatrick CXIndex CIdx;
434e5dd7070Spatrick std::unique_ptr<ThreadSafeParsedRegions> SkipBodyData =
435e5dd7070Spatrick std::make_unique<ThreadSafeParsedRegions>();
436e5dd7070Spatrick
IndexSessionData__anon3007734c0211::IndexSessionData437e5dd7070Spatrick explicit IndexSessionData(CXIndex cIdx) : CIdx(cIdx) {}
438e5dd7070Spatrick };
439e5dd7070Spatrick
440e5dd7070Spatrick } // anonymous namespace
441e5dd7070Spatrick
clang_indexSourceFile_Impl(CXIndexAction cxIdxAction,CXClientData client_data,IndexerCallbacks * client_index_callbacks,unsigned index_callbacks_size,unsigned index_options,const char * source_filename,const char * const * command_line_args,int num_command_line_args,ArrayRef<CXUnsavedFile> unsaved_files,CXTranslationUnit * out_TU,unsigned TU_options)442e5dd7070Spatrick static CXErrorCode clang_indexSourceFile_Impl(
443e5dd7070Spatrick CXIndexAction cxIdxAction, CXClientData client_data,
444e5dd7070Spatrick IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size,
445e5dd7070Spatrick unsigned index_options, const char *source_filename,
446e5dd7070Spatrick const char *const *command_line_args, int num_command_line_args,
447e5dd7070Spatrick ArrayRef<CXUnsavedFile> unsaved_files, CXTranslationUnit *out_TU,
448e5dd7070Spatrick unsigned TU_options) {
449e5dd7070Spatrick if (out_TU)
450e5dd7070Spatrick *out_TU = nullptr;
451e5dd7070Spatrick bool requestedToGetTU = (out_TU != nullptr);
452e5dd7070Spatrick
453e5dd7070Spatrick if (!cxIdxAction) {
454e5dd7070Spatrick return CXError_InvalidArguments;
455e5dd7070Spatrick }
456e5dd7070Spatrick if (!client_index_callbacks || index_callbacks_size == 0) {
457e5dd7070Spatrick return CXError_InvalidArguments;
458e5dd7070Spatrick }
459e5dd7070Spatrick
460e5dd7070Spatrick IndexerCallbacks CB;
461e5dd7070Spatrick memset(&CB, 0, sizeof(CB));
462e5dd7070Spatrick unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
463e5dd7070Spatrick ? index_callbacks_size : sizeof(CB);
464e5dd7070Spatrick memcpy(&CB, client_index_callbacks, ClientCBSize);
465e5dd7070Spatrick
466e5dd7070Spatrick IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction);
467e5dd7070Spatrick CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx);
468e5dd7070Spatrick
469e5dd7070Spatrick if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
470e5dd7070Spatrick setThreadBackgroundPriority();
471e5dd7070Spatrick
472e5dd7070Spatrick CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All;
473e5dd7070Spatrick if (TU_options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles)
474e5dd7070Spatrick CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes;
475e5dd7070Spatrick if (Logger::isLoggingEnabled())
476e5dd7070Spatrick CaptureDiagnostics = CaptureDiagsKind::None;
477e5dd7070Spatrick
478e5dd7070Spatrick CaptureDiagnosticConsumer *CaptureDiag = nullptr;
479e5dd7070Spatrick if (CaptureDiagnostics != CaptureDiagsKind::None)
480e5dd7070Spatrick CaptureDiag = new CaptureDiagnosticConsumer();
481e5dd7070Spatrick
482e5dd7070Spatrick // Configure the diagnostics.
483e5dd7070Spatrick IntrusiveRefCntPtr<DiagnosticsEngine>
484e5dd7070Spatrick Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
485e5dd7070Spatrick CaptureDiag,
486e5dd7070Spatrick /*ShouldOwnClient=*/true));
487e5dd7070Spatrick
488e5dd7070Spatrick // Recover resources if we crash before exiting this function.
489e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
490e5dd7070Spatrick llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
491e5dd7070Spatrick DiagCleanup(Diags.get());
492e5dd7070Spatrick
493e5dd7070Spatrick std::unique_ptr<std::vector<const char *>> Args(
494e5dd7070Spatrick new std::vector<const char *>());
495e5dd7070Spatrick
496e5dd7070Spatrick // Recover resources if we crash before exiting this method.
497e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
498e5dd7070Spatrick ArgsCleanup(Args.get());
499e5dd7070Spatrick
500e5dd7070Spatrick Args->insert(Args->end(), command_line_args,
501e5dd7070Spatrick command_line_args + num_command_line_args);
502e5dd7070Spatrick
503e5dd7070Spatrick // The 'source_filename' argument is optional. If the caller does not
504e5dd7070Spatrick // specify it then it is assumed that the source file is specified
505e5dd7070Spatrick // in the actual argument list.
506e5dd7070Spatrick // Put the source file after command_line_args otherwise if '-x' flag is
507e5dd7070Spatrick // present it will be unused.
508e5dd7070Spatrick if (source_filename)
509e5dd7070Spatrick Args->push_back(source_filename);
510e5dd7070Spatrick
511*12c85518Srobert CreateInvocationOptions CIOpts;
512*12c85518Srobert CIOpts.Diags = Diags;
513*12c85518Srobert CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
514e5dd7070Spatrick std::shared_ptr<CompilerInvocation> CInvok =
515*12c85518Srobert createInvocation(*Args, std::move(CIOpts));
516e5dd7070Spatrick
517e5dd7070Spatrick if (!CInvok)
518e5dd7070Spatrick return CXError_Failure;
519e5dd7070Spatrick
520e5dd7070Spatrick // Recover resources if we crash before exiting this function.
521e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<
522e5dd7070Spatrick std::shared_ptr<CompilerInvocation>,
523e5dd7070Spatrick llvm::CrashRecoveryContextDestructorCleanup<
524e5dd7070Spatrick std::shared_ptr<CompilerInvocation>>>
525e5dd7070Spatrick CInvokCleanup(&CInvok);
526e5dd7070Spatrick
527e5dd7070Spatrick if (CInvok->getFrontendOpts().Inputs.empty())
528e5dd7070Spatrick return CXError_Failure;
529e5dd7070Spatrick
530e5dd7070Spatrick typedef SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 8> MemBufferOwner;
531e5dd7070Spatrick std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner);
532e5dd7070Spatrick
533e5dd7070Spatrick // Recover resources if we crash before exiting this method.
534e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup(
535e5dd7070Spatrick BufOwner.get());
536e5dd7070Spatrick
537e5dd7070Spatrick for (auto &UF : unsaved_files) {
538e5dd7070Spatrick std::unique_ptr<llvm::MemoryBuffer> MB =
539e5dd7070Spatrick llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
540e5dd7070Spatrick CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get());
541e5dd7070Spatrick BufOwner->push_back(std::move(MB));
542e5dd7070Spatrick }
543e5dd7070Spatrick
544e5dd7070Spatrick // Since libclang is primarily used by batch tools dealing with
545e5dd7070Spatrick // (often very broken) source code, where spell-checking can have a
546e5dd7070Spatrick // significant negative impact on performance (particularly when
547e5dd7070Spatrick // precompiled headers are involved), we disable it.
548e5dd7070Spatrick CInvok->getLangOpts()->SpellChecking = false;
549e5dd7070Spatrick
550e5dd7070Spatrick if (index_options & CXIndexOpt_SuppressWarnings)
551e5dd7070Spatrick CInvok->getDiagnosticOpts().IgnoreWarnings = true;
552e5dd7070Spatrick
553e5dd7070Spatrick // Make sure to use the raw module format.
554ec727ea7Spatrick CInvok->getHeaderSearchOpts().ModuleFormat = std::string(
555ec727ea7Spatrick CXXIdx->getPCHContainerOperations()->getRawReader().getFormat());
556e5dd7070Spatrick
557e5dd7070Spatrick auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics,
558e5dd7070Spatrick /*UserFilesAreVolatile=*/true);
559e5dd7070Spatrick if (!Unit)
560e5dd7070Spatrick return CXError_InvalidArguments;
561e5dd7070Spatrick
562e5dd7070Spatrick auto *UPtr = Unit.get();
563e5dd7070Spatrick std::unique_ptr<CXTUOwner> CXTU(
564e5dd7070Spatrick new CXTUOwner(MakeCXTranslationUnit(CXXIdx, std::move(Unit))));
565e5dd7070Spatrick
566e5dd7070Spatrick // Recover resources if we crash before exiting this method.
567e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
568e5dd7070Spatrick CXTUCleanup(CXTU.get());
569e5dd7070Spatrick
570e5dd7070Spatrick // Enable the skip-parsed-bodies optimization only for C++; this may be
571e5dd7070Spatrick // revisited.
572e5dd7070Spatrick bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) &&
573e5dd7070Spatrick CInvok->getLangOpts()->CPlusPlus;
574e5dd7070Spatrick if (SkipBodies)
575e5dd7070Spatrick CInvok->getFrontendOpts().SkipFunctionBodies = true;
576e5dd7070Spatrick
577e5dd7070Spatrick auto DataConsumer =
578e5dd7070Spatrick std::make_shared<CXIndexDataConsumer>(client_data, CB, index_options,
579e5dd7070Spatrick CXTU->getTU());
580e5dd7070Spatrick auto IndexAction = std::make_unique<IndexingFrontendAction>(
581e5dd7070Spatrick DataConsumer, getIndexingOptionsFromCXOptions(index_options),
582e5dd7070Spatrick SkipBodies ? IdxSession->SkipBodyData.get() : nullptr);
583e5dd7070Spatrick
584e5dd7070Spatrick // Recover resources if we crash before exiting this method.
585e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<FrontendAction>
586e5dd7070Spatrick IndexActionCleanup(IndexAction.get());
587e5dd7070Spatrick
588e5dd7070Spatrick bool Persistent = requestedToGetTU;
589e5dd7070Spatrick bool OnlyLocalDecls = false;
590e5dd7070Spatrick bool PrecompilePreamble = false;
591e5dd7070Spatrick bool CreatePreambleOnFirstParse = false;
592e5dd7070Spatrick bool CacheCodeCompletionResults = false;
593e5dd7070Spatrick PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
594e5dd7070Spatrick PPOpts.AllowPCHWithCompilerErrors = true;
595e5dd7070Spatrick
596e5dd7070Spatrick if (requestedToGetTU) {
597e5dd7070Spatrick OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();
598e5dd7070Spatrick PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble;
599e5dd7070Spatrick CreatePreambleOnFirstParse =
600e5dd7070Spatrick TU_options & CXTranslationUnit_CreatePreambleOnFirstParse;
601e5dd7070Spatrick // FIXME: Add a flag for modules.
602e5dd7070Spatrick CacheCodeCompletionResults
603e5dd7070Spatrick = TU_options & CXTranslationUnit_CacheCompletionResults;
604e5dd7070Spatrick }
605e5dd7070Spatrick
606e5dd7070Spatrick if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
607e5dd7070Spatrick PPOpts.DetailedRecord = true;
608e5dd7070Spatrick }
609e5dd7070Spatrick
610e5dd7070Spatrick if (!requestedToGetTU && !CInvok->getLangOpts()->Modules)
611e5dd7070Spatrick PPOpts.DetailedRecord = false;
612e5dd7070Spatrick
613e5dd7070Spatrick // Unless the user specified that they want the preamble on the first parse
614e5dd7070Spatrick // set it up to be created on the first reparse. This makes the first parse
615e5dd7070Spatrick // faster, trading for a slower (first) reparse.
616e5dd7070Spatrick unsigned PrecompilePreambleAfterNParses =
617e5dd7070Spatrick !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
618e5dd7070Spatrick DiagnosticErrorTrap DiagTrap(*Diags);
619e5dd7070Spatrick bool Success = ASTUnit::LoadFromCompilerInvocationAction(
620e5dd7070Spatrick std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags,
621e5dd7070Spatrick IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(),
622e5dd7070Spatrick OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses,
623a9ac8606Spatrick CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true);
624e5dd7070Spatrick if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics())
625e5dd7070Spatrick printDiagsToStderr(UPtr);
626e5dd7070Spatrick
627e5dd7070Spatrick if (isASTReadError(UPtr))
628e5dd7070Spatrick return CXError_ASTReadError;
629e5dd7070Spatrick
630e5dd7070Spatrick if (!Success)
631e5dd7070Spatrick return CXError_Failure;
632e5dd7070Spatrick
633e5dd7070Spatrick if (out_TU)
634e5dd7070Spatrick *out_TU = CXTU->takeTU();
635e5dd7070Spatrick
636e5dd7070Spatrick return CXError_Success;
637e5dd7070Spatrick }
638e5dd7070Spatrick
639e5dd7070Spatrick //===----------------------------------------------------------------------===//
640e5dd7070Spatrick // clang_indexTranslationUnit Implementation
641e5dd7070Spatrick //===----------------------------------------------------------------------===//
642e5dd7070Spatrick
indexPreprocessingRecord(ASTUnit & Unit,CXIndexDataConsumer & IdxCtx)643e5dd7070Spatrick static void indexPreprocessingRecord(ASTUnit &Unit, CXIndexDataConsumer &IdxCtx) {
644e5dd7070Spatrick Preprocessor &PP = Unit.getPreprocessor();
645e5dd7070Spatrick if (!PP.getPreprocessingRecord())
646e5dd7070Spatrick return;
647e5dd7070Spatrick
648e5dd7070Spatrick // FIXME: Only deserialize inclusion directives.
649e5dd7070Spatrick
650e5dd7070Spatrick bool isModuleFile = Unit.isModuleFile();
651e5dd7070Spatrick for (PreprocessedEntity *PPE : Unit.getLocalPreprocessingEntities()) {
652e5dd7070Spatrick if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
653e5dd7070Spatrick SourceLocation Loc = ID->getSourceRange().getBegin();
654e5dd7070Spatrick // Modules have synthetic main files as input, give an invalid location
655e5dd7070Spatrick // if the location points to such a file.
656e5dd7070Spatrick if (isModuleFile && Unit.isInMainFileID(Loc))
657e5dd7070Spatrick Loc = SourceLocation();
658e5dd7070Spatrick IdxCtx.ppIncludedFile(Loc, ID->getFileName(),
659e5dd7070Spatrick ID->getFile(),
660e5dd7070Spatrick ID->getKind() == InclusionDirective::Import,
661e5dd7070Spatrick !ID->wasInQuotes(), ID->importedModule());
662e5dd7070Spatrick }
663e5dd7070Spatrick }
664e5dd7070Spatrick }
665e5dd7070Spatrick
clang_indexTranslationUnit_Impl(CXIndexAction idxAction,CXClientData client_data,IndexerCallbacks * client_index_callbacks,unsigned index_callbacks_size,unsigned index_options,CXTranslationUnit TU)666e5dd7070Spatrick static CXErrorCode clang_indexTranslationUnit_Impl(
667e5dd7070Spatrick CXIndexAction idxAction, CXClientData client_data,
668e5dd7070Spatrick IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size,
669e5dd7070Spatrick unsigned index_options, CXTranslationUnit TU) {
670e5dd7070Spatrick // Check arguments.
671e5dd7070Spatrick if (isNotUsableTU(TU)) {
672e5dd7070Spatrick LOG_BAD_TU(TU);
673e5dd7070Spatrick return CXError_InvalidArguments;
674e5dd7070Spatrick }
675e5dd7070Spatrick if (!client_index_callbacks || index_callbacks_size == 0) {
676e5dd7070Spatrick return CXError_InvalidArguments;
677e5dd7070Spatrick }
678e5dd7070Spatrick
679e5dd7070Spatrick CIndexer *CXXIdx = TU->CIdx;
680e5dd7070Spatrick if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
681e5dd7070Spatrick setThreadBackgroundPriority();
682e5dd7070Spatrick
683e5dd7070Spatrick IndexerCallbacks CB;
684e5dd7070Spatrick memset(&CB, 0, sizeof(CB));
685e5dd7070Spatrick unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
686e5dd7070Spatrick ? index_callbacks_size : sizeof(CB);
687e5dd7070Spatrick memcpy(&CB, client_index_callbacks, ClientCBSize);
688e5dd7070Spatrick
689e5dd7070Spatrick CXIndexDataConsumer DataConsumer(client_data, CB, index_options, TU);
690e5dd7070Spatrick
691e5dd7070Spatrick ASTUnit *Unit = cxtu::getASTUnit(TU);
692e5dd7070Spatrick if (!Unit)
693e5dd7070Spatrick return CXError_Failure;
694e5dd7070Spatrick
695e5dd7070Spatrick ASTUnit::ConcurrencyCheck Check(*Unit);
696e5dd7070Spatrick
697e5dd7070Spatrick if (const FileEntry *PCHFile = Unit->getPCHFile())
698e5dd7070Spatrick DataConsumer.importedPCH(PCHFile);
699e5dd7070Spatrick
700e5dd7070Spatrick FileManager &FileMgr = Unit->getFileManager();
701e5dd7070Spatrick
702e5dd7070Spatrick if (Unit->getOriginalSourceFileName().empty())
703e5dd7070Spatrick DataConsumer.enteredMainFile(nullptr);
704e5dd7070Spatrick else if (auto MainFile = FileMgr.getFile(Unit->getOriginalSourceFileName()))
705e5dd7070Spatrick DataConsumer.enteredMainFile(*MainFile);
706e5dd7070Spatrick else
707e5dd7070Spatrick DataConsumer.enteredMainFile(nullptr);
708e5dd7070Spatrick
709e5dd7070Spatrick DataConsumer.setASTContext(Unit->getASTContext());
710e5dd7070Spatrick DataConsumer.startedTranslationUnit();
711e5dd7070Spatrick
712e5dd7070Spatrick indexPreprocessingRecord(*Unit, DataConsumer);
713e5dd7070Spatrick indexASTUnit(*Unit, DataConsumer, getIndexingOptionsFromCXOptions(index_options));
714e5dd7070Spatrick DataConsumer.indexDiagnostics();
715e5dd7070Spatrick
716e5dd7070Spatrick return CXError_Success;
717e5dd7070Spatrick }
718e5dd7070Spatrick
719e5dd7070Spatrick //===----------------------------------------------------------------------===//
720e5dd7070Spatrick // libclang public APIs.
721e5dd7070Spatrick //===----------------------------------------------------------------------===//
722e5dd7070Spatrick
clang_index_isEntityObjCContainerKind(CXIdxEntityKind K)723e5dd7070Spatrick int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) {
724e5dd7070Spatrick return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory;
725e5dd7070Spatrick }
726e5dd7070Spatrick
727e5dd7070Spatrick const CXIdxObjCContainerDeclInfo *
clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo * DInfo)728e5dd7070Spatrick clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) {
729e5dd7070Spatrick if (!DInfo)
730e5dd7070Spatrick return nullptr;
731e5dd7070Spatrick
732e5dd7070Spatrick const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
733e5dd7070Spatrick if (const ObjCContainerDeclInfo *
734e5dd7070Spatrick ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI))
735e5dd7070Spatrick return &ContInfo->ObjCContDeclInfo;
736e5dd7070Spatrick
737e5dd7070Spatrick return nullptr;
738e5dd7070Spatrick }
739e5dd7070Spatrick
740e5dd7070Spatrick const CXIdxObjCInterfaceDeclInfo *
clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo * DInfo)741e5dd7070Spatrick clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) {
742e5dd7070Spatrick if (!DInfo)
743e5dd7070Spatrick return nullptr;
744e5dd7070Spatrick
745e5dd7070Spatrick const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
746e5dd7070Spatrick if (const ObjCInterfaceDeclInfo *
747e5dd7070Spatrick InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
748e5dd7070Spatrick return &InterInfo->ObjCInterDeclInfo;
749e5dd7070Spatrick
750e5dd7070Spatrick return nullptr;
751e5dd7070Spatrick }
752e5dd7070Spatrick
753e5dd7070Spatrick const CXIdxObjCCategoryDeclInfo *
clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo * DInfo)754e5dd7070Spatrick clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){
755e5dd7070Spatrick if (!DInfo)
756e5dd7070Spatrick return nullptr;
757e5dd7070Spatrick
758e5dd7070Spatrick const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
759e5dd7070Spatrick if (const ObjCCategoryDeclInfo *
760e5dd7070Spatrick CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
761e5dd7070Spatrick return &CatInfo->ObjCCatDeclInfo;
762e5dd7070Spatrick
763e5dd7070Spatrick return nullptr;
764e5dd7070Spatrick }
765e5dd7070Spatrick
766e5dd7070Spatrick const CXIdxObjCProtocolRefListInfo *
clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo * DInfo)767e5dd7070Spatrick clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) {
768e5dd7070Spatrick if (!DInfo)
769e5dd7070Spatrick return nullptr;
770e5dd7070Spatrick
771e5dd7070Spatrick const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
772e5dd7070Spatrick
773e5dd7070Spatrick if (const ObjCInterfaceDeclInfo *
774e5dd7070Spatrick InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
775e5dd7070Spatrick return InterInfo->ObjCInterDeclInfo.protocols;
776e5dd7070Spatrick
777e5dd7070Spatrick if (const ObjCProtocolDeclInfo *
778e5dd7070Spatrick ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI))
779e5dd7070Spatrick return &ProtInfo->ObjCProtoRefListInfo;
780e5dd7070Spatrick
781e5dd7070Spatrick if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
782e5dd7070Spatrick return CatInfo->ObjCCatDeclInfo.protocols;
783e5dd7070Spatrick
784e5dd7070Spatrick return nullptr;
785e5dd7070Spatrick }
786e5dd7070Spatrick
787e5dd7070Spatrick const CXIdxObjCPropertyDeclInfo *
clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo * DInfo)788e5dd7070Spatrick clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) {
789e5dd7070Spatrick if (!DInfo)
790e5dd7070Spatrick return nullptr;
791e5dd7070Spatrick
792e5dd7070Spatrick const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
793e5dd7070Spatrick if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI))
794e5dd7070Spatrick return &PropInfo->ObjCPropDeclInfo;
795e5dd7070Spatrick
796e5dd7070Spatrick return nullptr;
797e5dd7070Spatrick }
798e5dd7070Spatrick
799e5dd7070Spatrick const CXIdxIBOutletCollectionAttrInfo *
clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo * AInfo)800e5dd7070Spatrick clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) {
801e5dd7070Spatrick if (!AInfo)
802e5dd7070Spatrick return nullptr;
803e5dd7070Spatrick
804e5dd7070Spatrick const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo);
805e5dd7070Spatrick if (const IBOutletCollectionInfo *
806e5dd7070Spatrick IBInfo = dyn_cast<IBOutletCollectionInfo>(DI))
807e5dd7070Spatrick return &IBInfo->IBCollInfo;
808e5dd7070Spatrick
809e5dd7070Spatrick return nullptr;
810e5dd7070Spatrick }
811e5dd7070Spatrick
812e5dd7070Spatrick const CXIdxCXXClassDeclInfo *
clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo * DInfo)813e5dd7070Spatrick clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) {
814e5dd7070Spatrick if (!DInfo)
815e5dd7070Spatrick return nullptr;
816e5dd7070Spatrick
817e5dd7070Spatrick const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
818e5dd7070Spatrick if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI))
819e5dd7070Spatrick return &ClassInfo->CXXClassInfo;
820e5dd7070Spatrick
821e5dd7070Spatrick return nullptr;
822e5dd7070Spatrick }
823e5dd7070Spatrick
824e5dd7070Spatrick CXIdxClientContainer
clang_index_getClientContainer(const CXIdxContainerInfo * info)825e5dd7070Spatrick clang_index_getClientContainer(const CXIdxContainerInfo *info) {
826e5dd7070Spatrick if (!info)
827e5dd7070Spatrick return nullptr;
828e5dd7070Spatrick const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
829e5dd7070Spatrick return Container->IndexCtx->getClientContainerForDC(Container->DC);
830e5dd7070Spatrick }
831e5dd7070Spatrick
clang_index_setClientContainer(const CXIdxContainerInfo * info,CXIdxClientContainer client)832e5dd7070Spatrick void clang_index_setClientContainer(const CXIdxContainerInfo *info,
833e5dd7070Spatrick CXIdxClientContainer client) {
834e5dd7070Spatrick if (!info)
835e5dd7070Spatrick return;
836e5dd7070Spatrick const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
837e5dd7070Spatrick Container->IndexCtx->addContainerInMap(Container->DC, client);
838e5dd7070Spatrick }
839e5dd7070Spatrick
clang_index_getClientEntity(const CXIdxEntityInfo * info)840e5dd7070Spatrick CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) {
841e5dd7070Spatrick if (!info)
842e5dd7070Spatrick return nullptr;
843e5dd7070Spatrick const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
844e5dd7070Spatrick return Entity->IndexCtx->getClientEntity(Entity->Dcl);
845e5dd7070Spatrick }
846e5dd7070Spatrick
clang_index_setClientEntity(const CXIdxEntityInfo * info,CXIdxClientEntity client)847e5dd7070Spatrick void clang_index_setClientEntity(const CXIdxEntityInfo *info,
848e5dd7070Spatrick CXIdxClientEntity client) {
849e5dd7070Spatrick if (!info)
850e5dd7070Spatrick return;
851e5dd7070Spatrick const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
852e5dd7070Spatrick Entity->IndexCtx->setClientEntity(Entity->Dcl, client);
853e5dd7070Spatrick }
854e5dd7070Spatrick
clang_IndexAction_create(CXIndex CIdx)855e5dd7070Spatrick CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
856e5dd7070Spatrick return new IndexSessionData(CIdx);
857e5dd7070Spatrick }
858e5dd7070Spatrick
clang_IndexAction_dispose(CXIndexAction idxAction)859e5dd7070Spatrick void clang_IndexAction_dispose(CXIndexAction idxAction) {
860e5dd7070Spatrick if (idxAction)
861e5dd7070Spatrick delete static_cast<IndexSessionData *>(idxAction);
862e5dd7070Spatrick }
863e5dd7070Spatrick
clang_indexSourceFile(CXIndexAction idxAction,CXClientData client_data,IndexerCallbacks * index_callbacks,unsigned index_callbacks_size,unsigned index_options,const char * source_filename,const char * const * command_line_args,int num_command_line_args,struct CXUnsavedFile * unsaved_files,unsigned num_unsaved_files,CXTranslationUnit * out_TU,unsigned TU_options)864e5dd7070Spatrick int clang_indexSourceFile(CXIndexAction idxAction,
865e5dd7070Spatrick CXClientData client_data,
866e5dd7070Spatrick IndexerCallbacks *index_callbacks,
867e5dd7070Spatrick unsigned index_callbacks_size,
868e5dd7070Spatrick unsigned index_options,
869e5dd7070Spatrick const char *source_filename,
870e5dd7070Spatrick const char * const *command_line_args,
871e5dd7070Spatrick int num_command_line_args,
872e5dd7070Spatrick struct CXUnsavedFile *unsaved_files,
873e5dd7070Spatrick unsigned num_unsaved_files,
874e5dd7070Spatrick CXTranslationUnit *out_TU,
875e5dd7070Spatrick unsigned TU_options) {
876e5dd7070Spatrick SmallVector<const char *, 4> Args;
877e5dd7070Spatrick Args.push_back("clang");
878e5dd7070Spatrick Args.append(command_line_args, command_line_args + num_command_line_args);
879e5dd7070Spatrick return clang_indexSourceFileFullArgv(
880e5dd7070Spatrick idxAction, client_data, index_callbacks, index_callbacks_size,
881e5dd7070Spatrick index_options, source_filename, Args.data(), Args.size(), unsaved_files,
882e5dd7070Spatrick num_unsaved_files, out_TU, TU_options);
883e5dd7070Spatrick }
884e5dd7070Spatrick
clang_indexSourceFileFullArgv(CXIndexAction idxAction,CXClientData client_data,IndexerCallbacks * index_callbacks,unsigned index_callbacks_size,unsigned index_options,const char * source_filename,const char * const * command_line_args,int num_command_line_args,struct CXUnsavedFile * unsaved_files,unsigned num_unsaved_files,CXTranslationUnit * out_TU,unsigned TU_options)885e5dd7070Spatrick int clang_indexSourceFileFullArgv(
886e5dd7070Spatrick CXIndexAction idxAction, CXClientData client_data,
887e5dd7070Spatrick IndexerCallbacks *index_callbacks, unsigned index_callbacks_size,
888e5dd7070Spatrick unsigned index_options, const char *source_filename,
889e5dd7070Spatrick const char *const *command_line_args, int num_command_line_args,
890e5dd7070Spatrick struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
891e5dd7070Spatrick CXTranslationUnit *out_TU, unsigned TU_options) {
892e5dd7070Spatrick LOG_FUNC_SECTION {
893e5dd7070Spatrick *Log << source_filename << ": ";
894e5dd7070Spatrick for (int i = 0; i != num_command_line_args; ++i)
895e5dd7070Spatrick *Log << command_line_args[i] << " ";
896e5dd7070Spatrick }
897e5dd7070Spatrick
898e5dd7070Spatrick if (num_unsaved_files && !unsaved_files)
899e5dd7070Spatrick return CXError_InvalidArguments;
900e5dd7070Spatrick
901e5dd7070Spatrick CXErrorCode result = CXError_Failure;
902e5dd7070Spatrick auto IndexSourceFileImpl = [=, &result]() {
903e5dd7070Spatrick result = clang_indexSourceFile_Impl(
904e5dd7070Spatrick idxAction, client_data, index_callbacks, index_callbacks_size,
905e5dd7070Spatrick index_options, source_filename, command_line_args,
906*12c85518Srobert num_command_line_args, llvm::ArrayRef(unsaved_files, num_unsaved_files),
907*12c85518Srobert out_TU, TU_options);
908e5dd7070Spatrick };
909e5dd7070Spatrick
910e5dd7070Spatrick llvm::CrashRecoveryContext CRC;
911e5dd7070Spatrick
912e5dd7070Spatrick if (!RunSafely(CRC, IndexSourceFileImpl)) {
913e5dd7070Spatrick fprintf(stderr, "libclang: crash detected during indexing source file: {\n");
914e5dd7070Spatrick fprintf(stderr, " 'source_filename' : '%s'\n", source_filename);
915e5dd7070Spatrick fprintf(stderr, " 'command_line_args' : [");
916e5dd7070Spatrick for (int i = 0; i != num_command_line_args; ++i) {
917e5dd7070Spatrick if (i)
918e5dd7070Spatrick fprintf(stderr, ", ");
919e5dd7070Spatrick fprintf(stderr, "'%s'", command_line_args[i]);
920e5dd7070Spatrick }
921e5dd7070Spatrick fprintf(stderr, "],\n");
922e5dd7070Spatrick fprintf(stderr, " 'unsaved_files' : [");
923e5dd7070Spatrick for (unsigned i = 0; i != num_unsaved_files; ++i) {
924e5dd7070Spatrick if (i)
925e5dd7070Spatrick fprintf(stderr, ", ");
926e5dd7070Spatrick fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename,
927e5dd7070Spatrick unsaved_files[i].Length);
928e5dd7070Spatrick }
929e5dd7070Spatrick fprintf(stderr, "],\n");
930e5dd7070Spatrick fprintf(stderr, " 'options' : %d,\n", TU_options);
931e5dd7070Spatrick fprintf(stderr, "}\n");
932e5dd7070Spatrick
933e5dd7070Spatrick return 1;
934e5dd7070Spatrick } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
935e5dd7070Spatrick if (out_TU)
936e5dd7070Spatrick PrintLibclangResourceUsage(*out_TU);
937e5dd7070Spatrick }
938e5dd7070Spatrick
939e5dd7070Spatrick return result;
940e5dd7070Spatrick }
941e5dd7070Spatrick
clang_indexTranslationUnit(CXIndexAction idxAction,CXClientData client_data,IndexerCallbacks * index_callbacks,unsigned index_callbacks_size,unsigned index_options,CXTranslationUnit TU)942e5dd7070Spatrick int clang_indexTranslationUnit(CXIndexAction idxAction,
943e5dd7070Spatrick CXClientData client_data,
944e5dd7070Spatrick IndexerCallbacks *index_callbacks,
945e5dd7070Spatrick unsigned index_callbacks_size,
946e5dd7070Spatrick unsigned index_options,
947e5dd7070Spatrick CXTranslationUnit TU) {
948e5dd7070Spatrick LOG_FUNC_SECTION {
949e5dd7070Spatrick *Log << TU;
950e5dd7070Spatrick }
951e5dd7070Spatrick
952e5dd7070Spatrick CXErrorCode result;
953e5dd7070Spatrick auto IndexTranslationUnitImpl = [=, &result]() {
954e5dd7070Spatrick result = clang_indexTranslationUnit_Impl(
955e5dd7070Spatrick idxAction, client_data, index_callbacks, index_callbacks_size,
956e5dd7070Spatrick index_options, TU);
957e5dd7070Spatrick };
958e5dd7070Spatrick
959e5dd7070Spatrick llvm::CrashRecoveryContext CRC;
960e5dd7070Spatrick
961e5dd7070Spatrick if (!RunSafely(CRC, IndexTranslationUnitImpl)) {
962e5dd7070Spatrick fprintf(stderr, "libclang: crash detected during indexing TU\n");
963e5dd7070Spatrick
964e5dd7070Spatrick return 1;
965e5dd7070Spatrick }
966e5dd7070Spatrick
967e5dd7070Spatrick return result;
968e5dd7070Spatrick }
969e5dd7070Spatrick
clang_indexLoc_getFileLocation(CXIdxLoc location,CXIdxClientFile * indexFile,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)970e5dd7070Spatrick void clang_indexLoc_getFileLocation(CXIdxLoc location,
971e5dd7070Spatrick CXIdxClientFile *indexFile,
972e5dd7070Spatrick CXFile *file,
973e5dd7070Spatrick unsigned *line,
974e5dd7070Spatrick unsigned *column,
975e5dd7070Spatrick unsigned *offset) {
976e5dd7070Spatrick if (indexFile) *indexFile = nullptr;
977e5dd7070Spatrick if (file) *file = nullptr;
978e5dd7070Spatrick if (line) *line = 0;
979e5dd7070Spatrick if (column) *column = 0;
980e5dd7070Spatrick if (offset) *offset = 0;
981e5dd7070Spatrick
982e5dd7070Spatrick SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
983e5dd7070Spatrick if (!location.ptr_data[0] || Loc.isInvalid())
984e5dd7070Spatrick return;
985e5dd7070Spatrick
986e5dd7070Spatrick CXIndexDataConsumer &DataConsumer =
987e5dd7070Spatrick *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]);
988e5dd7070Spatrick DataConsumer.translateLoc(Loc, indexFile, file, line, column, offset);
989e5dd7070Spatrick }
990e5dd7070Spatrick
clang_indexLoc_getCXSourceLocation(CXIdxLoc location)991e5dd7070Spatrick CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) {
992e5dd7070Spatrick SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
993e5dd7070Spatrick if (!location.ptr_data[0] || Loc.isInvalid())
994e5dd7070Spatrick return clang_getNullLocation();
995e5dd7070Spatrick
996e5dd7070Spatrick CXIndexDataConsumer &DataConsumer =
997e5dd7070Spatrick *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]);
998e5dd7070Spatrick return cxloc::translateSourceLocation(DataConsumer.getASTContext(), Loc);
999e5dd7070Spatrick }
1000