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