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