static void clang_indexTranslationUnit_Impl(void *UserData) { IndexTranslationUnitInfo *ITUI = static_cast<IndexTranslationUnitInfo*>(UserData); CXTranslationUnit TU = ITUI->TU; CXClientData client_data = ITUI->client_data; IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; unsigned index_callbacks_size = ITUI->index_callbacks_size; unsigned index_options = ITUI->index_options; ITUI->result = 1; // init as error. if (!TU) return; if (!client_index_callbacks || index_callbacks_size == 0) return; CIndexer *CXXIdx = (CIndexer*)TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); IndexerCallbacks CB; memset(&CB, 0, sizeof(CB)); unsigned ClientCBSize = index_callbacks_size < sizeof(CB) ? index_callbacks_size : sizeof(CB); memcpy(&CB, client_index_callbacks, ClientCBSize); OwningPtr<IndexingContext> IndexCtx; IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext> IndexCtxCleanup(IndexCtx.get()); OwningPtr<IndexingConsumer> IndexConsumer; IndexConsumer.reset(new IndexingConsumer(*IndexCtx)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer> IndexConsumerCleanup(IndexConsumer.get()); ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData); if (!Unit) return; ASTUnit::ConcurrencyCheck Check(*Unit); FileManager &FileMgr = Unit->getFileManager(); if (Unit->getOriginalSourceFileName().empty()) IndexCtx->enteredMainFile(0); else IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName())); IndexConsumer->Initialize(Unit->getASTContext()); indexPreprocessingRecord(*Unit, *IndexCtx); indexTranslationUnit(*Unit, *IndexCtx); indexDiagnostics(TU, *IndexCtx); ITUI->result = 0; }
static CXErrorCode clang_indexTranslationUnit_Impl( CXIndexAction idxAction, CXClientData client_data, IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, unsigned index_options, CXTranslationUnit TU) { // Check arguments. if (isNotUsableTU(TU)) { LOG_BAD_TU(TU); return CXError_InvalidArguments; } if (!client_index_callbacks || index_callbacks_size == 0) { return CXError_InvalidArguments; } CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); IndexerCallbacks CB; memset(&CB, 0, sizeof(CB)); unsigned ClientCBSize = index_callbacks_size < sizeof(CB) ? index_callbacks_size : sizeof(CB); memcpy(&CB, client_index_callbacks, ClientCBSize); auto DataConsumer = std::make_shared<CXIndexDataConsumer>(client_data, CB, index_options, TU); ASTUnit *Unit = cxtu::getASTUnit(TU); if (!Unit) return CXError_Failure; ASTUnit::ConcurrencyCheck Check(*Unit); if (const FileEntry *PCHFile = Unit->getPCHFile()) DataConsumer->importedPCH(PCHFile); FileManager &FileMgr = Unit->getFileManager(); if (Unit->getOriginalSourceFileName().empty()) DataConsumer->enteredMainFile(nullptr); else DataConsumer->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName())); DataConsumer->setASTContext(Unit->getASTContext()); DataConsumer->startedTranslationUnit(); indexPreprocessingRecord(*Unit, *DataConsumer); indexASTUnit(*Unit, DataConsumer, getIndexingOptionsFromCXOptions(index_options)); DataConsumer->indexDiagnostics(); return CXError_Success; }
static void clang_indexSourceFile_Impl(void *UserData) { IndexSourceFileInfo *ITUI = static_cast<IndexSourceFileInfo*>(UserData); CXIndex CIdx = (CXIndex)ITUI->idxAction; CXClientData client_data = ITUI->client_data; IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; unsigned index_callbacks_size = ITUI->index_callbacks_size; unsigned index_options = ITUI->index_options; const char *source_filename = ITUI->source_filename; const char * const *command_line_args = ITUI->command_line_args; int num_command_line_args = ITUI->num_command_line_args; struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files; unsigned num_unsaved_files = ITUI->num_unsaved_files; CXTranslationUnit *out_TU = ITUI->out_TU; unsigned TU_options = ITUI->TU_options; ITUI->result = 1; // init as error. if (out_TU) *out_TU = 0; bool requestedToGetTU = (out_TU != 0); if (!CIdx) return; if (!client_index_callbacks || index_callbacks_size == 0) return; IndexerCallbacks CB; memset(&CB, 0, sizeof(CB)); unsigned ClientCBSize = index_callbacks_size < sizeof(CB) ? index_callbacks_size : sizeof(CB); memcpy(&CB, client_index_callbacks, ClientCBSize); CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer(); // Configure the diagnostics. DiagnosticOptions DiagOpts; IntrusiveRefCntPtr<DiagnosticsEngine> Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, command_line_args, CaptureDiag, /*ShouldOwnClient=*/true, /*ShouldCloneClient=*/false)); // Recover resources if we crash before exiting this function. llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); OwningPtr<std::vector<const char *> > Args(new std::vector<const char*>()); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > ArgsCleanup(Args.get()); Args->insert(Args->end(), command_line_args, command_line_args + num_command_line_args); // The 'source_filename' argument is optional. If the caller does not // specify it then it is assumed that the source file is specified // in the actual argument list. // Put the source file after command_line_args otherwise if '-x' flag is // present it will be unused. if (source_filename) Args->push_back(source_filename); IntrusiveRefCntPtr<CompilerInvocation> CInvok(createInvocationFromCommandLine(*Args, Diags)); if (!CInvok) return; // Recover resources if we crash before exiting this function. llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > CInvokCleanup(CInvok.getPtr()); if (CInvok->getFrontendOpts().Inputs.empty()) return; OwningPtr<MemBufferOwner> BufOwner(new MemBufferOwner()); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup(BufOwner.get()); for (unsigned I = 0; I != num_unsaved_files; ++I) { StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer); BufOwner->Buffers.push_back(Buffer); } // Since libclang is primarily used by batch tools dealing with // (often very broken) source code, where spell-checking can have a // significant negative impact on performance (particularly when // precompiled headers are involved), we disable it. CInvok->getLangOpts()->SpellChecking = false; if (index_options & CXIndexOpt_SuppressWarnings) CInvok->getDiagnosticOpts().IgnoreWarnings = true; ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags, /*CaptureDiagnostics=*/true, /*UserFilesAreVolatile=*/true); OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner> CXTUCleanup(CXTU.get()); OwningPtr<IndexingFrontendAction> IndexAction; IndexAction.reset(new IndexingFrontendAction(client_data, CB, index_options, CXTU->getTU())); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction> IndexActionCleanup(IndexAction.get()); bool Persistent = requestedToGetTU; bool OnlyLocalDecls = false; bool PrecompilePreamble = false; bool CacheCodeCompletionResults = false; PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); PPOpts.AllowPCHWithCompilerErrors = true; if (requestedToGetTU) { OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; // FIXME: Add a flag for modules. CacheCodeCompletionResults = TU_options & CXTranslationUnit_CacheCompletionResults; if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) { PPOpts.DetailedRecord = true; } } IndexAction->EnablePPDetailedRecordForModules = PPOpts.DetailedRecord || (TU_options & CXTranslationUnit_DetailedPreprocessingRecord); if (!requestedToGetTU) PPOpts.DetailedRecord = false; DiagnosticErrorTrap DiagTrap(*Diags); bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags, IndexAction.get(), Unit, Persistent, CXXIdx->getClangResourcesPath(), OnlyLocalDecls, /*CaptureDiagnostics=*/true, PrecompilePreamble, CacheCodeCompletionResults, /*IncludeBriefCommentsInCodeCompletion=*/false, /*UserFilesAreVolatile=*/true); if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) printDiagsToStderr(Unit); if (!Success) return; if (out_TU) *out_TU = CXTU->takeTU(); ITUI->result = 0; // success. }
static void clang_indexTranslationUnit_Impl(void *UserData) { IndexTranslationUnitInfo *ITUI = static_cast<IndexTranslationUnitInfo*>(UserData); CXTranslationUnit TU = ITUI->TU; CXClientData client_data = ITUI->client_data; IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; unsigned index_callbacks_size = ITUI->index_callbacks_size; unsigned index_options = ITUI->index_options; // Set up the initial return value. ITUI->result = CXError_Failure; // Check arguments. if (isNotUsableTU(TU)) { LOG_BAD_TU(TU); ITUI->result = CXError_InvalidArguments; return; } if (!client_index_callbacks || index_callbacks_size == 0) { ITUI->result = CXError_InvalidArguments; return; } CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); IndexerCallbacks CB; memset(&CB, 0, sizeof(CB)); unsigned ClientCBSize = index_callbacks_size < sizeof(CB) ? index_callbacks_size : sizeof(CB); memcpy(&CB, client_index_callbacks, ClientCBSize); std::unique_ptr<IndexingContext> IndexCtx; IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext> IndexCtxCleanup(IndexCtx.get()); std::unique_ptr<IndexingConsumer> IndexConsumer; IndexConsumer.reset(new IndexingConsumer(*IndexCtx, nullptr)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer> IndexConsumerCleanup(IndexConsumer.get()); ASTUnit *Unit = cxtu::getASTUnit(TU); if (!Unit) return; ASTUnit::ConcurrencyCheck Check(*Unit); if (const FileEntry *PCHFile = Unit->getPCHFile()) IndexCtx->importedPCH(PCHFile); FileManager &FileMgr = Unit->getFileManager(); if (Unit->getOriginalSourceFileName().empty()) IndexCtx->enteredMainFile(nullptr); else IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName())); IndexConsumer->Initialize(Unit->getASTContext()); indexPreprocessingRecord(*Unit, *IndexCtx); indexTranslationUnit(*Unit, *IndexCtx); indexDiagnostics(TU, *IndexCtx); ITUI->result = CXError_Success; }
static CXCodeCompleteResults * clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename, unsigned complete_line, unsigned complete_column, ArrayRef<CXUnsavedFile> unsaved_files, unsigned options) { bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; bool SkipPreamble = options & CXCodeComplete_SkipPreamble; bool IncludeFixIts = options & CXCodeComplete_IncludeCompletionsWithFixIts; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); #endif #endif bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr; if (cxtu::isNotUsableTU(TU)) { LOG_BAD_TU(TU); return nullptr; } ASTUnit *AST = cxtu::getASTUnit(TU); if (!AST) return nullptr; CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); ASTUnit::ConcurrencyCheck Check(*AST); // Perform the remapping of source files. SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release())); } if (EnableLogging) { // FIXME: Add logging. } // Parse the resulting source file to find code-completion results. AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults( &AST->getFileManager()); Results->Results = nullptr; Results->NumResults = 0; // Create a code-completion consumer to capture the results. CodeCompleteOptions Opts; Opts.IncludeBriefComments = IncludeBriefComments; Opts.LoadExternal = !SkipPreamble; Opts.IncludeFixIts = IncludeFixIts; CaptureCompletionResults Capture(Opts, *Results, &TU); // Perform completion. std::vector<const char *> CArgs; for (const auto &Arg : TU->Arguments) CArgs.push_back(Arg.c_str()); std::string CompletionInvocation = llvm::formatv("-code-completion-at={0}:{1}:{2}", complete_filename, complete_line, complete_column) .str(); LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::CompletionOperation, TU->ParsingOptions, CArgs, CompletionInvocation, unsaved_files); AST->CodeComplete(complete_filename, complete_line, complete_column, RemappedFiles, (options & CXCodeComplete_IncludeMacros), (options & CXCodeComplete_IncludeCodePatterns), IncludeBriefComments, Capture, CXXIdx->getPCHContainerOperations(), *Results->Diag, Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); Results->DiagnosticsWrappers.resize(Results->Diagnostics.size()); // Keep a reference to the allocator used for cached global completions, so // that we can be sure that the memory used by our code completion strings // doesn't get freed due to subsequent reparses (while the code completion // results are still active). Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); SmallString<256> LogResult; llvm::raw_svector_ostream os(LogResult); // Figure out the language and whether or not it uses PCH. const char *lang = 0; bool usesPCH = false; for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); I != E; ++I) { if (*I == 0) continue; if (strcmp(*I, "-x") == 0) { if (I + 1 != E) { lang = *(++I); continue; } } else if (strcmp(*I, "-include") == 0) { if (I+1 != E) { const char *arg = *(++I); SmallString<512> pchName; { llvm::raw_svector_ostream os(pchName); os << arg << ".pth"; } pchName.push_back('\0'); struct stat stat_results; if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } } } os << "{ "; os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); os << ", \"numRes\": " << Results->NumResults; os << ", \"diags\": " << Results->Diagnostics.size(); os << ", \"pch\": " << (usesPCH ? "true" : "false"); os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; const char *name = getlogin(); os << ", \"user\": \"" << (name ? name : "unknown") << '"'; os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; os << " }"; StringRef res = os.str(); if (res.size() > 0) { do { // Setup the UDP socket. struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, &servaddr.sin_addr) <= 0) break; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) break; sendto(sockfd, res.data(), res.size(), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); close(sockfd); } while (false); } #endif #endif return Results; }
void clang_codeCompleteAt_Impl(void *UserData) { CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData); CXTranslationUnit TU = CCAI->TU; const char *complete_filename = CCAI->complete_filename; unsigned complete_line = CCAI->complete_line; unsigned complete_column = CCAI->complete_column; struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files; unsigned num_unsaved_files = CCAI->num_unsaved_files; unsigned options = CCAI->options; bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; CCAI->result = 0; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); #endif #endif bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; if (cxtu::isNotUsableTU(TU)) { LOG_BAD_TU(TU); return; } ASTUnit *AST = cxtu::getASTUnit(TU); if (!AST) return; CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); ASTUnit::ConcurrencyCheck Check(*AST); // Perform the remapping of source files. SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, Buffer)); } if (EnableLogging) { // FIXME: Add logging. } // Parse the resulting source file to find code-completion results. AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts()); Results->Results = 0; Results->NumResults = 0; // Create a code-completion consumer to capture the results. CodeCompleteOptions Opts; Opts.IncludeBriefComments = IncludeBriefComments; CaptureCompletionResults Capture(Opts, *Results, &TU); // Perform completion. AST->CodeComplete(complete_filename, complete_line, complete_column, RemappedFiles, (options & CXCodeComplete_IncludeMacros), (options & CXCodeComplete_IncludeCodePatterns), IncludeBriefComments, Capture, *Results->Diag, Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); // Keep a reference to the allocator used for cached global completions, so // that we can be sure that the memory used by our code completion strings // doesn't get freed due to subsequent reparses (while the code completion // results are still active). Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); SmallString<256> LogResult; llvm::raw_svector_ostream os(LogResult); // Figure out the language and whether or not it uses PCH. const char *lang = 0; bool usesPCH = false; for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); I != E; ++I) { if (*I == 0) continue; if (strcmp(*I, "-x") == 0) { if (I + 1 != E) { lang = *(++I); continue; } } else if (strcmp(*I, "-include") == 0) { if (I+1 != E) { const char *arg = *(++I); SmallString<512> pchName; { llvm::raw_svector_ostream os(pchName); os << arg << ".pth"; } pchName.push_back('\0'); struct stat stat_results; if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } } } os << "{ "; os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); os << ", \"numRes\": " << Results->NumResults; os << ", \"diags\": " << Results->Diagnostics.size(); os << ", \"pch\": " << (usesPCH ? "true" : "false"); os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; const char *name = getlogin(); os << ", \"user\": \"" << (name ? name : "unknown") << '"'; os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; os << " }"; StringRef res = os.str(); if (res.size() > 0) { do { // Setup the UDP socket. struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, &servaddr.sin_addr) <= 0) break; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) break; sendto(sockfd, res.data(), res.size(), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); close(sockfd); } while (false); } #endif #endif CCAI->result = Results; }
static CXErrorCode clang_indexSourceFile_Impl( CXIndexAction cxIdxAction, CXClientData client_data, IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, unsigned index_options, const char *source_filename, const char *const *command_line_args, int num_command_line_args, ArrayRef<CXUnsavedFile> unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options) { if (out_TU) *out_TU = nullptr; bool requestedToGetTU = (out_TU != nullptr); if (!cxIdxAction) { return CXError_InvalidArguments; } if (!client_index_callbacks || index_callbacks_size == 0) { return CXError_InvalidArguments; } IndexerCallbacks CB; memset(&CB, 0, sizeof(CB)); unsigned ClientCBSize = index_callbacks_size < sizeof(CB) ? index_callbacks_size : sizeof(CB); memcpy(&CB, client_index_callbacks, ClientCBSize); IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction); CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx); if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); bool CaptureDiagnostics = !Logger::isLoggingEnabled(); CaptureDiagnosticConsumer *CaptureDiag = nullptr; if (CaptureDiagnostics) CaptureDiag = new CaptureDiagnosticConsumer(); // Configure the diagnostics. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, CaptureDiag, /*ShouldOwnClient=*/true)); // Recover resources if we crash before exiting this function. llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.get()); std::unique_ptr<std::vector<const char *>> Args( new std::vector<const char *>()); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > ArgsCleanup(Args.get()); Args->insert(Args->end(), command_line_args, command_line_args + num_command_line_args); // The 'source_filename' argument is optional. If the caller does not // specify it then it is assumed that the source file is specified // in the actual argument list. // Put the source file after command_line_args otherwise if '-x' flag is // present it will be unused. if (source_filename) Args->push_back(source_filename); IntrusiveRefCntPtr<CompilerInvocation> CInvok(createInvocationFromCommandLine(*Args, Diags)); if (!CInvok) return CXError_Failure; // Recover resources if we crash before exiting this function. llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > CInvokCleanup(CInvok.get()); if (CInvok->getFrontendOpts().Inputs.empty()) return CXError_Failure; typedef SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 8> MemBufferOwner; std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup( BufOwner.get()); for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get()); BufOwner->push_back(std::move(MB)); } // Since libclang is primarily used by batch tools dealing with // (often very broken) source code, where spell-checking can have a // significant negative impact on performance (particularly when // precompiled headers are involved), we disable it. CInvok->getLangOpts()->SpellChecking = false; if (index_options & CXIndexOpt_SuppressWarnings) CInvok->getDiagnosticOpts().IgnoreWarnings = true; ASTUnit *Unit = ASTUnit::create(CInvok.get(), Diags, CaptureDiagnostics, /*UserFilesAreVolatile=*/true); if (!Unit) return CXError_InvalidArguments; std::unique_ptr<CXTUOwner> CXTU( new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner> CXTUCleanup(CXTU.get()); // Enable the skip-parsed-bodies optimization only for C++; this may be // revisited. bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) && CInvok->getLangOpts()->CPlusPlus; if (SkipBodies) CInvok->getFrontendOpts().SkipFunctionBodies = true; std::unique_ptr<IndexingFrontendAction> IndexAction; IndexAction.reset(new IndexingFrontendAction(client_data, CB, index_options, CXTU->getTU(), SkipBodies ? IdxSession->SkipBodyData.get() : nullptr)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction> IndexActionCleanup(IndexAction.get()); bool Persistent = requestedToGetTU; bool OnlyLocalDecls = false; bool PrecompilePreamble = false; bool CacheCodeCompletionResults = false; PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); PPOpts.AllowPCHWithCompilerErrors = true; if (requestedToGetTU) { OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; // FIXME: Add a flag for modules. CacheCodeCompletionResults = TU_options & CXTranslationUnit_CacheCompletionResults; } if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) { PPOpts.DetailedRecord = true; } if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) PPOpts.DetailedRecord = false; DiagnosticErrorTrap DiagTrap(*Diags); bool Success = ASTUnit::LoadFromCompilerInvocationAction( CInvok.get(), CXXIdx->getPCHContainerOperations(), Diags, IndexAction.get(), Unit, Persistent, CXXIdx->getClangResourcesPath(), OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble, CacheCodeCompletionResults, /*IncludeBriefCommentsInCodeCompletion=*/false, /*UserFilesAreVolatile=*/true); if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) printDiagsToStderr(Unit); if (isASTReadError(Unit)) return CXError_ASTReadError; if (!Success) return CXError_Failure; if (out_TU) *out_TU = CXTU->takeTU(); return CXError_Success; }