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