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