Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -104,31 +104,28 @@ DiagPrinter->BeginSourceFile(LangOpts); } - void reportDiagnostic(const ClangTidyMessage &Message, - DiagnosticsEngine::Level Level, - const tooling::Replacements *Fixes = nullptr) { + void reportDiagnostic(const ClangTidyError &Error) { + const ClangTidyMessage &Message = Error.Message; SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); // Contains a pair for each attempted fix: location and whether the fix was // applied successfully. SmallVector, 4> FixLocations; { + auto Level = static_cast(Error.DiagLevel); DiagnosticBuilder Diag = - Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0")) - << Message.Message; - if (Fixes != nullptr) { - for (const tooling::Replacement &Fix : *Fixes) { - SourceLocation FixLoc = - getLocation(Fix.getFilePath(), Fix.getOffset()); - SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength()); - Diag << FixItHint::CreateReplacement(SourceRange(FixLoc, FixEndLoc), - Fix.getReplacementText()); - ++TotalFixes; - if (ApplyFixes) { - bool Success = Fix.isApplicable() && Fix.apply(Rewrite); - if (Success) - ++AppliedFixes; - FixLocations.push_back(std::make_pair(FixLoc, Success)); - } + Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]")) + << Message.Message << Error.CheckName; + for (const tooling::Replacement &Fix : Error.Fix) { + SourceLocation FixLoc = getLocation(Fix.getFilePath(), Fix.getOffset()); + SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength()); + Diag << FixItHint::CreateReplacement(SourceRange(FixLoc, FixEndLoc), + Fix.getReplacementText()); + ++TotalFixes; + if (ApplyFixes) { + bool Success = Fix.isApplicable() && Fix.apply(Rewrite); + if (Success) + ++AppliedFixes; + FixLocations.push_back(std::make_pair(FixLoc, Success)); } } } @@ -136,6 +133,8 @@ Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied : diag::note_fixit_failed); } + for (const ClangTidyMessage &Note : Error.Notes) + reportNote(Note); } void Finish() { @@ -157,6 +156,13 @@ return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset); } + void reportNote(const ClangTidyMessage &Message) { + SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); + DiagnosticBuilder Diag = + Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0")) + << Message.Message; + } + FileManager Files; LangOptions LangOpts; // FIXME: use langopts from each original file IntrusiveRefCntPtr DiagOpts; @@ -349,13 +355,8 @@ void handleErrors(const std::vector &Errors, bool Fix) { ErrorReporter Reporter(Fix); - for (const ClangTidyError &Error : Errors) { - Reporter.reportDiagnostic( - Error.Message, static_cast(Error.DiagLevel), - &Error.Fix); - for (const ClangTidyMessage &Note : Error.Notes) - Reporter.reportDiagnostic(Note, DiagnosticsEngine::Note); - } + for (const ClangTidyError &Error : Errors) + Reporter.reportDiagnostic(Error); Reporter.Finish(); } Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -40,6 +40,14 @@ ArrayRef Ranges, const SourceManager *SM, DiagOrStoredDiag Info) override { + // Remove check name from the message. + // FIXME: Remove this once there's a better way to pass check names than + // appending the check name to the message in ClangTidyContext::diag and + // using getCustomDiagID. + std::string CheckNameInMessage = " [" + Error.CheckName + "]"; + if (Message.endswith(CheckNameInMessage)) + Message = Message.substr(0, Message.size() - CheckNameInMessage.size()); + ClangTidyMessage TidyMessage = Loc.isValid() ? ClangTidyMessage(Message, *SM, Loc) : ClangTidyMessage(Message); @@ -259,7 +267,6 @@ assert(!Errors.empty() && "A diagnostic note can only be appended to a message."); } else { - // FIXME: Pass all errors here regardless of filters and non-user code. finalizeLastError(); StringRef WarningOption = Context.DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag( @@ -268,9 +275,28 @@ ? ("clang-diagnostic-" + WarningOption).str() : Context.getCheckName(Info.getID()).str(); + if (CheckName.empty()) { + // This is a compiler diagnostic without a warning option. Assign check + // name based on its level. + switch (DiagLevel) { + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: + CheckName = "clang-diagnostic-error"; + break; + case DiagnosticsEngine::Warning: + CheckName = "clang-diagnostic-warning"; + break; + default: + CheckName = "clang-diagnostic-unknown"; + break; + } + } + ClangTidyError::Level Level = ClangTidyError::Warning; if (DiagLevel == DiagnosticsEngine::Error || DiagLevel == DiagnosticsEngine::Fatal) { + // Force reporting of Clang errors regardless of filters and non-user + // code. Level = ClangTidyError::Error; LastErrorRelatesToUserCode = true; LastErrorPassesLineFilter = true; Index: test/clang-tidy/diagnostic.cpp =================================================================== --- test/clang-tidy/diagnostic.cpp +++ test/clang-tidy/diagnostic.cpp @@ -7,8 +7,8 @@ // CHECK2-NOT: warning // CHECK3-NOT: warning -// CHECK1: error: error reading '{{.*}}.nonexistent.cpp' -// CHECK2: error: unknown argument: '-fan-unknown-option' +// CHECK1: error: error reading '{{.*}}.nonexistent.cpp' [clang-diagnostic-error] +// CHECK2: error: unknown argument: '-fan-unknown-option' [clang-diagnostic-error] // CHECK2: :[[@LINE+2]]:9: warning: implicit conversion from 'double' to 'int' changes value // CHECK3: :[[@LINE+1]]:9: warning: implicit conversion from 'double' to 'int' changes value