int completion_reparseTranslationUnit(completion_Session *session) { struct CXUnsavedFile unsaved_files = __get_CXUnsavedFile(session); return clang_reparseTranslationUnit( session->cx_tu, 1, &unsaved_files, session->ParseOptions); }
// Argument taken as non-const ref because we need to be able to pass a // non-const pointer to clang. This function (and clang too) will not modify the // param though. void TranslationUnit::Reparse( std::vector< CXUnsavedFile > &unsaved_files, size_t parse_options ) { int failure = 0; { unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return; CXUnsavedFile *unsaved = unsaved_files.size() > 0 ? &unsaved_files[ 0 ] : NULL; failure = clang_reparseTranslationUnit( clang_translation_unit_, unsaved_files.size(), unsaved, parse_options ); } if ( failure ) { Destroy(); throw( ClangParseError() ); } UpdateLatestDiagnostics(); }
// Argument taken as non-const ref because we need to be able to pass a // non-const pointer to clang. This function (and clang too) will not modify the // param though. void TranslationUnit::Reparse( std::vector< CXUnsavedFile > &unsaved_files, size_t parse_options ) { CXErrorCode failure; { unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) { return; } CXUnsavedFile *unsaved = unsaved_files.empty() ? nullptr : &unsaved_files[ 0 ]; // This function should technically return a CXErrorCode enum but return an // int instead. failure = static_cast< CXErrorCode >( clang_reparseTranslationUnit( clang_translation_unit_, unsaved_files.size(), unsaved, parse_options ) ); } if ( failure != CXError_Success ) { Destroy(); throw ClangParseError( failure ); } UpdateLatestDiagnostics(); }
bool CodeFile::ReparseTranslationUnit(const std::string& code) { if (!translationUnit) return false; CXUnsavedFile file; file.Filename = path.c_str(); file.Contents = code.c_str(); file.Length = code.size(); return clang_reparseTranslationUnit(translationUnit, 1, &file, clang_defaultReparseOptions(translationUnit)) == 0; }
void reparseTranslationUnit(CXTranslationUnit &unit, CXUnsavedFile *unsaved, int unsavedCount) { assert(unit); if (clang_reparseTranslationUnit(unit, 0, unsaved, clang_defaultReparseOptions(unit)) != 0) { clang_disposeTranslationUnit(unit); unit = 0; } }
void TranslationUnit::reparseTranslationUnit() const { clang_reparseTranslationUnit(d->translationUnit, unsavedFiles().count(), unsavedFiles().cxUnsavedFiles(), clang_defaultReparseOptions(d->translationUnit)); d->needsToBeReparsed = false; }
bool ReparseTU(unsigned num_unsaved_files, CXUnsavedFile* unsaved_files) { if (clang_reparseTranslationUnit(ClangTU, num_unsaved_files, unsaved_files, clang_defaultReparseOptions(ClangTU))) { DEBUG(llvm::dbgs() << "Reparse failed\n"); return false; } DisplayDiagnostics(); return true; }
void translation_unit::reparse() { int err = clang_reparseTranslationUnit(tu, 0, 0, clang_defaultReparseOptions(tu)); if(err) { clang_disposeTranslationUnit(tu); tu = nullptr; throw error("unable to reparse tu"); } }
CXTranslationUnit ClangWorkerThread::DoCreateTU(CXIndex index, ClangThreadRequest* task, bool reparse) { wxFileName fn(task->GetFileName()); DoSetStatusMsg(wxString::Format(wxT("clang: parsing file %s..."), fn.GetFullName().c_str())); FileExtManager::FileType type = FileExtManager::GetType(task->GetFileName()); int argc(0); char** argv = MakeCommandLine(task, argc, type); for(int i = 0; i < argc; i++) { CL_DEBUG(wxT("Command Line Argument: %s"), wxString(argv[i], wxConvUTF8).c_str()); } std::string c_filename = task->GetFileName().mb_str(wxConvUTF8).data(); CL_DEBUG(wxT("Calling clang_parseTranslationUnit...")); // First time, need to create it unsigned flags; if(reparse) { flags = CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_Incomplete | CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_CXXChainedPCH; } else { flags = CXTranslationUnit_Incomplete | #if HAS_LIBCLANG_BRIEFCOMMENTS CXTranslationUnit_SkipFunctionBodies | #endif CXTranslationUnit_DetailedPreprocessingRecord; } CXTranslationUnit TU = clang_parseTranslationUnit(index, c_filename.c_str(), argv, argc, NULL, 0, flags); CL_DEBUG(wxT("Calling clang_parseTranslationUnit... done")); ClangUtils::FreeArgv(argv, argc); DoSetStatusMsg(wxString::Format(wxT("clang: parsing file %s...done"), fn.GetFullName().c_str())); if(TU && reparse) { CL_DEBUG(wxT("Calling clang_reparseTranslationUnit...")); if(clang_reparseTranslationUnit(TU, 0, NULL, clang_defaultReparseOptions(TU)) == 0) { CL_DEBUG(wxT("Calling clang_reparseTranslationUnit... done")); return TU; } else { CL_DEBUG(wxT("An error occured during reparsing of the TU for file %s. TU: %p"), task->GetFileName().c_str(), (void*)TU); // The only thing that left to be done here, is to dispose the TU clang_disposeTranslationUnit(TU); PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName()); return NULL; } } return TU; }
void TranslationUnit::reparse(const clang::unsaved_files_list& unsaved_files) { auto files = unsaved_files.get(); auto result = clang_reparseTranslationUnit( m_unit , files.size() , files.data() , clang_defaultReparseOptions(m_unit) ); if (result) throw Exception::ReparseFailure("It seems preparsed file is invalid"); }
bool parse( std::vector<CXUnsavedFile> unsavedfiles ) { if ( !valid ) { std::cout << "Warning, not valid!\n"; if ( !parse( orig_argc, orig_argv, unsavedfiles.data(), unsavedfiles.size() ) ) return false; } valid = !clang_reparseTranslationUnit( unit, unsavedfiles.size(), unsavedfiles.data(), options ); return valid; }
void Tokenizer::parse(OovStringRef fileName, OovStringRef buffer, size_t bufLen, char const * const clang_args[], size_t num_clang_args) { CLangAutoLock lock(mCLangLock, __LINE__, this); try { if(!mSourceFile) { // The clang_defaultCodeCompleteOptions() options are not for the parse // function, they are for the clang_codeCompleteAt func. unsigned options = clang_defaultEditingTranslationUnitOptions(); // This is required to allow go to definition to work with #include. options |= CXTranslationUnit_DetailedPreprocessingRecord; mSourceFilename = fileName; mContextIndex = clang_createIndex(1, 1); mTransUnit = clang_parseTranslationUnit(mContextIndex, fileName, clang_args, static_cast<int>(num_clang_args), 0, 0, options); } else { static CXUnsavedFile file; file.Filename = mSourceFilename.c_str(); file.Contents = buffer; file.Length = bufLen; unsigned options = clang_defaultReparseOptions(mTransUnit); int stat = clang_reparseTranslationUnit(mTransUnit, 1, &file, options); if(stat != 0) { clang_disposeTranslationUnit(mTransUnit); mTransUnit = nullptr; } } mSourceFile = clang_getFile(mTransUnit, fileName); } catch(...) { DUMP_PARSE_INT("Tokenizer::parse - CRASHED", 0); } }
void TranslationUnitUpdater::reparse() { UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments(); m_reparseErrorCode = clang_reparseTranslationUnit( m_cxTranslationUnit, unsaved.count(), unsaved.data(), clang_defaultReparseOptions(m_cxTranslationUnit)); if (reparseWasSuccessful()) { updateIncludeFilePaths(); m_out.reparseTimePoint = Clock::now(); m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint; } else { qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode; m_out.hasParseOrReparseFailed = true; } }
translation_unit& index::parse_translation_unit(const std::vector<std::string>& args, const std::vector<unsaved_file>& unsaved) { auto argv = convert_args(args); auto unsaved_files = convert_unsaved_files(unsaved); unsigned options = CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_CacheCompletionResults; auto tu = clang_parseTranslationUnit(idx, nullptr, argv.data(), argv.size(), unsaved_files.data(), unsaved_files.size(), options); if(!tu) throw error("unable to parse tu"); // Have to reparse to cache completion results. int err = clang_reparseTranslationUnit(tu, unsaved_files.size(), unsaved_files.data(), clang_defaultReparseOptions(tu)); if(err) { clang_disposeTranslationUnit(tu); throw error("unable to reparse tu"); } tus.emplace_back(tu); return tus.back(); }
void TextEdit::slotReparse() { //connect(this,SIGNAL(textChanged()), this,SLOT(slotReparse())); QTextCursor tc = textCursor(); tc.select(QTextCursor::WordUnderCursor); QString prefix = tc.selectedText(); completionList->clear(); qDebug()<<prefix; //clang_disposeTranslationUnit(cx_tu); struct CXUnsavedFile unsaved_file; unsaved_file.Filename = "/tmp/a.m"; unsaved_file.Contents = strdup(this->toPlainText().toStdString().c_str()); unsaved_file.Length = this->toPlainText().length(); clang_reparseTranslationUnit( cx_tu, 1, &unsaved_file, CXTranslationUnit_PrecompiledPreamble); CXFile file = clang_getFile(cx_tu, unsaved_file.Filename); CXSourceLocation start = clang_getLocationForOffset(cx_tu, file, 0); CXSourceLocation end = clang_getLocationForOffset(cx_tu, file, this->toPlainText().length()); CXSourceRange range= clang_getRange(start,end); CXToken *tokens; unsigned tokenCount; clang_tokenize(cx_tu,range, &tokens, &tokenCount); if (tokenCount > 0) { CXCursor *cursors = NULL; cursors = (CXCursor *)calloc(sizeof(CXCursor), tokenCount); clang_annotateTokens(cx_tu, tokens, tokenCount, cursors); for (unsigned i=0 ; i<tokenCount ; i++) { CXSourceRange sr = clang_getTokenExtent(cx_tu, tokens[i]); unsigned start, end; CXSourceLocation s = clang_getRangeStart(sr); CXSourceLocation e = clang_getRangeEnd(sr); clang_getInstantiationLocation(s, 0, 0, 0, &start); clang_getInstantiationLocation(e, 0, 0, 0, &end); qDebug()<<"start:"<<start<<"end:"<<end; /* if(start >end) { int tmp = start; start = end; end = tmp; } */ switch (cursors[i].kind) { case CXCursor_FirstRef... CXCursor_LastRef: break; case CXCursor_MacroDefinition: break; case CXCursor_MacroInstantiation: break; case CXCursor_FirstDecl...CXCursor_LastDecl: break; case CXCursor_ObjCMessageExpr: break; case CXCursor_DeclRefExpr: break; case CXCursor_PreprocessingDirective: { } break; default: break; } /* if(cursors[i].kind == CXCursor_FunctionDecl) setFormat(start, end-start, m_formatSingleLineComment);*/ } }
CXTranslationUnit TUManager::parse(const std::string & filename, const std::vector<std::string> & flags) { CXTranslationUnit tu = translationUnits_[filename]; if (! tu) { // FIXME: needed ? // Note: the -cc1 argument indicates the compiler front-end, and // not the driver, should be run. The compiler front-end has // several additional Clang specific features which are not // exposed through the GCC compatible driver interface. // from: http://clang.llvm.org/get_started.html // const_cast<std::vector<std::string> &>(flags).push_back("-cc1"); std::size_t nbArgs = flags.size(); const char **argv = 0; if (nbArgs > 0) { argv = new const char *[nbArgs + 1]; argv[nbArgs] = 0; for (std::size_t i = 0; i < nbArgs; ++i) argv[i] = flags[i].c_str(); } tu = clang_parseTranslationUnit(index_, filename.c_str(), argv, nbArgs, 0, 0, clang_defaultEditingTranslationUnitOptions() | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_CacheCompletionResults); delete [] argv; translationUnits_[filename] = tu; } if (! tu) { std::clog << "parsing \"" << filename << "\" failed." << std::endl; return 0; } // NOTE: Even at the first time the translation unit is reparsed, // because without this the completion is erroneous. // From the clang mailing list: // From: Douglas Gregor <*****@*****.**> // Subject: Re: Clang indexing library performance // Newsgroups: gmane.comp.compilers.clang.devel // ... // You want to use the "default editing options" when parsing the // translation unit // clang_defaultEditingTranslationUnitOptions() // and then reparse at least once. That will enable the various // code-completion optimizations that should bring this time down // significantly. if (clang_reparseTranslationUnit(tu, 0, 0, clang_defaultReparseOptions(tu))) { // a 'fatal' error occur (even a diagnostic is impossible) clang_disposeTranslationUnit(tu); translationUnits_[filename] = 0; } return tu; }
void ClangWorkerThread::ProcessRequest(ThreadRequest* request) { // Send start event PostEvent(wxEVT_CLANG_PCH_CACHE_STARTED, ""); ClangThreadRequest* task = dynamic_cast<ClangThreadRequest*>(request); wxASSERT_MSG(task, "ClangWorkerThread: NULL task"); { // A bit of optimization wxCriticalSectionLocker locker(m_criticalSection); if(task->GetContext() == CTX_CachePCH && m_cache.Contains(task->GetFileName())) { // Nothing to be done here PostEvent(wxEVT_CLANG_PCH_CACHE_ENDED, task->GetFileName()); return; } } CL_DEBUG(wxT("==========> [ ClangPchMakerThread ] ProcessRequest started: %s"), task->GetFileName().c_str()); CL_DEBUG(wxT("ClangWorkerThread:: processing request %d"), (int)task->GetContext()); ClangCacheEntry cacheEntry = findEntry(task->GetFileName()); CXTranslationUnit TU = cacheEntry.TU; CL_DEBUG(wxT("ClangWorkerThread:: found cached TU: %p"), (void*)TU); bool reparseRequired = true; if(!TU) { // First time creating the TU TU = DoCreateTU(task->GetIndex(), task, true); reparseRequired = false; cacheEntry.lastReparse = time(NULL); cacheEntry.TU = TU; cacheEntry.sourceFile = task->GetFileName(); } if(!TU) { CL_DEBUG(wxT("Failed to parse Translation UNIT...")); PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName()); return; } if(reparseRequired && task->GetContext() == ::CTX_ReparseTU) { DoSetStatusMsg(wxString::Format(wxT("clang: re-parsing file %s..."), task->GetFileName().c_str())); // We need to reparse the TU CL_DEBUG(wxT("Calling clang_reparseTranslationUnit... [CTX_ReparseTU]")); if(clang_reparseTranslationUnit(TU, 0, NULL, clang_defaultReparseOptions(TU)) == 0) { CL_DEBUG(wxT("Calling clang_reparseTranslationUnit... done [CTX_ReparseTU]")); cacheEntry.lastReparse = time(NULL); } else { CL_DEBUG(wxT("An error occured during reparsing of the TU for file %s. TU: %p"), task->GetFileName().c_str(), (void*)TU); // The only thing that left to be done here, is to dispose the TU clang_disposeTranslationUnit(TU); PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName()); return; } } // Construct a cache-returner class // which makes sure that the TU is cached // when we leave the current scope CacheReturner cr(this, cacheEntry); // Prepare the 'End' event wxCommandEvent eEnd(wxEVT_CLANG_PCH_CACHE_ENDED); ClangThreadReply* reply = new ClangThreadReply; reply->context = task->GetContext(); reply->filterWord = task->GetFilterWord(); reply->filename = task->GetFileName().c_str(); reply->results = NULL; wxFileName realFileName(reply->filename); if(realFileName.GetFullName().StartsWith(CODELITE_CLANG_FILE_PREFIX)) { realFileName.SetFullName(realFileName.GetFullName().Mid(strlen(CODELITE_CLANG_FILE_PREFIX))); } reply->filename = realFileName.GetFullPath(); if(task->GetContext() == CTX_CodeCompletion || task->GetContext() == CTX_WordCompletion || task->GetContext() == CTX_Calltip) { CL_DEBUG(wxT("Calling clang_codeCompleteAt...")); ClangThreadRequest::List_t usList = task->GetModifiedBuffers(); usList.push_back(std::make_pair(task->GetFileName(), task->GetDirtyBuffer())); ClangUnsavedFiles usf(usList); CL_DEBUG(wxT("Location: %s:%u:%u"), task->GetFileName().c_str(), task->GetLine(), task->GetColumn()); reply->results = clang_codeCompleteAt(TU, cstr(task->GetFileName()), task->GetLine(), task->GetColumn(), usf.GetUnsavedFiles(), usf.GetCount(), clang_defaultCodeCompleteOptions() #if HAS_LIBCLANG_BRIEFCOMMENTS | CXCodeComplete_IncludeBriefComments #endif ); cacheEntry.lastReparse = time(NULL); CL_DEBUG(wxT("Calling clang_codeCompleteAt... done")); wxString displayTip; bool hasErrors(false); if(reply->results) { unsigned maxErrorToDisplay = 10; std::set<wxString> errorMessages; unsigned errorCount = clang_codeCompleteGetNumDiagnostics(reply->results); // Collect all errors / fatal errors and report them back to user for(unsigned i = 0; i < errorCount; i++) { CXDiagnostic diag = clang_codeCompleteGetDiagnostic(reply->results, i); CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diag); if(!hasErrors) { hasErrors = (severity == CXDiagnostic_Error || severity == CXDiagnostic_Fatal); } if(severity == CXDiagnostic_Error || severity == CXDiagnostic_Fatal || severity == CXDiagnostic_Note) { CXString diagStr = clang_getDiagnosticSpelling(diag); wxString wxDiagString = wxString(clang_getCString(diagStr), wxConvUTF8); // Collect up to 10 error messages // and dont collect the same error twice if(errorMessages.find(wxDiagString) == errorMessages.end() && errorMessages.size() <= maxErrorToDisplay) { errorMessages.insert(wxDiagString); displayTip << wxDiagString.c_str() << wxT("\n"); } clang_disposeString(diagStr); } clang_disposeDiagnostic(diag); } CL_DEBUG(wxT("Found %u matches"), reply->results->NumResults); ClangUtils::printCompletionDiagnostics(reply->results); } if(!displayTip.IsEmpty() && hasErrors) { // Send back the error messages reply->errorMessage << "clang: " << displayTip; reply->errorMessage.RemoveLast(); // Free the results clang_disposeCodeCompleteResults(reply->results); reply->results = NULL; } // Send the event eEnd.SetClientData(reply); EventNotifier::Get()->AddPendingEvent(eEnd); } else if(task->GetContext() == CTX_GotoDecl || task->GetContext() == CTX_GotoImpl) { // Check to see if the file was modified since it was last reparsed // If it does, we need to re-parse it again wxFileName fnSource(cacheEntry.sourceFile); time_t fileModificationTime = fnSource.GetModificationTime().GetTicks(); time_t lastReparseTime = cacheEntry.lastReparse; if(fileModificationTime > lastReparseTime) { // The file needs to be re-parsed DoSetStatusMsg(wxString::Format(wxT("clang: re-parsing file %s...\n"), cacheEntry.sourceFile)); // Try reparsing the TU ClangThreadRequest::List_t usList = task->GetModifiedBuffers(); usList.push_back(std::make_pair(task->GetFileName(), task->GetDirtyBuffer())); ClangUnsavedFiles usf(usList); if(clang_reparseTranslationUnit( TU, usf.GetCount(), usf.GetUnsavedFiles(), clang_defaultReparseOptions(TU)) != 0) { // Failed to reparse cr.SetCancelled(true); // cancel the re-caching of the TU DoSetStatusMsg( wxString::Format("clang: clang_reparseTranslationUnit '%s' failed\n", cacheEntry.sourceFile)); clang_disposeTranslationUnit(TU); wxDELETE(reply); PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName()); return; } DoSetStatusMsg( wxString::Format("clang: clang_reparseTranslationUnit '%s' - done\n", cacheEntry.sourceFile)); // Update the 'lastReparse' field cacheEntry.lastReparse = time(NULL); } bool success = DoGotoDefinition(TU, task, reply); if(success) { eEnd.SetClientData(reply); EventNotifier::Get()->AddPendingEvent(eEnd); } else { DoSetStatusMsg(wxT("clang: no matches were found")); CL_DEBUG(wxT("Clang Goto Decl/Impl: could not find a cursor matching for position %s:%d:%d"), task->GetFileName().c_str(), (int)task->GetLine(), (int)task->GetColumn()); // Failed, delete the 'reply' allocatd earlier wxDELETE(reply); PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName()); } } else { wxDELETE(reply); PostEvent(wxEVT_CLANG_PCH_CACHE_ENDED, task->GetFileName()); } }