Diagnostic DiagnosticWrapToDiagnostic( DiagnosticWrap diagnostic_wrap ) { Diagnostic diagnostic; if ( !diagnostic_wrap ) return diagnostic; diagnostic.kind_ = DiagnosticSeverityToType( clang_getDiagnosticSeverity( diagnostic_wrap.get() ) ); // If this is an "ignored" diagnostic, there's no point in continuing since we // won't display those to the user if ( diagnostic.kind_ == 'I' ) return diagnostic; CXSourceLocation location = clang_getDiagnosticLocation( diagnostic_wrap.get() ); CXFile file; uint unused_offset; clang_getSpellingLocation( location, &file, &diagnostic.line_number_, &diagnostic.column_number_, &unused_offset ); diagnostic.filename_ = CXFileToFilepath( file ); diagnostic.text_ = CXStringToString( clang_getDiagnosticSpelling( diagnostic_wrap.get() ) ); diagnostic.long_formatted_text_ = FullDiagnosticText( diagnostic_wrap.get() ); return diagnostic; }
Diagnostic BuildDiagnostic( DiagnosticWrap diagnostic_wrap, CXTranslationUnit translation_unit ) { Diagnostic diagnostic; if ( !diagnostic_wrap ) return diagnostic; diagnostic.kind_ = DiagnosticSeverityToType( clang_getDiagnosticSeverity( diagnostic_wrap.get() ) ); // If this is an "ignored" diagnostic, there's no point in continuing since we // won't display those to the user if ( diagnostic.kind_ == INFORMATION ) return diagnostic; CXSourceLocation source_location = clang_getDiagnosticLocation( diagnostic_wrap.get() ); diagnostic.location_ = Location( source_location ); diagnostic.location_extent_ = GetLocationExtent( source_location, translation_unit ); diagnostic.ranges_ = GetRanges( diagnostic_wrap ); diagnostic.text_ = CXStringToString( clang_getDiagnosticSpelling( diagnostic_wrap.get() ) ); diagnostic.long_formatted_text_ = FullDiagnosticText( diagnostic_wrap.get() ); return diagnostic; }
static void dumpDiagnostics(const CXTranslationUnit &tu) { std::cout << "(\n"; std::string file; for (unsigned i = 0, diagnosticCount = clang_getNumDiagnostics(tu); i < diagnosticCount; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(tu, i); CXSourceLocation location = clang_getDiagnosticLocation(diagnostic); unsigned line, column, offset; if (clang_equalLocations(location, clang_getNullLocation())) { file.clear(); line = 0; column = 0; offset = 0; } else { CXFile cxFile; // clang_getInstantiationLocation() has been marked deprecated and // is aimed to be replaced by clang_getExpansionLocation(). #if CINDEX_VERSION >= 6 clang_getExpansionLocation(location, &cxFile, &line, &column, &offset); #else clang_getInstantiationLocation(location, &cxFile, &line, &column, &offset); #endif file = cxStringToStd(clang_getFileName(cxFile)); } const char *severity = diagnosticSeverity(diagnostic); std::string message = cxStringToStd(clang_getDiagnosticSpelling(diagnostic)); std::cout << '(' << support::quoted(file) // << ' ' << line // << ' ' << column // << ' ' << offset // << ' ' << severity // << ' ' << support::quoted(message) // << ")\n"; clang_disposeDiagnostic(diagnostic); } std::cout << ")\n"; }
void ClangUtils::printCompletionDiagnostics(CXCodeCompleteResults *res) { //// Report diagnostics to the log file const unsigned diagCount = clang_codeCompleteGetNumDiagnostics(res); for(unsigned i=0; i<diagCount; i++) { CXDiagnostic diag = clang_codeCompleteGetDiagnostic(res, i); CXString diagStr = clang_getDiagnosticSpelling(diag); wxString wxDiagString = wxString(clang_getCString(diagStr), wxConvUTF8); CL_DEBUG(wxT("Completion diagnostic [%d]: %s"), clang_getDiagnosticSeverity(diag), wxDiagString.c_str()); clang_disposeString(diagStr); clang_disposeDiagnostic(diag); } }
/** * \attention \c clang_formatDiagnostic have a nasty BUG since clang 3.3! * It fails (<em>pure virtual function call</em>) on messages w/o location attached * (like notices). DO NOT USE IT! EVER! * \todo Check for fresh clang versions! */ void TranslationUnit::appendDiagnostic(const CXDiagnostic& diag) { // Should we ignore this item? const auto severity = clang_getDiagnosticSeverity(diag); if (severity == CXDiagnostic_Ignored) return; kDebug(DEBUG_AREA) << "TU diagnostic severity level: " << severity; // Get record type clang::diagnostic_message::type type; switch (severity) { case CXDiagnostic_Note: type = clang::diagnostic_message::type::info; break; case CXDiagnostic_Warning: type = clang::diagnostic_message::type::warning; break; case CXDiagnostic_Error: case CXDiagnostic_Fatal: type = clang::diagnostic_message::type::error; break; default: assert(!"Unexpected severity level! Code review required!"); } // Get location clang::location loc; /// \attention \c Notes have no location attached!? if (severity != CXDiagnostic_Note) { try { loc = {clang_getDiagnosticLocation(diag)}; } catch (std::exception& e) { kDebug(DEBUG_AREA) << "TU diag.fmt: Can't get diagnostic location"; } } // Get diagnostic text and form a new diagnostic record m_last_diagnostic_messages.emplace_back( std::move(loc) , clang::toString(clang_getDiagnosticSpelling(diag)) , type ); }
void GmacsPreprocessor::codeCompletion(const QTextCursor &cursor) { int line = cursor.blockNumber(); int column = cursor.columnNumber(); //const char *name = filename->toLocal8Bit().data(); const char *name = clang_getCString(clang_getTranslationUnitSpelling(unit)); //qDebug() << cursor.document()->toPlainText(); //qDebug() << cursor.document()->toPlainText().size(); QString document = cursor.document()->toPlainText(); QString text = cursor.block().text(); QRegExp exp("\t"); int tab_count = text.count(exp); fprintf(stderr, "column = [%d]\n", cursor.positionInBlock()); //unsaved_file->Filename = name; //unsaved_file->Contents = document.toLocal8Bit().data(); //unsaved_file->Length = document.size(); if (!unit) return; CLANG_REPARSE(unit, NULL);//unsaved_file); fprintf(stderr, "line = [%d], column = [%d]\n", line+1, column + tab_count); fprintf(stderr, "name = [%s]\n", name); CXCodeCompleteResults *res = CLANG_CODE_COMPLETION(unit, name, line+1, column + tab_count); if (!res) fprintf(stderr, "ERROR: could not complete\n"); for (size_t i = 0; i < clang_codeCompleteGetNumDiagnostics(res); i++) { const CXDiagnostic &diag = clang_codeCompleteGetDiagnostic(res, i); const CXString &s = clang_getDiagnosticSpelling(diag); fprintf(stderr, "%s\n", clang_getCString(s)); } unsigned num_results = res->NumResults; fprintf(stderr, "num_results = [%d]\n"); for (unsigned i = 0; i < num_results; i++) { const CXCompletionString& str = res->Results[i].CompletionString; unsigned chunks = clang_getNumCompletionChunks(str); for (unsigned j = 0; j < chunks; j++) { const CXString& out = clang_getCompletionChunkText(str, j); //std::cout << clang_getCString(out) << " "; if (clang_getCompletionChunkKind(str, j) != CXCompletionChunk_TypedText) continue; } //std::cout << std::endl; } clang_disposeCodeCompleteResults(res); }
std::string diagnostic::spelling() { return string(clang_getDiagnosticSpelling(diag)).str(); }
/** Returns small diagnostic summary */ inline std::string diagnostic_summary(CXDiagnostic diag) { return cx2std(clang_getDiagnosticSpelling(diag)); }
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()); } }
bool ClangIndexer::diagnose() { if (!mClangUnit) { return false; } List<String> compilationErrors; const unsigned diagnosticCount = clang_getNumDiagnostics(mClangUnit); Map<Location, XmlEntry> xmlEntries; for (unsigned i=0; i<diagnosticCount; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(mClangUnit, i); const CXSourceLocation diagLoc = clang_getDiagnosticLocation(diagnostic); const Location loc = createLocation(diagLoc, 0); const uint32_t fileId = loc.fileId(); if (mData->visited.value(fileId)) { const String msg = RTags::eatString(clang_getDiagnosticSpelling(diagnostic)); const CXDiagnosticSeverity sev = clang_getDiagnosticSeverity(diagnostic); XmlEntry::Type type = XmlEntry::None; switch (sev) { case CXDiagnostic_Warning: type = XmlEntry::Warning; break; case CXDiagnostic_Error: case CXDiagnostic_Fatal: type = XmlEntry::Error; break; default: break; } if (type != XmlEntry::None) { const unsigned rangeCount = clang_getDiagnosticNumRanges(diagnostic); bool ok = false; for (unsigned rangePos = 0; rangePos < rangeCount; ++rangePos) { const CXSourceRange range = clang_getDiagnosticRange(diagnostic, rangePos); const CXSourceLocation start = clang_getRangeStart(range); const CXSourceLocation end = clang_getRangeEnd(range); unsigned startOffset, endOffset; clang_getSpellingLocation(start, 0, 0, 0, &startOffset); clang_getSpellingLocation(end, 0, 0, 0, &endOffset); if (!rangePos && !startOffset && !endOffset) { // huh, range invalid? fall back to diag location break; } else { unsigned int line, column; clang_getPresumedLocation(start, 0, &line, &column); const Location key(loc.fileId(), line, column); xmlEntries[key] = XmlEntry(type, msg, endOffset - startOffset); ok = true; break; } } if (!ok) { unsigned line, column; clang_getPresumedLocation(diagLoc, 0, &line, &column); const Location key(loc.fileId(), line, column); xmlEntries[key] = XmlEntry(type, msg); // no length } } // logDirect(RTags::CompilationError, msg.constData()); const unsigned fixItCount = clang_getDiagnosticNumFixIts(diagnostic); for (unsigned f=0; f<fixItCount; ++f) { CXSourceRange range; const CXStringScope stringScope = clang_getDiagnosticFixIt(diagnostic, f, &range); CXSourceLocation start = clang_getRangeStart(range); unsigned line, column; CXString file; clang_getPresumedLocation(start, &file, &line, &column); CXStringScope fileScope(file); const Location loc = createLocation(clang_getCString(file), line, column); if (mData->visited.value(loc.fileId())) { unsigned int startOffset, endOffset; CXSourceLocation end = clang_getRangeEnd(range); clang_getSpellingLocation(start, 0, 0, 0, &startOffset); clang_getSpellingLocation(end, 0, 0, 0, &endOffset); const char *string = clang_getCString(stringScope); error("Fixit for %s:%d:%d: Replace %d characters with [%s]", loc.path().constData(), line, column, endOffset - startOffset, string); XmlEntry &entry = xmlEntries[Location(loc.fileId(), line, column)]; entry.type = XmlEntry::Fixit; if (entry.message.isEmpty()) { entry.message = String::format<64>("did you mean '%s'?", string); } entry.length = endOffset - startOffset; mData->fixIts[loc.fileId()].insert(FixIt(line, column, endOffset - startOffset, string)); } } } clang_disposeDiagnostic(diagnostic); } mData->xmlDiagnostics = "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>"; if (!xmlEntries.isEmpty()) { Map<Location, XmlEntry>::const_iterator entry = xmlEntries.begin(); const Map<Location, XmlEntry>::const_iterator end = xmlEntries.end(); const char *severities[] = { "none", "warning", "error", "fixit" }; uint32_t lastFileId = 0; while (entry != end) { const Location &loc = entry->first; const XmlEntry &xmlEntry = entry->second; if (loc.fileId() != lastFileId) { if (lastFileId) mData->xmlDiagnostics += "</file>"; lastFileId = loc.fileId(); mData->xmlDiagnostics += String::format<128>("<file name=\"%s\">", loc.path().constData()); } mData->xmlDiagnostics += String::format("<error line=\"%d\" column=\"%d\" %sseverity=\"%s\" message=\"%s\"/>", loc.line(), loc.column(), (xmlEntry.length <= 0 ? "" : String::format<32>("length=\"%d\" ", xmlEntry.length).constData()), severities[xmlEntry.type], xmlEscape(xmlEntry.message).constData()); ++entry; } if (lastFileId) mData->xmlDiagnostics += "</file>"; } for (Hash<uint32_t, bool>::const_iterator it = mData->visited.begin(); it != mData->visited.end(); ++it) { if (it->second) { const Map<Location, XmlEntry>::const_iterator x = xmlEntries.lower_bound(Location(it->first, 0, 0)); if (x == xmlEntries.end() || x->first.fileId() != it->first) { const String fn = Location::path(it->first); mData->xmlDiagnostics += String::format("<file name=\"%s\"/>", fn.constData()); } } } mData->xmlDiagnostics += "</checkstyle>"; return true; }