diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -20,6 +20,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Capacity.h" @@ -108,7 +109,12 @@ } void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info, - const LangOptions &LangOpts) { + const LangOptions &LangOpts, + llvm::DenseSet &IncludeLinesWithErrors) { + // We only report diagnostics with at least error severity from headers. + if (D.Severity < DiagnosticsEngine::Level::Error) + return; + const SourceLocation &DiagLoc = Info.getLocation(); const SourceManager &SM = Info.getSourceManager(); SourceLocation IncludeInMainFile; @@ -120,12 +126,17 @@ IncludeInMainFile = IncludeLocation; if (IncludeInMainFile.isInvalid()) return; + Position StartPos = sourceLocToPosition(SM, IncludeInMainFile); + // Only report the first diagnostic coming from a header. + if (!IncludeLinesWithErrors.insert(StartPos.line).second) + return; // Update diag to point at include inside main file. D.File = SM.getFileEntryForID(SM.getMainFileID())->getName().str(); - D.Range.start = sourceLocToPosition(SM, IncludeInMainFile); + D.Range.start = std::move(StartPos); D.Range.end = sourceLocToPosition( SM, Lexer::getLocForEndOfToken(IncludeInMainFile, 0, SM, LangOpts)); + D.InsideMainFile = true; // Add a note that will point to real diagnostic. const auto *FE = SM.getFileEntryForID(SM.getFileID(DiagLoc)); @@ -465,6 +476,7 @@ } bool InsideMainFile = isInsideMainFile(Info); + SourceManager &SM = Info.getSourceManager(); auto FillDiagBase = [&](DiagBase &D) { D.Range = diagnosticRange(Info, *LangOpts); @@ -472,8 +484,7 @@ Info.FormatDiagnostic(Message); D.Message = Message.str(); D.InsideMainFile = InsideMainFile; - D.File = Info.getSourceManager().getFilename(Info.getLocation()); - auto &SM = Info.getSourceManager(); + D.File = SM.getFilename(Info.getLocation()); D.AbsFile = getCanonicalPath( SM.getFileEntryForID(SM.getFileID(Info.getLocation())), SM); D.Severity = DiagLevel; @@ -496,10 +507,9 @@ if (FixIt.RemoveRange.getBegin().isMacroID() || FixIt.RemoveRange.getEnd().isMacroID()) return false; - if (!isInsideMainFile(FixIt.RemoveRange.getBegin(), - Info.getSourceManager())) + if (!isInsideMainFile(FixIt.RemoveRange.getBegin(), SM)) return false; - Edits.push_back(toTextEdit(FixIt, Info.getSourceManager(), *LangOpts)); + Edits.push_back(toTextEdit(FixIt, SM, *LangOpts)); } llvm::SmallString<64> Message; @@ -507,8 +517,8 @@ if (SyntheticMessage && Info.getNumFixItHints() == 1) { const auto &FixIt = Info.getFixItHint(0); bool Invalid = false; - llvm::StringRef Remove = Lexer::getSourceText( - FixIt.RemoveRange, Info.getSourceManager(), *LangOpts, &Invalid); + llvm::StringRef Remove = + Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid); llvm::StringRef Insert = FixIt.CodeToInsert; if (!Invalid) { llvm::raw_svector_ostream M(Message); @@ -553,7 +563,7 @@ LastDiag = Diag(); LastDiag->ID = Info.getID(); FillDiagBase(*LastDiag); - adjustDiagFromHeader(*LastDiag, Info, *LangOpts); + adjustDiagFromHeader(*LastDiag, Info, *LangOpts, IncludeLinesWithErrors); if (!Info.getFixItHints().empty()) AddFix(true /* try to invent a message instead of repeating the diag */); @@ -595,11 +605,7 @@ void StoreDiags::flushLastDiag() { if (!LastDiag) return; - // Only keeps diagnostics inside main file or the first one coming from a - // header. - if (mentionsMainFile(*LastDiag) || - (LastDiag->Severity >= DiagnosticsEngine::Level::Error && - IncludeLinesWithErrors.insert(LastDiag->Range.start.line).second)) { + if (mentionsMainFile(*LastDiag)) { Output.push_back(std::move(*LastDiag)); } else { vlog("Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message); diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -907,7 +907,6 @@ int x = 5/0;)cpp"); TestTU TU = TestTU::withCode(Main.code()); TU.AdditionalFiles = {{"a.h", Header.code()}}; - auto diags = TU.build().getDiagnostics(); EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre(AllOf( Diag(Main.range(), "in included file: C++ requires " @@ -915,6 +914,19 @@ WithNote(Diag(Header.range(), "error occurred here"))))); } +TEST(IgnoreDiags, FromNonWrittenSources) { + Annotations Main(R"cpp( + #include [["a.h"]] + void foo() {})cpp"); + Annotations Header(R"cpp( + int x = 5/0; + int b = [[FOO]];)cpp"); + TestTU TU = TestTU::withCode(Main.code()); + TU.AdditionalFiles = {{"a.h", Header.code()}}; + TU.ExtraArgs = {"-DFOO=NOOO"}; + EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre()); +} + } // namespace } // namespace clangd