106f32e7eSjoerg //===- Indexing.cpp - Higher level API functions --------------------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg
906f32e7eSjoerg #include "CIndexDiagnostic.h"
1006f32e7eSjoerg #include "CIndexer.h"
1106f32e7eSjoerg #include "CLog.h"
1206f32e7eSjoerg #include "CXCursor.h"
1306f32e7eSjoerg #include "CXIndexDataConsumer.h"
1406f32e7eSjoerg #include "CXSourceLocation.h"
1506f32e7eSjoerg #include "CXString.h"
1606f32e7eSjoerg #include "CXTranslationUnit.h"
1706f32e7eSjoerg #include "clang/AST/ASTConsumer.h"
1806f32e7eSjoerg #include "clang/Frontend/ASTUnit.h"
1906f32e7eSjoerg #include "clang/Frontend/CompilerInstance.h"
2006f32e7eSjoerg #include "clang/Frontend/CompilerInvocation.h"
2106f32e7eSjoerg #include "clang/Frontend/FrontendAction.h"
2206f32e7eSjoerg #include "clang/Frontend/MultiplexConsumer.h"
2306f32e7eSjoerg #include "clang/Frontend/Utils.h"
2406f32e7eSjoerg #include "clang/Index/IndexingAction.h"
2506f32e7eSjoerg #include "clang/Lex/HeaderSearch.h"
2606f32e7eSjoerg #include "clang/Lex/PPCallbacks.h"
2706f32e7eSjoerg #include "clang/Lex/PPConditionalDirectiveRecord.h"
2806f32e7eSjoerg #include "clang/Lex/Preprocessor.h"
2906f32e7eSjoerg #include "clang/Lex/PreprocessorOptions.h"
3006f32e7eSjoerg #include "llvm/Support/CrashRecoveryContext.h"
3106f32e7eSjoerg #include "llvm/Support/MemoryBuffer.h"
3206f32e7eSjoerg #include <cstdio>
3306f32e7eSjoerg #include <mutex>
3406f32e7eSjoerg #include <utility>
3506f32e7eSjoerg
3606f32e7eSjoerg using namespace clang;
3706f32e7eSjoerg using namespace clang::index;
3806f32e7eSjoerg using namespace cxtu;
3906f32e7eSjoerg using namespace cxindex;
4006f32e7eSjoerg
4106f32e7eSjoerg namespace {
4206f32e7eSjoerg
4306f32e7eSjoerg //===----------------------------------------------------------------------===//
4406f32e7eSjoerg // Skip Parsed Bodies
4506f32e7eSjoerg //===----------------------------------------------------------------------===//
4606f32e7eSjoerg
4706f32e7eSjoerg /// A "region" in source code identified by the file/offset of the
4806f32e7eSjoerg /// preprocessor conditional directive that it belongs to.
4906f32e7eSjoerg /// Multiple, non-consecutive ranges can be parts of the same region.
5006f32e7eSjoerg ///
5106f32e7eSjoerg /// As an example of different regions separated by preprocessor directives:
5206f32e7eSjoerg ///
5306f32e7eSjoerg /// \code
5406f32e7eSjoerg /// #1
5506f32e7eSjoerg /// #ifdef BLAH
5606f32e7eSjoerg /// #2
5706f32e7eSjoerg /// #ifdef CAKE
5806f32e7eSjoerg /// #3
5906f32e7eSjoerg /// #endif
6006f32e7eSjoerg /// #2
6106f32e7eSjoerg /// #endif
6206f32e7eSjoerg /// #1
6306f32e7eSjoerg /// \endcode
6406f32e7eSjoerg ///
6506f32e7eSjoerg /// There are 3 regions, with non-consecutive parts:
6606f32e7eSjoerg /// #1 is identified as the beginning of the file
6706f32e7eSjoerg /// #2 is identified as the location of "#ifdef BLAH"
6806f32e7eSjoerg /// #3 is identified as the location of "#ifdef CAKE"
6906f32e7eSjoerg ///
7006f32e7eSjoerg class PPRegion {
7106f32e7eSjoerg llvm::sys::fs::UniqueID UniqueID;
7206f32e7eSjoerg time_t ModTime;
7306f32e7eSjoerg unsigned Offset;
7406f32e7eSjoerg public:
PPRegion()7506f32e7eSjoerg PPRegion() : UniqueID(0, 0), ModTime(), Offset() {}
PPRegion(llvm::sys::fs::UniqueID UniqueID,unsigned offset,time_t modTime)7606f32e7eSjoerg PPRegion(llvm::sys::fs::UniqueID UniqueID, unsigned offset, time_t modTime)
7706f32e7eSjoerg : UniqueID(UniqueID), ModTime(modTime), Offset(offset) {}
7806f32e7eSjoerg
getUniqueID() const7906f32e7eSjoerg const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
getOffset() const8006f32e7eSjoerg unsigned getOffset() const { return Offset; }
getModTime() const8106f32e7eSjoerg time_t getModTime() const { return ModTime; }
8206f32e7eSjoerg
isInvalid() const8306f32e7eSjoerg bool isInvalid() const { return *this == PPRegion(); }
8406f32e7eSjoerg
operator ==(const PPRegion & lhs,const PPRegion & rhs)8506f32e7eSjoerg friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) {
8606f32e7eSjoerg return lhs.UniqueID == rhs.UniqueID && lhs.Offset == rhs.Offset &&
8706f32e7eSjoerg lhs.ModTime == rhs.ModTime;
8806f32e7eSjoerg }
8906f32e7eSjoerg };
9006f32e7eSjoerg
9106f32e7eSjoerg } // end anonymous namespace
9206f32e7eSjoerg
9306f32e7eSjoerg namespace llvm {
9406f32e7eSjoerg
9506f32e7eSjoerg template <>
9606f32e7eSjoerg struct DenseMapInfo<PPRegion> {
getEmptyKeyllvm::DenseMapInfo9706f32e7eSjoerg static inline PPRegion getEmptyKey() {
9806f32e7eSjoerg return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-1), 0);
9906f32e7eSjoerg }
getTombstoneKeyllvm::DenseMapInfo10006f32e7eSjoerg static inline PPRegion getTombstoneKey() {
10106f32e7eSjoerg return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-2), 0);
10206f32e7eSjoerg }
10306f32e7eSjoerg
getHashValuellvm::DenseMapInfo10406f32e7eSjoerg static unsigned getHashValue(const PPRegion &S) {
10506f32e7eSjoerg llvm::FoldingSetNodeID ID;
10606f32e7eSjoerg const llvm::sys::fs::UniqueID &UniqueID = S.getUniqueID();
10706f32e7eSjoerg ID.AddInteger(UniqueID.getFile());
10806f32e7eSjoerg ID.AddInteger(UniqueID.getDevice());
10906f32e7eSjoerg ID.AddInteger(S.getOffset());
11006f32e7eSjoerg ID.AddInteger(S.getModTime());
11106f32e7eSjoerg return ID.ComputeHash();
11206f32e7eSjoerg }
11306f32e7eSjoerg
isEqualllvm::DenseMapInfo11406f32e7eSjoerg static bool isEqual(const PPRegion &LHS, const PPRegion &RHS) {
11506f32e7eSjoerg return LHS == RHS;
11606f32e7eSjoerg }
11706f32e7eSjoerg };
11806f32e7eSjoerg }
11906f32e7eSjoerg
12006f32e7eSjoerg namespace {
12106f32e7eSjoerg
12206f32e7eSjoerg /// Keeps track of function bodies that have already been parsed.
12306f32e7eSjoerg ///
12406f32e7eSjoerg /// Is thread-safe.
12506f32e7eSjoerg class ThreadSafeParsedRegions {
12606f32e7eSjoerg mutable std::mutex Mutex;
12706f32e7eSjoerg llvm::DenseSet<PPRegion> ParsedRegions;
12806f32e7eSjoerg
12906f32e7eSjoerg public:
13006f32e7eSjoerg ~ThreadSafeParsedRegions() = default;
13106f32e7eSjoerg
getParsedRegions() const13206f32e7eSjoerg llvm::DenseSet<PPRegion> getParsedRegions() const {
13306f32e7eSjoerg std::lock_guard<std::mutex> MG(Mutex);
13406f32e7eSjoerg return ParsedRegions;
13506f32e7eSjoerg }
13606f32e7eSjoerg
addParsedRegions(ArrayRef<PPRegion> Regions)13706f32e7eSjoerg void addParsedRegions(ArrayRef<PPRegion> Regions) {
13806f32e7eSjoerg std::lock_guard<std::mutex> MG(Mutex);
13906f32e7eSjoerg ParsedRegions.insert(Regions.begin(), Regions.end());
14006f32e7eSjoerg }
14106f32e7eSjoerg };
14206f32e7eSjoerg
14306f32e7eSjoerg /// Provides information whether source locations have already been parsed in
14406f32e7eSjoerg /// another FrontendAction.
14506f32e7eSjoerg ///
14606f32e7eSjoerg /// Is NOT thread-safe.
14706f32e7eSjoerg class ParsedSrcLocationsTracker {
14806f32e7eSjoerg ThreadSafeParsedRegions &ParsedRegionsStorage;
14906f32e7eSjoerg PPConditionalDirectiveRecord &PPRec;
15006f32e7eSjoerg Preprocessor &PP;
15106f32e7eSjoerg
15206f32e7eSjoerg /// Snapshot of the shared state at the point when this instance was
15306f32e7eSjoerg /// constructed.
15406f32e7eSjoerg llvm::DenseSet<PPRegion> ParsedRegionsSnapshot;
15506f32e7eSjoerg /// Regions that were queried during this instance lifetime.
15606f32e7eSjoerg SmallVector<PPRegion, 32> NewParsedRegions;
15706f32e7eSjoerg
15806f32e7eSjoerg /// Caching the last queried region.
15906f32e7eSjoerg PPRegion LastRegion;
16006f32e7eSjoerg bool LastIsParsed;
16106f32e7eSjoerg
16206f32e7eSjoerg public:
16306f32e7eSjoerg /// Creates snapshot of \p ParsedRegionsStorage.
ParsedSrcLocationsTracker(ThreadSafeParsedRegions & ParsedRegionsStorage,PPConditionalDirectiveRecord & ppRec,Preprocessor & pp)16406f32e7eSjoerg ParsedSrcLocationsTracker(ThreadSafeParsedRegions &ParsedRegionsStorage,
16506f32e7eSjoerg PPConditionalDirectiveRecord &ppRec,
16606f32e7eSjoerg Preprocessor &pp)
16706f32e7eSjoerg : ParsedRegionsStorage(ParsedRegionsStorage), PPRec(ppRec), PP(pp),
16806f32e7eSjoerg ParsedRegionsSnapshot(ParsedRegionsStorage.getParsedRegions()) {}
16906f32e7eSjoerg
17006f32e7eSjoerg /// \returns true iff \p Loc has already been parsed.
17106f32e7eSjoerg ///
17206f32e7eSjoerg /// Can provide false-negative in case the location was parsed after this
17306f32e7eSjoerg /// instance had been constructed.
hasAlredyBeenParsed(SourceLocation Loc,FileID FID,const FileEntry * FE)17406f32e7eSjoerg bool hasAlredyBeenParsed(SourceLocation Loc, FileID FID,
17506f32e7eSjoerg const FileEntry *FE) {
17606f32e7eSjoerg assert(FE);
17706f32e7eSjoerg PPRegion region = getRegion(Loc, FID, FE);
17806f32e7eSjoerg if (region.isInvalid())
17906f32e7eSjoerg return false;
18006f32e7eSjoerg
18106f32e7eSjoerg // Check common case, consecutive functions in the same region.
18206f32e7eSjoerg if (LastRegion == region)
18306f32e7eSjoerg return LastIsParsed;
18406f32e7eSjoerg
18506f32e7eSjoerg LastRegion = region;
18606f32e7eSjoerg // Source locations can't be revisited during single TU parsing.
18706f32e7eSjoerg // That means if we hit the same region again, it's a different location in
18806f32e7eSjoerg // the same region and so the "is parsed" value from the snapshot is still
18906f32e7eSjoerg // correct.
19006f32e7eSjoerg LastIsParsed = ParsedRegionsSnapshot.count(region);
19106f32e7eSjoerg if (!LastIsParsed)
19206f32e7eSjoerg NewParsedRegions.emplace_back(std::move(region));
19306f32e7eSjoerg return LastIsParsed;
19406f32e7eSjoerg }
19506f32e7eSjoerg
19606f32e7eSjoerg /// Updates ParsedRegionsStorage with newly parsed regions.
syncWithStorage()19706f32e7eSjoerg void syncWithStorage() {
19806f32e7eSjoerg ParsedRegionsStorage.addParsedRegions(NewParsedRegions);
19906f32e7eSjoerg }
20006f32e7eSjoerg
20106f32e7eSjoerg private:
getRegion(SourceLocation Loc,FileID FID,const FileEntry * FE)20206f32e7eSjoerg PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) {
20306f32e7eSjoerg assert(FE);
20406f32e7eSjoerg auto Bail = [this, FE]() {
20506f32e7eSjoerg if (isParsedOnceInclude(FE)) {
20606f32e7eSjoerg const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
20706f32e7eSjoerg return PPRegion(ID, 0, FE->getModificationTime());
20806f32e7eSjoerg }
20906f32e7eSjoerg return PPRegion();
21006f32e7eSjoerg };
21106f32e7eSjoerg
21206f32e7eSjoerg SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc);
21306f32e7eSjoerg assert(RegionLoc.isFileID());
21406f32e7eSjoerg if (RegionLoc.isInvalid())
21506f32e7eSjoerg return Bail();
21606f32e7eSjoerg
21706f32e7eSjoerg FileID RegionFID;
21806f32e7eSjoerg unsigned RegionOffset;
21906f32e7eSjoerg std::tie(RegionFID, RegionOffset) =
22006f32e7eSjoerg PPRec.getSourceManager().getDecomposedLoc(RegionLoc);
22106f32e7eSjoerg
22206f32e7eSjoerg if (RegionFID != FID)
22306f32e7eSjoerg return Bail();
22406f32e7eSjoerg
22506f32e7eSjoerg const llvm::sys::fs::UniqueID &ID = FE->getUniqueID();
22606f32e7eSjoerg return PPRegion(ID, RegionOffset, FE->getModificationTime());
22706f32e7eSjoerg }
22806f32e7eSjoerg
isParsedOnceInclude(const FileEntry * FE)22906f32e7eSjoerg bool isParsedOnceInclude(const FileEntry *FE) {
230*13fbcb42Sjoerg return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE) ||
231*13fbcb42Sjoerg PP.getHeaderSearchInfo().hasFileBeenImported(FE);
23206f32e7eSjoerg }
23306f32e7eSjoerg };
23406f32e7eSjoerg
23506f32e7eSjoerg //===----------------------------------------------------------------------===//
23606f32e7eSjoerg // IndexPPCallbacks
23706f32e7eSjoerg //===----------------------------------------------------------------------===//
23806f32e7eSjoerg
23906f32e7eSjoerg class IndexPPCallbacks : public PPCallbacks {
24006f32e7eSjoerg Preprocessor &PP;
24106f32e7eSjoerg CXIndexDataConsumer &DataConsumer;
24206f32e7eSjoerg bool IsMainFileEntered;
24306f32e7eSjoerg
24406f32e7eSjoerg public:
IndexPPCallbacks(Preprocessor & PP,CXIndexDataConsumer & dataConsumer)24506f32e7eSjoerg IndexPPCallbacks(Preprocessor &PP, CXIndexDataConsumer &dataConsumer)
24606f32e7eSjoerg : PP(PP), DataConsumer(dataConsumer), IsMainFileEntered(false) { }
24706f32e7eSjoerg
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)24806f32e7eSjoerg void FileChanged(SourceLocation Loc, FileChangeReason Reason,
24906f32e7eSjoerg SrcMgr::CharacteristicKind FileType, FileID PrevFID) override {
25006f32e7eSjoerg if (IsMainFileEntered)
25106f32e7eSjoerg return;
25206f32e7eSjoerg
25306f32e7eSjoerg SourceManager &SM = PP.getSourceManager();
25406f32e7eSjoerg SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID());
25506f32e7eSjoerg
25606f32e7eSjoerg if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) {
25706f32e7eSjoerg IsMainFileEntered = true;
25806f32e7eSjoerg DataConsumer.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID()));
25906f32e7eSjoerg }
26006f32e7eSjoerg }
26106f32e7eSjoerg
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,const FileEntry * File,StringRef SearchPath,StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)26206f32e7eSjoerg void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
26306f32e7eSjoerg StringRef FileName, bool IsAngled,
26406f32e7eSjoerg CharSourceRange FilenameRange, const FileEntry *File,
26506f32e7eSjoerg StringRef SearchPath, StringRef RelativePath,
26606f32e7eSjoerg const Module *Imported,
26706f32e7eSjoerg SrcMgr::CharacteristicKind FileType) override {
26806f32e7eSjoerg bool isImport = (IncludeTok.is(tok::identifier) &&
26906f32e7eSjoerg IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
27006f32e7eSjoerg DataConsumer.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled,
27106f32e7eSjoerg Imported);
27206f32e7eSjoerg }
27306f32e7eSjoerg
27406f32e7eSjoerg /// MacroDefined - This hook is called whenever a macro definition is seen.
MacroDefined(const Token & Id,const MacroDirective * MD)27506f32e7eSjoerg void MacroDefined(const Token &Id, const MacroDirective *MD) override {}
27606f32e7eSjoerg
27706f32e7eSjoerg /// MacroUndefined - This hook is called whenever a macro #undef is seen.
27806f32e7eSjoerg /// MI is released immediately following this callback.
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * UD)27906f32e7eSjoerg void MacroUndefined(const Token &MacroNameTok,
28006f32e7eSjoerg const MacroDefinition &MD,
28106f32e7eSjoerg const MacroDirective *UD) override {}
28206f32e7eSjoerg
28306f32e7eSjoerg /// MacroExpands - This is called by when a macro invocation is found.
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)28406f32e7eSjoerg void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
28506f32e7eSjoerg SourceRange Range, const MacroArgs *Args) override {}
28606f32e7eSjoerg
28706f32e7eSjoerg /// SourceRangeSkipped - This hook is called when a source range is skipped.
28806f32e7eSjoerg /// \param Range The SourceRange that was skipped. The range begins at the
28906f32e7eSjoerg /// #if/#else directive and ends after the #endif/#else directive.
SourceRangeSkipped(SourceRange Range,SourceLocation EndifLoc)29006f32e7eSjoerg void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override {
29106f32e7eSjoerg }
29206f32e7eSjoerg };
29306f32e7eSjoerg
29406f32e7eSjoerg //===----------------------------------------------------------------------===//
29506f32e7eSjoerg // IndexingConsumer
29606f32e7eSjoerg //===----------------------------------------------------------------------===//
29706f32e7eSjoerg
29806f32e7eSjoerg class IndexingConsumer : public ASTConsumer {
29906f32e7eSjoerg CXIndexDataConsumer &DataConsumer;
30006f32e7eSjoerg
30106f32e7eSjoerg public:
IndexingConsumer(CXIndexDataConsumer & dataConsumer,ParsedSrcLocationsTracker * parsedLocsTracker)30206f32e7eSjoerg IndexingConsumer(CXIndexDataConsumer &dataConsumer,
30306f32e7eSjoerg ParsedSrcLocationsTracker *parsedLocsTracker)
30406f32e7eSjoerg : DataConsumer(dataConsumer) {}
30506f32e7eSjoerg
Initialize(ASTContext & Context)30606f32e7eSjoerg void Initialize(ASTContext &Context) override {
30706f32e7eSjoerg DataConsumer.setASTContext(Context);
30806f32e7eSjoerg DataConsumer.startedTranslationUnit();
30906f32e7eSjoerg }
31006f32e7eSjoerg
HandleTopLevelDecl(DeclGroupRef DG)31106f32e7eSjoerg bool HandleTopLevelDecl(DeclGroupRef DG) override {
31206f32e7eSjoerg return !DataConsumer.shouldAbort();
31306f32e7eSjoerg }
31406f32e7eSjoerg };
31506f32e7eSjoerg
31606f32e7eSjoerg //===----------------------------------------------------------------------===//
31706f32e7eSjoerg // CaptureDiagnosticConsumer
31806f32e7eSjoerg //===----------------------------------------------------------------------===//
31906f32e7eSjoerg
32006f32e7eSjoerg class CaptureDiagnosticConsumer : public DiagnosticConsumer {
32106f32e7eSjoerg SmallVector<StoredDiagnostic, 4> Errors;
32206f32e7eSjoerg public:
32306f32e7eSjoerg
HandleDiagnostic(DiagnosticsEngine::Level level,const Diagnostic & Info)32406f32e7eSjoerg void HandleDiagnostic(DiagnosticsEngine::Level level,
32506f32e7eSjoerg const Diagnostic &Info) override {
32606f32e7eSjoerg if (level >= DiagnosticsEngine::Error)
32706f32e7eSjoerg Errors.push_back(StoredDiagnostic(level, Info));
32806f32e7eSjoerg }
32906f32e7eSjoerg };
33006f32e7eSjoerg
33106f32e7eSjoerg //===----------------------------------------------------------------------===//
33206f32e7eSjoerg // IndexingFrontendAction
33306f32e7eSjoerg //===----------------------------------------------------------------------===//
33406f32e7eSjoerg
33506f32e7eSjoerg class IndexingFrontendAction : public ASTFrontendAction {
33606f32e7eSjoerg std::shared_ptr<CXIndexDataConsumer> DataConsumer;
33706f32e7eSjoerg IndexingOptions Opts;
33806f32e7eSjoerg
33906f32e7eSjoerg ThreadSafeParsedRegions *SKData;
34006f32e7eSjoerg std::unique_ptr<ParsedSrcLocationsTracker> ParsedLocsTracker;
34106f32e7eSjoerg
34206f32e7eSjoerg public:
IndexingFrontendAction(std::shared_ptr<CXIndexDataConsumer> dataConsumer,const IndexingOptions & Opts,ThreadSafeParsedRegions * skData)34306f32e7eSjoerg IndexingFrontendAction(std::shared_ptr<CXIndexDataConsumer> dataConsumer,
34406f32e7eSjoerg const IndexingOptions &Opts,
34506f32e7eSjoerg ThreadSafeParsedRegions *skData)
34606f32e7eSjoerg : DataConsumer(std::move(dataConsumer)), Opts(Opts), SKData(skData) {}
34706f32e7eSjoerg
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)34806f32e7eSjoerg std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
34906f32e7eSjoerg StringRef InFile) override {
35006f32e7eSjoerg PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
35106f32e7eSjoerg
35206f32e7eSjoerg if (!PPOpts.ImplicitPCHInclude.empty()) {
35306f32e7eSjoerg auto File = CI.getFileManager().getFile(PPOpts.ImplicitPCHInclude);
35406f32e7eSjoerg if (File)
35506f32e7eSjoerg DataConsumer->importedPCH(*File);
35606f32e7eSjoerg }
35706f32e7eSjoerg
35806f32e7eSjoerg DataConsumer->setASTContext(CI.getASTContext());
35906f32e7eSjoerg Preprocessor &PP = CI.getPreprocessor();
36006f32e7eSjoerg PP.addPPCallbacks(std::make_unique<IndexPPCallbacks>(PP, *DataConsumer));
36106f32e7eSjoerg DataConsumer->setPreprocessor(CI.getPreprocessorPtr());
36206f32e7eSjoerg
36306f32e7eSjoerg if (SKData) {
36406f32e7eSjoerg auto *PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager());
36506f32e7eSjoerg PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
36606f32e7eSjoerg ParsedLocsTracker =
36706f32e7eSjoerg std::make_unique<ParsedSrcLocationsTracker>(*SKData, *PPRec, PP);
36806f32e7eSjoerg }
36906f32e7eSjoerg
37006f32e7eSjoerg std::vector<std::unique_ptr<ASTConsumer>> Consumers;
37106f32e7eSjoerg Consumers.push_back(std::make_unique<IndexingConsumer>(
37206f32e7eSjoerg *DataConsumer, ParsedLocsTracker.get()));
37306f32e7eSjoerg Consumers.push_back(createIndexingASTConsumer(
37406f32e7eSjoerg DataConsumer, Opts, CI.getPreprocessorPtr(),
37506f32e7eSjoerg [this](const Decl *D) { return this->shouldSkipFunctionBody(D); }));
37606f32e7eSjoerg return std::make_unique<MultiplexConsumer>(std::move(Consumers));
37706f32e7eSjoerg }
37806f32e7eSjoerg
shouldSkipFunctionBody(const Decl * D)37906f32e7eSjoerg bool shouldSkipFunctionBody(const Decl *D) {
38006f32e7eSjoerg if (!ParsedLocsTracker) {
38106f32e7eSjoerg // Always skip bodies.
38206f32e7eSjoerg return true;
38306f32e7eSjoerg }
38406f32e7eSjoerg
38506f32e7eSjoerg const SourceManager &SM = D->getASTContext().getSourceManager();
38606f32e7eSjoerg SourceLocation Loc = D->getLocation();
38706f32e7eSjoerg if (Loc.isMacroID())
38806f32e7eSjoerg return false;
38906f32e7eSjoerg if (SM.isInSystemHeader(Loc))
39006f32e7eSjoerg return true; // always skip bodies from system headers.
39106f32e7eSjoerg
39206f32e7eSjoerg FileID FID;
39306f32e7eSjoerg unsigned Offset;
39406f32e7eSjoerg std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
39506f32e7eSjoerg // Don't skip bodies from main files; this may be revisited.
39606f32e7eSjoerg if (SM.getMainFileID() == FID)
39706f32e7eSjoerg return false;
39806f32e7eSjoerg const FileEntry *FE = SM.getFileEntryForID(FID);
39906f32e7eSjoerg if (!FE)
40006f32e7eSjoerg return false;
40106f32e7eSjoerg
40206f32e7eSjoerg return ParsedLocsTracker->hasAlredyBeenParsed(Loc, FID, FE);
40306f32e7eSjoerg }
40406f32e7eSjoerg
getTranslationUnitKind()40506f32e7eSjoerg TranslationUnitKind getTranslationUnitKind() override {
40606f32e7eSjoerg if (DataConsumer->shouldIndexImplicitTemplateInsts())
40706f32e7eSjoerg return TU_Complete;
40806f32e7eSjoerg else
40906f32e7eSjoerg return TU_Prefix;
41006f32e7eSjoerg }
hasCodeCompletionSupport() const41106f32e7eSjoerg bool hasCodeCompletionSupport() const override { return false; }
41206f32e7eSjoerg
EndSourceFileAction()41306f32e7eSjoerg void EndSourceFileAction() override {
41406f32e7eSjoerg if (ParsedLocsTracker)
41506f32e7eSjoerg ParsedLocsTracker->syncWithStorage();
41606f32e7eSjoerg }
41706f32e7eSjoerg };
41806f32e7eSjoerg
41906f32e7eSjoerg //===----------------------------------------------------------------------===//
42006f32e7eSjoerg // clang_indexSourceFileUnit Implementation
42106f32e7eSjoerg //===----------------------------------------------------------------------===//
42206f32e7eSjoerg
getIndexingOptionsFromCXOptions(unsigned index_options)42306f32e7eSjoerg static IndexingOptions getIndexingOptionsFromCXOptions(unsigned index_options) {
42406f32e7eSjoerg IndexingOptions IdxOpts;
42506f32e7eSjoerg if (index_options & CXIndexOpt_IndexFunctionLocalSymbols)
42606f32e7eSjoerg IdxOpts.IndexFunctionLocals = true;
42706f32e7eSjoerg if (index_options & CXIndexOpt_IndexImplicitTemplateInstantiations)
42806f32e7eSjoerg IdxOpts.IndexImplicitInstantiation = true;
42906f32e7eSjoerg return IdxOpts;
43006f32e7eSjoerg }
43106f32e7eSjoerg
43206f32e7eSjoerg struct IndexSessionData {
43306f32e7eSjoerg CXIndex CIdx;
43406f32e7eSjoerg std::unique_ptr<ThreadSafeParsedRegions> SkipBodyData =
43506f32e7eSjoerg std::make_unique<ThreadSafeParsedRegions>();
43606f32e7eSjoerg
IndexSessionData__anon62de29160211::IndexSessionData43706f32e7eSjoerg explicit IndexSessionData(CXIndex cIdx) : CIdx(cIdx) {}
43806f32e7eSjoerg };
43906f32e7eSjoerg
44006f32e7eSjoerg } // anonymous namespace
44106f32e7eSjoerg
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)44206f32e7eSjoerg static CXErrorCode clang_indexSourceFile_Impl(
44306f32e7eSjoerg CXIndexAction cxIdxAction, CXClientData client_data,
44406f32e7eSjoerg IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size,
44506f32e7eSjoerg unsigned index_options, const char *source_filename,
44606f32e7eSjoerg const char *const *command_line_args, int num_command_line_args,
44706f32e7eSjoerg ArrayRef<CXUnsavedFile> unsaved_files, CXTranslationUnit *out_TU,
44806f32e7eSjoerg unsigned TU_options) {
44906f32e7eSjoerg if (out_TU)
45006f32e7eSjoerg *out_TU = nullptr;
45106f32e7eSjoerg bool requestedToGetTU = (out_TU != nullptr);
45206f32e7eSjoerg
45306f32e7eSjoerg if (!cxIdxAction) {
45406f32e7eSjoerg return CXError_InvalidArguments;
45506f32e7eSjoerg }
45606f32e7eSjoerg if (!client_index_callbacks || index_callbacks_size == 0) {
45706f32e7eSjoerg return CXError_InvalidArguments;
45806f32e7eSjoerg }
45906f32e7eSjoerg
46006f32e7eSjoerg IndexerCallbacks CB;
46106f32e7eSjoerg memset(&CB, 0, sizeof(CB));
46206f32e7eSjoerg unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
46306f32e7eSjoerg ? index_callbacks_size : sizeof(CB);
46406f32e7eSjoerg memcpy(&CB, client_index_callbacks, ClientCBSize);
46506f32e7eSjoerg
46606f32e7eSjoerg IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction);
46706f32e7eSjoerg CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx);
46806f32e7eSjoerg
46906f32e7eSjoerg if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
47006f32e7eSjoerg setThreadBackgroundPriority();
47106f32e7eSjoerg
47206f32e7eSjoerg CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All;
47306f32e7eSjoerg if (TU_options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles)
47406f32e7eSjoerg CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes;
47506f32e7eSjoerg if (Logger::isLoggingEnabled())
47606f32e7eSjoerg CaptureDiagnostics = CaptureDiagsKind::None;
47706f32e7eSjoerg
47806f32e7eSjoerg CaptureDiagnosticConsumer *CaptureDiag = nullptr;
47906f32e7eSjoerg if (CaptureDiagnostics != CaptureDiagsKind::None)
48006f32e7eSjoerg CaptureDiag = new CaptureDiagnosticConsumer();
48106f32e7eSjoerg
48206f32e7eSjoerg // Configure the diagnostics.
48306f32e7eSjoerg IntrusiveRefCntPtr<DiagnosticsEngine>
48406f32e7eSjoerg Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
48506f32e7eSjoerg CaptureDiag,
48606f32e7eSjoerg /*ShouldOwnClient=*/true));
48706f32e7eSjoerg
48806f32e7eSjoerg // Recover resources if we crash before exiting this function.
48906f32e7eSjoerg llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
49006f32e7eSjoerg llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
49106f32e7eSjoerg DiagCleanup(Diags.get());
49206f32e7eSjoerg
49306f32e7eSjoerg std::unique_ptr<std::vector<const char *>> Args(
49406f32e7eSjoerg new std::vector<const char *>());
49506f32e7eSjoerg
49606f32e7eSjoerg // Recover resources if we crash before exiting this method.
49706f32e7eSjoerg llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
49806f32e7eSjoerg ArgsCleanup(Args.get());
49906f32e7eSjoerg
50006f32e7eSjoerg Args->insert(Args->end(), command_line_args,
50106f32e7eSjoerg command_line_args + num_command_line_args);
50206f32e7eSjoerg
50306f32e7eSjoerg // The 'source_filename' argument is optional. If the caller does not
50406f32e7eSjoerg // specify it then it is assumed that the source file is specified
50506f32e7eSjoerg // in the actual argument list.
50606f32e7eSjoerg // Put the source file after command_line_args otherwise if '-x' flag is
50706f32e7eSjoerg // present it will be unused.
50806f32e7eSjoerg if (source_filename)
50906f32e7eSjoerg Args->push_back(source_filename);
51006f32e7eSjoerg
51106f32e7eSjoerg std::shared_ptr<CompilerInvocation> CInvok =
51206f32e7eSjoerg createInvocationFromCommandLine(*Args, Diags);
51306f32e7eSjoerg
51406f32e7eSjoerg if (!CInvok)
51506f32e7eSjoerg return CXError_Failure;
51606f32e7eSjoerg
51706f32e7eSjoerg // Recover resources if we crash before exiting this function.
51806f32e7eSjoerg llvm::CrashRecoveryContextCleanupRegistrar<
51906f32e7eSjoerg std::shared_ptr<CompilerInvocation>,
52006f32e7eSjoerg llvm::CrashRecoveryContextDestructorCleanup<
52106f32e7eSjoerg std::shared_ptr<CompilerInvocation>>>
52206f32e7eSjoerg CInvokCleanup(&CInvok);
52306f32e7eSjoerg
52406f32e7eSjoerg if (CInvok->getFrontendOpts().Inputs.empty())
52506f32e7eSjoerg return CXError_Failure;
52606f32e7eSjoerg
52706f32e7eSjoerg typedef SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 8> MemBufferOwner;
52806f32e7eSjoerg std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner);
52906f32e7eSjoerg
53006f32e7eSjoerg // Recover resources if we crash before exiting this method.
53106f32e7eSjoerg llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup(
53206f32e7eSjoerg BufOwner.get());
53306f32e7eSjoerg
53406f32e7eSjoerg for (auto &UF : unsaved_files) {
53506f32e7eSjoerg std::unique_ptr<llvm::MemoryBuffer> MB =
53606f32e7eSjoerg llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
53706f32e7eSjoerg CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get());
53806f32e7eSjoerg BufOwner->push_back(std::move(MB));
53906f32e7eSjoerg }
54006f32e7eSjoerg
54106f32e7eSjoerg // Since libclang is primarily used by batch tools dealing with
54206f32e7eSjoerg // (often very broken) source code, where spell-checking can have a
54306f32e7eSjoerg // significant negative impact on performance (particularly when
54406f32e7eSjoerg // precompiled headers are involved), we disable it.
54506f32e7eSjoerg CInvok->getLangOpts()->SpellChecking = false;
54606f32e7eSjoerg
54706f32e7eSjoerg if (index_options & CXIndexOpt_SuppressWarnings)
54806f32e7eSjoerg CInvok->getDiagnosticOpts().IgnoreWarnings = true;
54906f32e7eSjoerg
55006f32e7eSjoerg // Make sure to use the raw module format.
551*13fbcb42Sjoerg CInvok->getHeaderSearchOpts().ModuleFormat = std::string(
552*13fbcb42Sjoerg CXXIdx->getPCHContainerOperations()->getRawReader().getFormat());
55306f32e7eSjoerg
55406f32e7eSjoerg auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics,
55506f32e7eSjoerg /*UserFilesAreVolatile=*/true);
55606f32e7eSjoerg if (!Unit)
55706f32e7eSjoerg return CXError_InvalidArguments;
55806f32e7eSjoerg
55906f32e7eSjoerg auto *UPtr = Unit.get();
56006f32e7eSjoerg std::unique_ptr<CXTUOwner> CXTU(
56106f32e7eSjoerg new CXTUOwner(MakeCXTranslationUnit(CXXIdx, std::move(Unit))));
56206f32e7eSjoerg
56306f32e7eSjoerg // Recover resources if we crash before exiting this method.
56406f32e7eSjoerg llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
56506f32e7eSjoerg CXTUCleanup(CXTU.get());
56606f32e7eSjoerg
56706f32e7eSjoerg // Enable the skip-parsed-bodies optimization only for C++; this may be
56806f32e7eSjoerg // revisited.
56906f32e7eSjoerg bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) &&
57006f32e7eSjoerg CInvok->getLangOpts()->CPlusPlus;
57106f32e7eSjoerg if (SkipBodies)
57206f32e7eSjoerg CInvok->getFrontendOpts().SkipFunctionBodies = true;
57306f32e7eSjoerg
57406f32e7eSjoerg auto DataConsumer =
57506f32e7eSjoerg std::make_shared<CXIndexDataConsumer>(client_data, CB, index_options,
57606f32e7eSjoerg CXTU->getTU());
57706f32e7eSjoerg auto IndexAction = std::make_unique<IndexingFrontendAction>(
57806f32e7eSjoerg DataConsumer, getIndexingOptionsFromCXOptions(index_options),
57906f32e7eSjoerg SkipBodies ? IdxSession->SkipBodyData.get() : nullptr);
58006f32e7eSjoerg
58106f32e7eSjoerg // Recover resources if we crash before exiting this method.
58206f32e7eSjoerg llvm::CrashRecoveryContextCleanupRegistrar<FrontendAction>
58306f32e7eSjoerg IndexActionCleanup(IndexAction.get());
58406f32e7eSjoerg
58506f32e7eSjoerg bool Persistent = requestedToGetTU;
58606f32e7eSjoerg bool OnlyLocalDecls = false;
58706f32e7eSjoerg bool PrecompilePreamble = false;
58806f32e7eSjoerg bool CreatePreambleOnFirstParse = false;
58906f32e7eSjoerg bool CacheCodeCompletionResults = false;
59006f32e7eSjoerg PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
59106f32e7eSjoerg PPOpts.AllowPCHWithCompilerErrors = true;
59206f32e7eSjoerg
59306f32e7eSjoerg if (requestedToGetTU) {
59406f32e7eSjoerg OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();
59506f32e7eSjoerg PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble;
59606f32e7eSjoerg CreatePreambleOnFirstParse =
59706f32e7eSjoerg TU_options & CXTranslationUnit_CreatePreambleOnFirstParse;
59806f32e7eSjoerg // FIXME: Add a flag for modules.
59906f32e7eSjoerg CacheCodeCompletionResults
60006f32e7eSjoerg = TU_options & CXTranslationUnit_CacheCompletionResults;
60106f32e7eSjoerg }
60206f32e7eSjoerg
60306f32e7eSjoerg if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
60406f32e7eSjoerg PPOpts.DetailedRecord = true;
60506f32e7eSjoerg }
60606f32e7eSjoerg
60706f32e7eSjoerg if (!requestedToGetTU && !CInvok->getLangOpts()->Modules)
60806f32e7eSjoerg PPOpts.DetailedRecord = false;
60906f32e7eSjoerg
61006f32e7eSjoerg // Unless the user specified that they want the preamble on the first parse
61106f32e7eSjoerg // set it up to be created on the first reparse. This makes the first parse
61206f32e7eSjoerg // faster, trading for a slower (first) reparse.
61306f32e7eSjoerg unsigned PrecompilePreambleAfterNParses =
61406f32e7eSjoerg !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
61506f32e7eSjoerg DiagnosticErrorTrap DiagTrap(*Diags);
61606f32e7eSjoerg bool Success = ASTUnit::LoadFromCompilerInvocationAction(
61706f32e7eSjoerg std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags,
61806f32e7eSjoerg IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(),
61906f32e7eSjoerg OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses,
620*13fbcb42Sjoerg CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true);
62106f32e7eSjoerg if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics())
62206f32e7eSjoerg printDiagsToStderr(UPtr);
62306f32e7eSjoerg
62406f32e7eSjoerg if (isASTReadError(UPtr))
62506f32e7eSjoerg return CXError_ASTReadError;
62606f32e7eSjoerg
62706f32e7eSjoerg if (!Success)
62806f32e7eSjoerg return CXError_Failure;
62906f32e7eSjoerg
63006f32e7eSjoerg if (out_TU)
63106f32e7eSjoerg *out_TU = CXTU->takeTU();
63206f32e7eSjoerg
63306f32e7eSjoerg return CXError_Success;
63406f32e7eSjoerg }
63506f32e7eSjoerg
63606f32e7eSjoerg //===----------------------------------------------------------------------===//
63706f32e7eSjoerg // clang_indexTranslationUnit Implementation
63806f32e7eSjoerg //===----------------------------------------------------------------------===//
63906f32e7eSjoerg
indexPreprocessingRecord(ASTUnit & Unit,CXIndexDataConsumer & IdxCtx)64006f32e7eSjoerg static void indexPreprocessingRecord(ASTUnit &Unit, CXIndexDataConsumer &IdxCtx) {
64106f32e7eSjoerg Preprocessor &PP = Unit.getPreprocessor();
64206f32e7eSjoerg if (!PP.getPreprocessingRecord())
64306f32e7eSjoerg return;
64406f32e7eSjoerg
64506f32e7eSjoerg // FIXME: Only deserialize inclusion directives.
64606f32e7eSjoerg
64706f32e7eSjoerg bool isModuleFile = Unit.isModuleFile();
64806f32e7eSjoerg for (PreprocessedEntity *PPE : Unit.getLocalPreprocessingEntities()) {
64906f32e7eSjoerg if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
65006f32e7eSjoerg SourceLocation Loc = ID->getSourceRange().getBegin();
65106f32e7eSjoerg // Modules have synthetic main files as input, give an invalid location
65206f32e7eSjoerg // if the location points to such a file.
65306f32e7eSjoerg if (isModuleFile && Unit.isInMainFileID(Loc))
65406f32e7eSjoerg Loc = SourceLocation();
65506f32e7eSjoerg IdxCtx.ppIncludedFile(Loc, ID->getFileName(),
65606f32e7eSjoerg ID->getFile(),
65706f32e7eSjoerg ID->getKind() == InclusionDirective::Import,
65806f32e7eSjoerg !ID->wasInQuotes(), ID->importedModule());
65906f32e7eSjoerg }
66006f32e7eSjoerg }
66106f32e7eSjoerg }
66206f32e7eSjoerg
clang_indexTranslationUnit_Impl(CXIndexAction idxAction,CXClientData client_data,IndexerCallbacks * client_index_callbacks,unsigned index_callbacks_size,unsigned index_options,CXTranslationUnit TU)66306f32e7eSjoerg static CXErrorCode clang_indexTranslationUnit_Impl(
66406f32e7eSjoerg CXIndexAction idxAction, CXClientData client_data,
66506f32e7eSjoerg IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size,
66606f32e7eSjoerg unsigned index_options, CXTranslationUnit TU) {
66706f32e7eSjoerg // Check arguments.
66806f32e7eSjoerg if (isNotUsableTU(TU)) {
66906f32e7eSjoerg LOG_BAD_TU(TU);
67006f32e7eSjoerg return CXError_InvalidArguments;
67106f32e7eSjoerg }
67206f32e7eSjoerg if (!client_index_callbacks || index_callbacks_size == 0) {
67306f32e7eSjoerg return CXError_InvalidArguments;
67406f32e7eSjoerg }
67506f32e7eSjoerg
67606f32e7eSjoerg CIndexer *CXXIdx = TU->CIdx;
67706f32e7eSjoerg if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
67806f32e7eSjoerg setThreadBackgroundPriority();
67906f32e7eSjoerg
68006f32e7eSjoerg IndexerCallbacks CB;
68106f32e7eSjoerg memset(&CB, 0, sizeof(CB));
68206f32e7eSjoerg unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
68306f32e7eSjoerg ? index_callbacks_size : sizeof(CB);
68406f32e7eSjoerg memcpy(&CB, client_index_callbacks, ClientCBSize);
68506f32e7eSjoerg
68606f32e7eSjoerg CXIndexDataConsumer DataConsumer(client_data, CB, index_options, TU);
68706f32e7eSjoerg
68806f32e7eSjoerg ASTUnit *Unit = cxtu::getASTUnit(TU);
68906f32e7eSjoerg if (!Unit)
69006f32e7eSjoerg return CXError_Failure;
69106f32e7eSjoerg
69206f32e7eSjoerg ASTUnit::ConcurrencyCheck Check(*Unit);
69306f32e7eSjoerg
69406f32e7eSjoerg if (const FileEntry *PCHFile = Unit->getPCHFile())
69506f32e7eSjoerg DataConsumer.importedPCH(PCHFile);
69606f32e7eSjoerg
69706f32e7eSjoerg FileManager &FileMgr = Unit->getFileManager();
69806f32e7eSjoerg
69906f32e7eSjoerg if (Unit->getOriginalSourceFileName().empty())
70006f32e7eSjoerg DataConsumer.enteredMainFile(nullptr);
70106f32e7eSjoerg else if (auto MainFile = FileMgr.getFile(Unit->getOriginalSourceFileName()))
70206f32e7eSjoerg DataConsumer.enteredMainFile(*MainFile);
70306f32e7eSjoerg else
70406f32e7eSjoerg DataConsumer.enteredMainFile(nullptr);
70506f32e7eSjoerg
70606f32e7eSjoerg DataConsumer.setASTContext(Unit->getASTContext());
70706f32e7eSjoerg DataConsumer.startedTranslationUnit();
70806f32e7eSjoerg
70906f32e7eSjoerg indexPreprocessingRecord(*Unit, DataConsumer);
71006f32e7eSjoerg indexASTUnit(*Unit, DataConsumer, getIndexingOptionsFromCXOptions(index_options));
71106f32e7eSjoerg DataConsumer.indexDiagnostics();
71206f32e7eSjoerg
71306f32e7eSjoerg return CXError_Success;
71406f32e7eSjoerg }
71506f32e7eSjoerg
71606f32e7eSjoerg //===----------------------------------------------------------------------===//
71706f32e7eSjoerg // libclang public APIs.
71806f32e7eSjoerg //===----------------------------------------------------------------------===//
71906f32e7eSjoerg
clang_index_isEntityObjCContainerKind(CXIdxEntityKind K)72006f32e7eSjoerg int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) {
72106f32e7eSjoerg return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory;
72206f32e7eSjoerg }
72306f32e7eSjoerg
72406f32e7eSjoerg const CXIdxObjCContainerDeclInfo *
clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo * DInfo)72506f32e7eSjoerg clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) {
72606f32e7eSjoerg if (!DInfo)
72706f32e7eSjoerg return nullptr;
72806f32e7eSjoerg
72906f32e7eSjoerg const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
73006f32e7eSjoerg if (const ObjCContainerDeclInfo *
73106f32e7eSjoerg ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI))
73206f32e7eSjoerg return &ContInfo->ObjCContDeclInfo;
73306f32e7eSjoerg
73406f32e7eSjoerg return nullptr;
73506f32e7eSjoerg }
73606f32e7eSjoerg
73706f32e7eSjoerg const CXIdxObjCInterfaceDeclInfo *
clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo * DInfo)73806f32e7eSjoerg clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) {
73906f32e7eSjoerg if (!DInfo)
74006f32e7eSjoerg return nullptr;
74106f32e7eSjoerg
74206f32e7eSjoerg const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
74306f32e7eSjoerg if (const ObjCInterfaceDeclInfo *
74406f32e7eSjoerg InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
74506f32e7eSjoerg return &InterInfo->ObjCInterDeclInfo;
74606f32e7eSjoerg
74706f32e7eSjoerg return nullptr;
74806f32e7eSjoerg }
74906f32e7eSjoerg
75006f32e7eSjoerg const CXIdxObjCCategoryDeclInfo *
clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo * DInfo)75106f32e7eSjoerg clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){
75206f32e7eSjoerg if (!DInfo)
75306f32e7eSjoerg return nullptr;
75406f32e7eSjoerg
75506f32e7eSjoerg const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
75606f32e7eSjoerg if (const ObjCCategoryDeclInfo *
75706f32e7eSjoerg CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
75806f32e7eSjoerg return &CatInfo->ObjCCatDeclInfo;
75906f32e7eSjoerg
76006f32e7eSjoerg return nullptr;
76106f32e7eSjoerg }
76206f32e7eSjoerg
76306f32e7eSjoerg const CXIdxObjCProtocolRefListInfo *
clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo * DInfo)76406f32e7eSjoerg clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) {
76506f32e7eSjoerg if (!DInfo)
76606f32e7eSjoerg return nullptr;
76706f32e7eSjoerg
76806f32e7eSjoerg const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
76906f32e7eSjoerg
77006f32e7eSjoerg if (const ObjCInterfaceDeclInfo *
77106f32e7eSjoerg InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
77206f32e7eSjoerg return InterInfo->ObjCInterDeclInfo.protocols;
77306f32e7eSjoerg
77406f32e7eSjoerg if (const ObjCProtocolDeclInfo *
77506f32e7eSjoerg ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI))
77606f32e7eSjoerg return &ProtInfo->ObjCProtoRefListInfo;
77706f32e7eSjoerg
77806f32e7eSjoerg if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
77906f32e7eSjoerg return CatInfo->ObjCCatDeclInfo.protocols;
78006f32e7eSjoerg
78106f32e7eSjoerg return nullptr;
78206f32e7eSjoerg }
78306f32e7eSjoerg
78406f32e7eSjoerg const CXIdxObjCPropertyDeclInfo *
clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo * DInfo)78506f32e7eSjoerg clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) {
78606f32e7eSjoerg if (!DInfo)
78706f32e7eSjoerg return nullptr;
78806f32e7eSjoerg
78906f32e7eSjoerg const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
79006f32e7eSjoerg if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI))
79106f32e7eSjoerg return &PropInfo->ObjCPropDeclInfo;
79206f32e7eSjoerg
79306f32e7eSjoerg return nullptr;
79406f32e7eSjoerg }
79506f32e7eSjoerg
79606f32e7eSjoerg const CXIdxIBOutletCollectionAttrInfo *
clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo * AInfo)79706f32e7eSjoerg clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) {
79806f32e7eSjoerg if (!AInfo)
79906f32e7eSjoerg return nullptr;
80006f32e7eSjoerg
80106f32e7eSjoerg const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo);
80206f32e7eSjoerg if (const IBOutletCollectionInfo *
80306f32e7eSjoerg IBInfo = dyn_cast<IBOutletCollectionInfo>(DI))
80406f32e7eSjoerg return &IBInfo->IBCollInfo;
80506f32e7eSjoerg
80606f32e7eSjoerg return nullptr;
80706f32e7eSjoerg }
80806f32e7eSjoerg
80906f32e7eSjoerg const CXIdxCXXClassDeclInfo *
clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo * DInfo)81006f32e7eSjoerg clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) {
81106f32e7eSjoerg if (!DInfo)
81206f32e7eSjoerg return nullptr;
81306f32e7eSjoerg
81406f32e7eSjoerg const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
81506f32e7eSjoerg if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI))
81606f32e7eSjoerg return &ClassInfo->CXXClassInfo;
81706f32e7eSjoerg
81806f32e7eSjoerg return nullptr;
81906f32e7eSjoerg }
82006f32e7eSjoerg
82106f32e7eSjoerg CXIdxClientContainer
clang_index_getClientContainer(const CXIdxContainerInfo * info)82206f32e7eSjoerg clang_index_getClientContainer(const CXIdxContainerInfo *info) {
82306f32e7eSjoerg if (!info)
82406f32e7eSjoerg return nullptr;
82506f32e7eSjoerg const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
82606f32e7eSjoerg return Container->IndexCtx->getClientContainerForDC(Container->DC);
82706f32e7eSjoerg }
82806f32e7eSjoerg
clang_index_setClientContainer(const CXIdxContainerInfo * info,CXIdxClientContainer client)82906f32e7eSjoerg void clang_index_setClientContainer(const CXIdxContainerInfo *info,
83006f32e7eSjoerg CXIdxClientContainer client) {
83106f32e7eSjoerg if (!info)
83206f32e7eSjoerg return;
83306f32e7eSjoerg const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
83406f32e7eSjoerg Container->IndexCtx->addContainerInMap(Container->DC, client);
83506f32e7eSjoerg }
83606f32e7eSjoerg
clang_index_getClientEntity(const CXIdxEntityInfo * info)83706f32e7eSjoerg CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) {
83806f32e7eSjoerg if (!info)
83906f32e7eSjoerg return nullptr;
84006f32e7eSjoerg const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
84106f32e7eSjoerg return Entity->IndexCtx->getClientEntity(Entity->Dcl);
84206f32e7eSjoerg }
84306f32e7eSjoerg
clang_index_setClientEntity(const CXIdxEntityInfo * info,CXIdxClientEntity client)84406f32e7eSjoerg void clang_index_setClientEntity(const CXIdxEntityInfo *info,
84506f32e7eSjoerg CXIdxClientEntity client) {
84606f32e7eSjoerg if (!info)
84706f32e7eSjoerg return;
84806f32e7eSjoerg const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
84906f32e7eSjoerg Entity->IndexCtx->setClientEntity(Entity->Dcl, client);
85006f32e7eSjoerg }
85106f32e7eSjoerg
clang_IndexAction_create(CXIndex CIdx)85206f32e7eSjoerg CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
85306f32e7eSjoerg return new IndexSessionData(CIdx);
85406f32e7eSjoerg }
85506f32e7eSjoerg
clang_IndexAction_dispose(CXIndexAction idxAction)85606f32e7eSjoerg void clang_IndexAction_dispose(CXIndexAction idxAction) {
85706f32e7eSjoerg if (idxAction)
85806f32e7eSjoerg delete static_cast<IndexSessionData *>(idxAction);
85906f32e7eSjoerg }
86006f32e7eSjoerg
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)86106f32e7eSjoerg int clang_indexSourceFile(CXIndexAction idxAction,
86206f32e7eSjoerg CXClientData client_data,
86306f32e7eSjoerg IndexerCallbacks *index_callbacks,
86406f32e7eSjoerg unsigned index_callbacks_size,
86506f32e7eSjoerg unsigned index_options,
86606f32e7eSjoerg const char *source_filename,
86706f32e7eSjoerg const char * const *command_line_args,
86806f32e7eSjoerg int num_command_line_args,
86906f32e7eSjoerg struct CXUnsavedFile *unsaved_files,
87006f32e7eSjoerg unsigned num_unsaved_files,
87106f32e7eSjoerg CXTranslationUnit *out_TU,
87206f32e7eSjoerg unsigned TU_options) {
87306f32e7eSjoerg SmallVector<const char *, 4> Args;
87406f32e7eSjoerg Args.push_back("clang");
87506f32e7eSjoerg Args.append(command_line_args, command_line_args + num_command_line_args);
87606f32e7eSjoerg return clang_indexSourceFileFullArgv(
87706f32e7eSjoerg idxAction, client_data, index_callbacks, index_callbacks_size,
87806f32e7eSjoerg index_options, source_filename, Args.data(), Args.size(), unsaved_files,
87906f32e7eSjoerg num_unsaved_files, out_TU, TU_options);
88006f32e7eSjoerg }
88106f32e7eSjoerg
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)88206f32e7eSjoerg int clang_indexSourceFileFullArgv(
88306f32e7eSjoerg CXIndexAction idxAction, CXClientData client_data,
88406f32e7eSjoerg IndexerCallbacks *index_callbacks, unsigned index_callbacks_size,
88506f32e7eSjoerg unsigned index_options, const char *source_filename,
88606f32e7eSjoerg const char *const *command_line_args, int num_command_line_args,
88706f32e7eSjoerg struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
88806f32e7eSjoerg CXTranslationUnit *out_TU, unsigned TU_options) {
88906f32e7eSjoerg LOG_FUNC_SECTION {
89006f32e7eSjoerg *Log << source_filename << ": ";
89106f32e7eSjoerg for (int i = 0; i != num_command_line_args; ++i)
89206f32e7eSjoerg *Log << command_line_args[i] << " ";
89306f32e7eSjoerg }
89406f32e7eSjoerg
89506f32e7eSjoerg if (num_unsaved_files && !unsaved_files)
89606f32e7eSjoerg return CXError_InvalidArguments;
89706f32e7eSjoerg
89806f32e7eSjoerg CXErrorCode result = CXError_Failure;
89906f32e7eSjoerg auto IndexSourceFileImpl = [=, &result]() {
90006f32e7eSjoerg result = clang_indexSourceFile_Impl(
90106f32e7eSjoerg idxAction, client_data, index_callbacks, index_callbacks_size,
90206f32e7eSjoerg index_options, source_filename, command_line_args,
90306f32e7eSjoerg num_command_line_args,
90406f32e7eSjoerg llvm::makeArrayRef(unsaved_files, num_unsaved_files), out_TU,
90506f32e7eSjoerg TU_options);
90606f32e7eSjoerg };
90706f32e7eSjoerg
90806f32e7eSjoerg llvm::CrashRecoveryContext CRC;
90906f32e7eSjoerg
91006f32e7eSjoerg if (!RunSafely(CRC, IndexSourceFileImpl)) {
91106f32e7eSjoerg fprintf(stderr, "libclang: crash detected during indexing source file: {\n");
91206f32e7eSjoerg fprintf(stderr, " 'source_filename' : '%s'\n", source_filename);
91306f32e7eSjoerg fprintf(stderr, " 'command_line_args' : [");
91406f32e7eSjoerg for (int i = 0; i != num_command_line_args; ++i) {
91506f32e7eSjoerg if (i)
91606f32e7eSjoerg fprintf(stderr, ", ");
91706f32e7eSjoerg fprintf(stderr, "'%s'", command_line_args[i]);
91806f32e7eSjoerg }
91906f32e7eSjoerg fprintf(stderr, "],\n");
92006f32e7eSjoerg fprintf(stderr, " 'unsaved_files' : [");
92106f32e7eSjoerg for (unsigned i = 0; i != num_unsaved_files; ++i) {
92206f32e7eSjoerg if (i)
92306f32e7eSjoerg fprintf(stderr, ", ");
92406f32e7eSjoerg fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename,
92506f32e7eSjoerg unsaved_files[i].Length);
92606f32e7eSjoerg }
92706f32e7eSjoerg fprintf(stderr, "],\n");
92806f32e7eSjoerg fprintf(stderr, " 'options' : %d,\n", TU_options);
92906f32e7eSjoerg fprintf(stderr, "}\n");
93006f32e7eSjoerg
93106f32e7eSjoerg return 1;
93206f32e7eSjoerg } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
93306f32e7eSjoerg if (out_TU)
93406f32e7eSjoerg PrintLibclangResourceUsage(*out_TU);
93506f32e7eSjoerg }
93606f32e7eSjoerg
93706f32e7eSjoerg return result;
93806f32e7eSjoerg }
93906f32e7eSjoerg
clang_indexTranslationUnit(CXIndexAction idxAction,CXClientData client_data,IndexerCallbacks * index_callbacks,unsigned index_callbacks_size,unsigned index_options,CXTranslationUnit TU)94006f32e7eSjoerg int clang_indexTranslationUnit(CXIndexAction idxAction,
94106f32e7eSjoerg CXClientData client_data,
94206f32e7eSjoerg IndexerCallbacks *index_callbacks,
94306f32e7eSjoerg unsigned index_callbacks_size,
94406f32e7eSjoerg unsigned index_options,
94506f32e7eSjoerg CXTranslationUnit TU) {
94606f32e7eSjoerg LOG_FUNC_SECTION {
94706f32e7eSjoerg *Log << TU;
94806f32e7eSjoerg }
94906f32e7eSjoerg
95006f32e7eSjoerg CXErrorCode result;
95106f32e7eSjoerg auto IndexTranslationUnitImpl = [=, &result]() {
95206f32e7eSjoerg result = clang_indexTranslationUnit_Impl(
95306f32e7eSjoerg idxAction, client_data, index_callbacks, index_callbacks_size,
95406f32e7eSjoerg index_options, TU);
95506f32e7eSjoerg };
95606f32e7eSjoerg
95706f32e7eSjoerg llvm::CrashRecoveryContext CRC;
95806f32e7eSjoerg
95906f32e7eSjoerg if (!RunSafely(CRC, IndexTranslationUnitImpl)) {
96006f32e7eSjoerg fprintf(stderr, "libclang: crash detected during indexing TU\n");
96106f32e7eSjoerg
96206f32e7eSjoerg return 1;
96306f32e7eSjoerg }
96406f32e7eSjoerg
96506f32e7eSjoerg return result;
96606f32e7eSjoerg }
96706f32e7eSjoerg
clang_indexLoc_getFileLocation(CXIdxLoc location,CXIdxClientFile * indexFile,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)96806f32e7eSjoerg void clang_indexLoc_getFileLocation(CXIdxLoc location,
96906f32e7eSjoerg CXIdxClientFile *indexFile,
97006f32e7eSjoerg CXFile *file,
97106f32e7eSjoerg unsigned *line,
97206f32e7eSjoerg unsigned *column,
97306f32e7eSjoerg unsigned *offset) {
97406f32e7eSjoerg if (indexFile) *indexFile = nullptr;
97506f32e7eSjoerg if (file) *file = nullptr;
97606f32e7eSjoerg if (line) *line = 0;
97706f32e7eSjoerg if (column) *column = 0;
97806f32e7eSjoerg if (offset) *offset = 0;
97906f32e7eSjoerg
98006f32e7eSjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
98106f32e7eSjoerg if (!location.ptr_data[0] || Loc.isInvalid())
98206f32e7eSjoerg return;
98306f32e7eSjoerg
98406f32e7eSjoerg CXIndexDataConsumer &DataConsumer =
98506f32e7eSjoerg *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]);
98606f32e7eSjoerg DataConsumer.translateLoc(Loc, indexFile, file, line, column, offset);
98706f32e7eSjoerg }
98806f32e7eSjoerg
clang_indexLoc_getCXSourceLocation(CXIdxLoc location)98906f32e7eSjoerg CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) {
99006f32e7eSjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
99106f32e7eSjoerg if (!location.ptr_data[0] || Loc.isInvalid())
99206f32e7eSjoerg return clang_getNullLocation();
99306f32e7eSjoerg
99406f32e7eSjoerg CXIndexDataConsumer &DataConsumer =
99506f32e7eSjoerg *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]);
99606f32e7eSjoerg return cxloc::translateSourceLocation(DataConsumer.getASTContext(), Loc);
99706f32e7eSjoerg }
998