int main(int argc, const char* argv[]) { if (argc < 4) { std::cerr << "Usage:\n" << " " << argv[0] << " <dbFilename> <indexFilename> [<options>] <sourceFilename>\n"; return 1; } const char* dbFilename = argv[1]; const char* indexFilename = argv[2]; const char* sourceFilename = argv[argc-1]; // Set up the clang translation unit CXIndex cxindex = clang_createIndex(0, 0); CXTranslationUnit tu = clang_parseTranslationUnit( cxindex, 0, argv + 3, argc - 3, // Skip over dbFilename and indexFilename 0, 0, CXTranslationUnit_None); // Print any errors or warnings int n = clang_getNumDiagnostics(tu); if (n > 0) { int nErrors = 0; for (unsigned i = 0; i != n; ++i) { CXDiagnostic diag = clang_getDiagnostic(tu, i); CXString string = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); fprintf(stderr, "%s\n", clang_getCString(string)); if (clang_getDiagnosticSeverity(diag) == CXDiagnostic_Error || clang_getDiagnosticSeverity(diag) == CXDiagnostic_Fatal) nErrors++; } } // Create the index EverythingIndexer visitor(sourceFilename); clang_visitChildren( clang_getTranslationUnitCursor(tu), &visitorFunction, &visitor); ClicIndex& index = visitor.usrToReferences; // OK, now write the index to a compressed file std::ofstream fout(indexFilename); boost::iostreams::filtering_stream<boost::iostreams::output> zout; zout.push(boost::iostreams::gzip_compressor()); zout.push(fout); printIndex(zout, index); // Now open the database and add the index to it ClicDb db(dbFilename); BOOST_FOREACH(const ClicIndex::value_type& it, index) { const std::string& usr = it.first; db.addMultiple(usr, it.second); } return 0; }
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; }
std::vector<diagnostic> translation_unit::diagnose() { // Get all the diagnostics uint32_t n = clang_getNumDiagnostics(mUnit); if (n == 0) return {}; std::vector<diagnostic> ret; ret.reserve(n); for (uint32_t i = 0; i < n; ++i) { CXFile file; uint32_t row = 0, col = 0, offset = 0; CXDiagnostic diag = clang_getDiagnostic(mUnit, i); CXSourceLocation loc = clang_getDiagnosticLocation(diag); clang_getExpansionLocation( loc, &file, &row, &col, &offset ); ret.push_back({ { cx2std(clang_getFileName(file)), row, col }, clang_getDiagnosticSeverity(diag), diagnostic_text(diag), diagnostic_summary(diag) }); clang_disposeDiagnostic(diag); } return ret; }
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; }
void PrintDiagnostic(CXDiagnostic Diagnostic) { FILE *out = stderr; CXFile file; CXString Msg; unsigned display_opts = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; unsigned i, num_fixits; if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; Msg = clang_formatDiagnostic(Diagnostic, display_opts); fprintf(stderr, "%s\n", clang_getCString(Msg)); clang_disposeString(Msg); clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), &file, 0, 0, 0); if (!file) return; num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); for (i = 0; i != num_fixits; ++i) { CXSourceRange range; CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range); CXSourceLocation start = clang_getRangeStart(range); CXSourceLocation end = clang_getRangeEnd(range); unsigned start_line, start_column, end_line, end_column; CXFile start_file, end_file; clang_getInstantiationLocation(start, &start_file, &start_line, &start_column, 0); clang_getInstantiationLocation(end, &end_file, &end_line, &end_column, 0); if (clang_equalLocations(start, end)) { /* Insertion. */ if (start_file == file) fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n", clang_getCString(insertion_text), start_line, start_column); } else if (strcmp(clang_getCString(insertion_text), "") == 0) { /* Removal. */ if (start_file == file && end_file == file) { fprintf(out, "FIX-IT: Remove "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, "\n"); } } else { /* Replacement. */ if (start_file == end_file) { fprintf(out, "FIX-IT: Replace "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text)); } break; } clang_disposeString(insertion_text); } }
void Irony::check(const std::string &file, const std::vector<std::string> &flags, const std::vector<CXUnsavedFile> &unsavedFiles) { std::cout << "("; unsigned numDiag = 0; int fatals = 0; int errors = 0; int warnings = 0; CXTranslationUnit tu = tuManager_.parse(file, flags, unsavedFiles); if (tu) { numDiag = clang_getNumDiagnostics(tu); } else { fatals = 1; } for (unsigned i = 0; i < numDiag; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(tu, i); switch (clang_getDiagnosticSeverity(diagnostic)) { case CXDiagnostic_Fatal: fatals++; break; case CXDiagnostic_Error: errors++; break; case CXDiagnostic_Warning: warnings++; break; default: break; } clang_disposeDiagnostic(diagnostic); } if (fatals > 0) std::cout << " :fatals " << fatals; if (errors > 0) std::cout << " :errors " << errors; if (warnings > 0) std::cout << " :warnings " << warnings; 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 ); }
static const char *diagnosticSeverity(CXDiagnostic diagnostic) { switch (clang_getDiagnosticSeverity(diagnostic)) { case CXDiagnostic_Ignored: return "ignored"; case CXDiagnostic_Note: return "note"; case CXDiagnostic_Warning: return "warning"; case CXDiagnostic_Error: return "error"; case CXDiagnostic_Fatal: return "fatal"; } return "unknown"; }
DiagnosticSeverity Diagnostic::severity() const { return static_cast<DiagnosticSeverity>(clang_getDiagnosticSeverity(cxDiagnostic)); }
bool IndexerJob::diagnose(int build, int *errorCount) { if (errorCount) *errorCount = 0; if (!mUnits.at(build).second) { abort(); return false; } List<String> compilationErrors; const unsigned diagnosticCount = clang_getNumDiagnostics(mUnits.at(build).second); const unsigned options = Server::instance()->options().options; for (unsigned i=0; i<diagnosticCount; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(mUnits.at(build).second, i); int logLevel = INT_MAX; const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diagnostic); switch (severity) { case CXDiagnostic_Fatal: case CXDiagnostic_Error: if (errorCount) ++*errorCount; logLevel = Error; break; case CXDiagnostic_Warning: logLevel = Warning; break; case CXDiagnostic_Note: logLevel = Debug; break; case CXDiagnostic_Ignored: break; } const unsigned diagnosticOptions = (CXDiagnostic_DisplaySourceLocation| CXDiagnostic_DisplayColumn| CXDiagnostic_DisplaySourceRanges| CXDiagnostic_DisplayOption| CXDiagnostic_DisplayCategoryId| CXDiagnostic_DisplayCategoryName); const uint32_t fileId = createLocation(clang_getDiagnosticLocation(diagnostic), 0).fileId(); if (mVisitedFiles.contains(fileId)) { const String text = RTags::eatString(clang_formatDiagnostic(diagnostic, diagnosticOptions)); if (testLog(logLevel) || testLog(CompilationError)) { log(logLevel, "%s: %s => %s", mSourceInformation.sourceFile.constData(), mClangLines.at(build).constData(), text.constData()); compilationErrors.append(text); } const unsigned fixItCount = clang_getDiagnosticNumFixIts(diagnostic); RegExp rx; if (options & Server::IgnorePrintfFixits) { rx = "^%[A-Za-z0-9]\\+$"; } for (unsigned f=0; f<fixItCount; ++f) { CXSourceRange range; const String string = RTags::eatString(clang_getDiagnosticFixIt(diagnostic, f, &range)); unsigned startOffset; CXFile file; clang_getSpellingLocation(clang_getRangeStart(range), &file, 0, 0, &startOffset); unsigned endOffset; clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &endOffset); const Location loc(file, startOffset); if (options & Server::IgnorePrintfFixits && rx.indexIn(string) == 0) { error("Ignored fixit for %s: Replace %d-%d with [%s]", loc.path().constData(), startOffset, endOffset, string.constData()); } else { error("Fixit for %s: Replace %d-%d with [%s]", loc.path().constData(), startOffset, endOffset, string.constData()); compilationErrors.append(String::format<128>("Fixit for %s: Replace %d-%d with [%s]", loc.path().constData(), startOffset, endOffset, string.constData())); mData->fixIts[loc.fileId()].insert(FixIt(startOffset, endOffset, string)); } } } clang_disposeDiagnostic(diagnostic); } if (testLog(CompilationError)) sendDiagnostics(compilationErrors); return !isAborted(); }
CXDiagnosticSeverity diagnostic::severity() { return clang_getDiagnosticSeverity(diag); }
CppInstr::eErrorTypes CppInstr::parse(OovStringRef const srcFn, OovStringRef const srcRootDir, OovStringRef const outDir, char const * const clang_args[], int num_clang_args) { eErrorTypes errType = ET_None; mOutputFileContents.read(srcFn); mTopParseFn.setPath(srcFn, FP_File); FilePath rootDir(srcRootDir, FP_Dir); setFileDefine(mTopParseFn, rootDir); CXIndex index = clang_createIndex(1, 1); // This doesn't appear to change anything. // clang_toggleCrashRecovery(true); // Get inclusion directives to be in AST. unsigned options = 0; CXTranslationUnit tu; CXErrorCode errCode = clang_parseTranslationUnit2(index, srcFn, clang_args, num_clang_args, 0, 0, options, &tu); if(errCode == CXError_Success) { CXCursor rootCursor = clang_getTranslationUnitCursor(tu); try { clang_visitChildren(rootCursor, ::visitTranslationUnit, this); } catch(...) { errType = ET_ParseError; sCrashDiagnostics.setCrashed(); } std::string outFileName; for(int i=0; i<num_clang_args; i++) { std::string testArg = clang_args[i]; if(testArg.compare("-o") == 0) { if(i+1 < num_clang_args) outFileName = clang_args[i+1]; } } try { mOutputFileContents.write(outFileName); } catch(...) { errType = ET_ParseError; } std::string outErrFileName = outFileName; outErrFileName += "-err.txt"; size_t numDiags = clang_getNumDiagnostics(tu); if(numDiags > 0 || sCrashDiagnostics.hasCrashed()) { FILE *fp = fopen(outErrFileName.c_str(), "w"); if(fp) { sCrashDiagnostics.dumpCrashed(fp); for (size_t i = 0; i<numDiags; i++) { CXDiagnostic diag = clang_getDiagnostic(tu, i); CXDiagnosticSeverity sev = clang_getDiagnosticSeverity(diag); if(errType == ET_None || errType == ET_CompileWarnings) { if(sev >= CXDiagnostic_Error) errType = ET_CompileErrors; else errType = ET_CompileWarnings; } CXStringDisposer diagStr = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); fprintf(fp, "%s\n", diagStr.c_str()); } fprintf(fp, "Arguments: %s %s %s ", static_cast<char const *>(srcFn), static_cast<char const *>(srcRootDir), static_cast<char const *>(outDir)); for(int i=0 ; i<num_clang_args; i++) { fprintf(fp, "%s ", clang_args[i]); } fprintf(fp, "\n"); fclose(fp); } } else { unlink(outErrFileName.c_str()); } FilePath covDir(outDir, FP_Dir); updateCoverageHeader(mTopParseFn, covDir, mInstrCount); updateCoverageSource(mTopParseFn, covDir); } else { errType = ET_CLangError; } return errType; }
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; }
void PrintDiagnostic(CXDiagnostic Diagnostic) { FILE *out = stderr; CXFile file; CXString text; unsigned display_opts = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; unsigned i, num_fixits; clang_displayDiagnostic(Diagnostic, out, display_opts); if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), &file, 0, 0, 0); if (!file) return; num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); for (i = 0; i != num_fixits; ++i) { switch (clang_getDiagnosticFixItKind(Diagnostic, i)) { case CXFixIt_Insertion: { CXSourceLocation insertion_loc; CXFile insertion_file; unsigned insertion_line, insertion_column; text = clang_getDiagnosticFixItInsertion(Diagnostic, i, &insertion_loc); clang_getInstantiationLocation(insertion_loc, &insertion_file, &insertion_line, &insertion_column, 0); if (insertion_file == file) fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n", clang_getCString(text), insertion_line, insertion_column); clang_disposeString(text); break; } case CXFixIt_Removal: { CXFile start_file, end_file; unsigned start_line, start_column, end_line, end_column; CXSourceRange remove_range = clang_getDiagnosticFixItRemoval(Diagnostic, i); clang_getInstantiationLocation(clang_getRangeStart(remove_range), &start_file, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(remove_range), &end_file, &end_line, &end_column, 0); if (start_file == file && end_file == file) { fprintf(out, "FIX-IT: Remove "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, "\n"); } break; } case CXFixIt_Replacement: { CXFile start_file, end_file; unsigned start_line, start_column, end_line, end_column; CXSourceRange remove_range; text = clang_getDiagnosticFixItReplacement(Diagnostic, i,&remove_range); clang_getInstantiationLocation(clang_getRangeStart(remove_range), &start_file, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(remove_range), &end_file, &end_line, &end_column, 0); if (start_file == end_file) { fprintf(out, "FIX-IT: Replace "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, " with \"%s\"\n", clang_getCString(text)); } clang_disposeString(text); break; } } } }