Indexing.cpp revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
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 36using namespace clang; 37using namespace cxtu; 38using namespace cxindex; 39 40static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx); 41 42namespace { 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 53class SessionSkipBodyData { }; 54 55class TUSkipBodyControl { 56public: 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/// 91class PPRegion { 92 llvm::sys::fs::UniqueID UniqueID; 93 time_t ModTime; 94 unsigned Offset; 95public: 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 112typedef llvm::DenseSet<PPRegion> PPRegionSetTy; 113 114} // end anonymous namespace 115 116namespace 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 146namespace { 147 148class SessionSkipBodyData { 149 llvm::sys::Mutex Mux; 150 PPRegionSetTy ParsedRegions; 151 152public: 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 169class 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 179public: 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 207private: 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 247class IndexPPCallbacks : public PPCallbacks { 248 Preprocessor &PP; 249 IndexingContext &IndexCtx; 250 bool IsMainFileEntered; 251 252public: 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 303class IndexingConsumer : public ASTConsumer { 304 IndexingContext &IndexCtx; 305 TUSkipBodyControl *SKCtrl; 306 307public: 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 386class CaptureDiagnosticConsumer : public DiagnosticConsumer { 387 SmallVector<StoredDiagnostic, 4> Errors; 388public: 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 401class IndexingFrontendAction : public ASTFrontendAction { 402 IndexingContext IndexCtx; 403 CXTranslationUnit CXTU; 404 405 SessionSkipBodyData *SKData; 406 std::unique_ptr<TUSkipBodyControl> SKCtrl; 407 408public: 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 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(new IndexPPCallbacks(PP, IndexCtx)); 429 IndexCtx.setPreprocessor(PP); 430 431 if (SKData) { 432 PPConditionalDirectiveRecord * 433 PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager()); 434 PP.addPPCallbacks(PPRec); 435 SKCtrl.reset(new TUSkipBodyControl(*SKData, *PPRec, PP)); 436 } 437 438 return new IndexingConsumer(IndexCtx, SKCtrl.get()); 439 } 440 441 void EndSourceFileAction() override { 442 indexDiagnostics(CXTU, IndexCtx); 443 } 444 445 TranslationUnitKind getTranslationUnitKind() override { 446 if (IndexCtx.shouldIndexImplicitTemplateInsts()) 447 return TU_Complete; 448 else 449 return TU_Prefix; 450 } 451 bool hasCodeCompletionSupport() const override { return false; } 452}; 453 454//===----------------------------------------------------------------------===// 455// clang_indexSourceFileUnit Implementation 456//===----------------------------------------------------------------------===// 457 458struct IndexSessionData { 459 CXIndex CIdx; 460 std::unique_ptr<SessionSkipBodyData> SkipBodyData; 461 462 explicit IndexSessionData(CXIndex cIdx) 463 : CIdx(cIdx), SkipBodyData(new SessionSkipBodyData) {} 464}; 465 466struct IndexSourceFileInfo { 467 CXIndexAction idxAction; 468 CXClientData client_data; 469 IndexerCallbacks *index_callbacks; 470 unsigned index_callbacks_size; 471 unsigned index_options; 472 const char *source_filename; 473 const char *const *command_line_args; 474 int num_command_line_args; 475 struct CXUnsavedFile *unsaved_files; 476 unsigned num_unsaved_files; 477 CXTranslationUnit *out_TU; 478 unsigned TU_options; 479 int result; 480}; 481 482struct MemBufferOwner { 483 SmallVector<const llvm::MemoryBuffer *, 8> Buffers; 484 485 ~MemBufferOwner() { 486 for (SmallVectorImpl<const llvm::MemoryBuffer *>::iterator 487 I = Buffers.begin(), E = Buffers.end(); I != E; ++I) 488 delete *I; 489 } 490}; 491 492} // anonymous namespace 493 494static void clang_indexSourceFile_Impl(void *UserData) { 495 IndexSourceFileInfo *ITUI = 496 static_cast<IndexSourceFileInfo*>(UserData); 497 CXIndexAction cxIdxAction = ITUI->idxAction; 498 CXClientData client_data = ITUI->client_data; 499 IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; 500 unsigned index_callbacks_size = ITUI->index_callbacks_size; 501 unsigned index_options = ITUI->index_options; 502 const char *source_filename = ITUI->source_filename; 503 const char * const *command_line_args = ITUI->command_line_args; 504 int num_command_line_args = ITUI->num_command_line_args; 505 struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files; 506 unsigned num_unsaved_files = ITUI->num_unsaved_files; 507 CXTranslationUnit *out_TU = ITUI->out_TU; 508 unsigned TU_options = ITUI->TU_options; 509 510 // Set up the initial return value. 511 ITUI->result = CXError_Failure; 512 513 if (out_TU) 514 *out_TU = 0; 515 bool requestedToGetTU = (out_TU != 0); 516 517 if (!cxIdxAction) { 518 ITUI->result = CXError_InvalidArguments; 519 return; 520 } 521 if (!client_index_callbacks || index_callbacks_size == 0) { 522 ITUI->result = CXError_InvalidArguments; 523 return; 524 } 525 526 IndexerCallbacks CB; 527 memset(&CB, 0, sizeof(CB)); 528 unsigned ClientCBSize = index_callbacks_size < sizeof(CB) 529 ? index_callbacks_size : sizeof(CB); 530 memcpy(&CB, client_index_callbacks, ClientCBSize); 531 532 IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction); 533 CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx); 534 535 if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) 536 setThreadBackgroundPriority(); 537 538 bool CaptureDiagnostics = !Logger::isLoggingEnabled(); 539 540 CaptureDiagnosticConsumer *CaptureDiag = 0; 541 if (CaptureDiagnostics) 542 CaptureDiag = new CaptureDiagnosticConsumer(); 543 544 // Configure the diagnostics. 545 IntrusiveRefCntPtr<DiagnosticsEngine> 546 Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, 547 CaptureDiag, 548 /*ShouldOwnClient=*/true)); 549 550 // Recover resources if we crash before exiting this function. 551 llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, 552 llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > 553 DiagCleanup(Diags.getPtr()); 554 555 std::unique_ptr<std::vector<const char *>> Args( 556 new std::vector<const char *>()); 557 558 // Recover resources if we crash before exiting this method. 559 llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > 560 ArgsCleanup(Args.get()); 561 562 Args->insert(Args->end(), command_line_args, 563 command_line_args + num_command_line_args); 564 565 // The 'source_filename' argument is optional. If the caller does not 566 // specify it then it is assumed that the source file is specified 567 // in the actual argument list. 568 // Put the source file after command_line_args otherwise if '-x' flag is 569 // present it will be unused. 570 if (source_filename) 571 Args->push_back(source_filename); 572 573 IntrusiveRefCntPtr<CompilerInvocation> 574 CInvok(createInvocationFromCommandLine(*Args, Diags)); 575 576 if (!CInvok) 577 return; 578 579 // Recover resources if we crash before exiting this function. 580 llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, 581 llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > 582 CInvokCleanup(CInvok.getPtr()); 583 584 if (CInvok->getFrontendOpts().Inputs.empty()) 585 return; 586 587 std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner()); 588 589 // Recover resources if we crash before exiting this method. 590 llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> 591 BufOwnerCleanup(BufOwner.get()); 592 593 for (unsigned I = 0; I != num_unsaved_files; ++I) { 594 StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); 595 const llvm::MemoryBuffer *Buffer 596 = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); 597 CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer); 598 BufOwner->Buffers.push_back(Buffer); 599 } 600 601 // Since libclang is primarily used by batch tools dealing with 602 // (often very broken) source code, where spell-checking can have a 603 // significant negative impact on performance (particularly when 604 // precompiled headers are involved), we disable it. 605 CInvok->getLangOpts()->SpellChecking = false; 606 607 if (index_options & CXIndexOpt_SuppressWarnings) 608 CInvok->getDiagnosticOpts().IgnoreWarnings = true; 609 610 ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags, 611 CaptureDiagnostics, 612 /*UserFilesAreVolatile=*/true); 613 if (!Unit) { 614 ITUI->result = CXError_InvalidArguments; 615 return; 616 } 617 618 std::unique_ptr<CXTUOwner> CXTU( 619 new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); 620 621 // Recover resources if we crash before exiting this method. 622 llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner> 623 CXTUCleanup(CXTU.get()); 624 625 // Enable the skip-parsed-bodies optimization only for C++; this may be 626 // revisited. 627 bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) && 628 CInvok->getLangOpts()->CPlusPlus; 629 if (SkipBodies) 630 CInvok->getFrontendOpts().SkipFunctionBodies = true; 631 632 std::unique_ptr<IndexingFrontendAction> IndexAction; 633 IndexAction.reset(new IndexingFrontendAction(client_data, CB, 634 index_options, CXTU->getTU(), 635 SkipBodies ? IdxSession->SkipBodyData.get() : 0)); 636 637 // Recover resources if we crash before exiting this method. 638 llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction> 639 IndexActionCleanup(IndexAction.get()); 640 641 bool Persistent = requestedToGetTU; 642 bool OnlyLocalDecls = false; 643 bool PrecompilePreamble = false; 644 bool CacheCodeCompletionResults = false; 645 PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); 646 PPOpts.AllowPCHWithCompilerErrors = true; 647 648 if (requestedToGetTU) { 649 OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); 650 PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; 651 // FIXME: Add a flag for modules. 652 CacheCodeCompletionResults 653 = TU_options & CXTranslationUnit_CacheCompletionResults; 654 } 655 656 if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) { 657 PPOpts.DetailedRecord = true; 658 } 659 660 if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) 661 PPOpts.DetailedRecord = false; 662 663 DiagnosticErrorTrap DiagTrap(*Diags); 664 bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags, 665 IndexAction.get(), 666 Unit, 667 Persistent, 668 CXXIdx->getClangResourcesPath(), 669 OnlyLocalDecls, 670 CaptureDiagnostics, 671 PrecompilePreamble, 672 CacheCodeCompletionResults, 673 /*IncludeBriefCommentsInCodeCompletion=*/false, 674 /*UserFilesAreVolatile=*/true); 675 if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) 676 printDiagsToStderr(Unit); 677 678 if (isASTReadError(Unit)) { 679 ITUI->result = CXError_ASTReadError; 680 return; 681 } 682 683 if (!Success) 684 return; 685 686 if (out_TU) 687 *out_TU = CXTU->takeTU(); 688 689 ITUI->result = CXError_Success; 690} 691 692//===----------------------------------------------------------------------===// 693// clang_indexTranslationUnit Implementation 694//===----------------------------------------------------------------------===// 695 696namespace { 697 698struct IndexTranslationUnitInfo { 699 CXIndexAction idxAction; 700 CXClientData client_data; 701 IndexerCallbacks *index_callbacks; 702 unsigned index_callbacks_size; 703 unsigned index_options; 704 CXTranslationUnit TU; 705 int result; 706}; 707 708} // anonymous namespace 709 710static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) { 711 Preprocessor &PP = Unit.getPreprocessor(); 712 if (!PP.getPreprocessingRecord()) 713 return; 714 715 // FIXME: Only deserialize inclusion directives. 716 717 PreprocessingRecord::iterator I, E; 718 std::tie(I, E) = Unit.getLocalPreprocessingEntities(); 719 720 bool isModuleFile = Unit.isModuleFile(); 721 for (; I != E; ++I) { 722 PreprocessedEntity *PPE = *I; 723 724 if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) { 725 SourceLocation Loc = ID->getSourceRange().getBegin(); 726 // Modules have synthetic main files as input, give an invalid location 727 // if the location points to such a file. 728 if (isModuleFile && Unit.isInMainFileID(Loc)) 729 Loc = SourceLocation(); 730 IdxCtx.ppIncludedFile(Loc, ID->getFileName(), 731 ID->getFile(), 732 ID->getKind() == InclusionDirective::Import, 733 !ID->wasInQuotes(), ID->importedModule()); 734 } 735 } 736} 737 738static bool topLevelDeclVisitor(void *context, const Decl *D) { 739 IndexingContext &IdxCtx = *static_cast<IndexingContext*>(context); 740 IdxCtx.indexTopLevelDecl(D); 741 if (IdxCtx.shouldAbort()) 742 return false; 743 return true; 744} 745 746static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) { 747 Unit.visitLocalTopLevelDecls(&IdxCtx, topLevelDeclVisitor); 748} 749 750static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) { 751 if (!IdxCtx.hasDiagnosticCallback()) 752 return; 753 754 CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(TU); 755 IdxCtx.handleDiagnosticSet(DiagSet); 756} 757 758static void clang_indexTranslationUnit_Impl(void *UserData) { 759 IndexTranslationUnitInfo *ITUI = 760 static_cast<IndexTranslationUnitInfo*>(UserData); 761 CXTranslationUnit TU = ITUI->TU; 762 CXClientData client_data = ITUI->client_data; 763 IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; 764 unsigned index_callbacks_size = ITUI->index_callbacks_size; 765 unsigned index_options = ITUI->index_options; 766 767 // Set up the initial return value. 768 ITUI->result = CXError_Failure; 769 770 // Check arguments. 771 if (isNotUsableTU(TU)) { 772 LOG_BAD_TU(TU); 773 ITUI->result = CXError_InvalidArguments; 774 return; 775 } 776 if (!client_index_callbacks || index_callbacks_size == 0) { 777 ITUI->result = CXError_InvalidArguments; 778 return; 779 } 780 781 CIndexer *CXXIdx = TU->CIdx; 782 if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) 783 setThreadBackgroundPriority(); 784 785 IndexerCallbacks CB; 786 memset(&CB, 0, sizeof(CB)); 787 unsigned ClientCBSize = index_callbacks_size < sizeof(CB) 788 ? index_callbacks_size : sizeof(CB); 789 memcpy(&CB, client_index_callbacks, ClientCBSize); 790 791 std::unique_ptr<IndexingContext> IndexCtx; 792 IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU)); 793 794 // Recover resources if we crash before exiting this method. 795 llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext> 796 IndexCtxCleanup(IndexCtx.get()); 797 798 std::unique_ptr<IndexingConsumer> IndexConsumer; 799 IndexConsumer.reset(new IndexingConsumer(*IndexCtx, 0)); 800 801 // Recover resources if we crash before exiting this method. 802 llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer> 803 IndexConsumerCleanup(IndexConsumer.get()); 804 805 ASTUnit *Unit = cxtu::getASTUnit(TU); 806 if (!Unit) 807 return; 808 809 ASTUnit::ConcurrencyCheck Check(*Unit); 810 811 if (const FileEntry *PCHFile = Unit->getPCHFile()) 812 IndexCtx->importedPCH(PCHFile); 813 814 FileManager &FileMgr = Unit->getFileManager(); 815 816 if (Unit->getOriginalSourceFileName().empty()) 817 IndexCtx->enteredMainFile(0); 818 else 819 IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName())); 820 821 IndexConsumer->Initialize(Unit->getASTContext()); 822 823 indexPreprocessingRecord(*Unit, *IndexCtx); 824 indexTranslationUnit(*Unit, *IndexCtx); 825 indexDiagnostics(TU, *IndexCtx); 826 827 ITUI->result = CXError_Success; 828} 829 830//===----------------------------------------------------------------------===// 831// libclang public APIs. 832//===----------------------------------------------------------------------===// 833 834extern "C" { 835 836int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) { 837 return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory; 838} 839 840const CXIdxObjCContainerDeclInfo * 841clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) { 842 if (!DInfo) 843 return 0; 844 845 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); 846 if (const ObjCContainerDeclInfo * 847 ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI)) 848 return &ContInfo->ObjCContDeclInfo; 849 850 return 0; 851} 852 853const CXIdxObjCInterfaceDeclInfo * 854clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) { 855 if (!DInfo) 856 return 0; 857 858 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); 859 if (const ObjCInterfaceDeclInfo * 860 InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) 861 return &InterInfo->ObjCInterDeclInfo; 862 863 return 0; 864} 865 866const CXIdxObjCCategoryDeclInfo * 867clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){ 868 if (!DInfo) 869 return 0; 870 871 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); 872 if (const ObjCCategoryDeclInfo * 873 CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) 874 return &CatInfo->ObjCCatDeclInfo; 875 876 return 0; 877} 878 879const CXIdxObjCProtocolRefListInfo * 880clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) { 881 if (!DInfo) 882 return 0; 883 884 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); 885 886 if (const ObjCInterfaceDeclInfo * 887 InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) 888 return InterInfo->ObjCInterDeclInfo.protocols; 889 890 if (const ObjCProtocolDeclInfo * 891 ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI)) 892 return &ProtInfo->ObjCProtoRefListInfo; 893 894 if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) 895 return CatInfo->ObjCCatDeclInfo.protocols; 896 897 return 0; 898} 899 900const CXIdxObjCPropertyDeclInfo * 901clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) { 902 if (!DInfo) 903 return 0; 904 905 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); 906 if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI)) 907 return &PropInfo->ObjCPropDeclInfo; 908 909 return 0; 910} 911 912const CXIdxIBOutletCollectionAttrInfo * 913clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) { 914 if (!AInfo) 915 return 0; 916 917 const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo); 918 if (const IBOutletCollectionInfo * 919 IBInfo = dyn_cast<IBOutletCollectionInfo>(DI)) 920 return &IBInfo->IBCollInfo; 921 922 return 0; 923} 924 925const CXIdxCXXClassDeclInfo * 926clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) { 927 if (!DInfo) 928 return 0; 929 930 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); 931 if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI)) 932 return &ClassInfo->CXXClassInfo; 933 934 return 0; 935} 936 937CXIdxClientContainer 938clang_index_getClientContainer(const CXIdxContainerInfo *info) { 939 if (!info) 940 return 0; 941 const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); 942 return Container->IndexCtx->getClientContainerForDC(Container->DC); 943} 944 945void clang_index_setClientContainer(const CXIdxContainerInfo *info, 946 CXIdxClientContainer client) { 947 if (!info) 948 return; 949 const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); 950 Container->IndexCtx->addContainerInMap(Container->DC, client); 951} 952 953CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) { 954 if (!info) 955 return 0; 956 const EntityInfo *Entity = static_cast<const EntityInfo *>(info); 957 return Entity->IndexCtx->getClientEntity(Entity->Dcl); 958} 959 960void clang_index_setClientEntity(const CXIdxEntityInfo *info, 961 CXIdxClientEntity client) { 962 if (!info) 963 return; 964 const EntityInfo *Entity = static_cast<const EntityInfo *>(info); 965 Entity->IndexCtx->setClientEntity(Entity->Dcl, client); 966} 967 968CXIndexAction clang_IndexAction_create(CXIndex CIdx) { 969 return new IndexSessionData(CIdx); 970} 971 972void clang_IndexAction_dispose(CXIndexAction idxAction) { 973 if (idxAction) 974 delete static_cast<IndexSessionData *>(idxAction); 975} 976 977int clang_indexSourceFile(CXIndexAction idxAction, 978 CXClientData client_data, 979 IndexerCallbacks *index_callbacks, 980 unsigned index_callbacks_size, 981 unsigned index_options, 982 const char *source_filename, 983 const char * const *command_line_args, 984 int num_command_line_args, 985 struct CXUnsavedFile *unsaved_files, 986 unsigned num_unsaved_files, 987 CXTranslationUnit *out_TU, 988 unsigned TU_options) { 989 LOG_FUNC_SECTION { 990 *Log << source_filename << ": "; 991 for (int i = 0; i != num_command_line_args; ++i) 992 *Log << command_line_args[i] << " "; 993 } 994 995 IndexSourceFileInfo ITUI = { idxAction, client_data, index_callbacks, 996 index_callbacks_size, index_options, 997 source_filename, command_line_args, 998 num_command_line_args, unsaved_files, 999 num_unsaved_files, out_TU, TU_options, 1000 CXError_Failure }; 1001 1002 if (getenv("LIBCLANG_NOTHREADS")) { 1003 clang_indexSourceFile_Impl(&ITUI); 1004 return ITUI.result; 1005 } 1006 1007 llvm::CrashRecoveryContext CRC; 1008 1009 if (!RunSafely(CRC, clang_indexSourceFile_Impl, &ITUI)) { 1010 fprintf(stderr, "libclang: crash detected during indexing source file: {\n"); 1011 fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); 1012 fprintf(stderr, " 'command_line_args' : ["); 1013 for (int i = 0; i != num_command_line_args; ++i) { 1014 if (i) 1015 fprintf(stderr, ", "); 1016 fprintf(stderr, "'%s'", command_line_args[i]); 1017 } 1018 fprintf(stderr, "],\n"); 1019 fprintf(stderr, " 'unsaved_files' : ["); 1020 for (unsigned i = 0; i != num_unsaved_files; ++i) { 1021 if (i) 1022 fprintf(stderr, ", "); 1023 fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, 1024 unsaved_files[i].Length); 1025 } 1026 fprintf(stderr, "],\n"); 1027 fprintf(stderr, " 'options' : %d,\n", TU_options); 1028 fprintf(stderr, "}\n"); 1029 1030 return 1; 1031 } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { 1032 if (out_TU) 1033 PrintLibclangResourceUsage(*out_TU); 1034 } 1035 1036 return ITUI.result; 1037} 1038 1039int clang_indexTranslationUnit(CXIndexAction idxAction, 1040 CXClientData client_data, 1041 IndexerCallbacks *index_callbacks, 1042 unsigned index_callbacks_size, 1043 unsigned index_options, 1044 CXTranslationUnit TU) { 1045 LOG_FUNC_SECTION { 1046 *Log << TU; 1047 } 1048 1049 IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks, 1050 index_callbacks_size, index_options, TU, 1051 0 }; 1052 1053 if (getenv("LIBCLANG_NOTHREADS")) { 1054 clang_indexTranslationUnit_Impl(&ITUI); 1055 return ITUI.result; 1056 } 1057 1058 llvm::CrashRecoveryContext CRC; 1059 1060 if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) { 1061 fprintf(stderr, "libclang: crash detected during indexing TU\n"); 1062 1063 return 1; 1064 } 1065 1066 return ITUI.result; 1067} 1068 1069void clang_indexLoc_getFileLocation(CXIdxLoc location, 1070 CXIdxClientFile *indexFile, 1071 CXFile *file, 1072 unsigned *line, 1073 unsigned *column, 1074 unsigned *offset) { 1075 if (indexFile) *indexFile = 0; 1076 if (file) *file = 0; 1077 if (line) *line = 0; 1078 if (column) *column = 0; 1079 if (offset) *offset = 0; 1080 1081 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 1082 if (!location.ptr_data[0] || Loc.isInvalid()) 1083 return; 1084 1085 IndexingContext &IndexCtx = 1086 *static_cast<IndexingContext*>(location.ptr_data[0]); 1087 IndexCtx.translateLoc(Loc, indexFile, file, line, column, offset); 1088} 1089 1090CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) { 1091 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 1092 if (!location.ptr_data[0] || Loc.isInvalid()) 1093 return clang_getNullLocation(); 1094 1095 IndexingContext &IndexCtx = 1096 *static_cast<IndexingContext*>(location.ptr_data[0]); 1097 return cxloc::translateSourceLocation(IndexCtx.getASTContext(), Loc); 1098} 1099 1100} // end: extern "C" 1101 1102