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