Skip to content

Commit fcfd891

Browse files
committed
Merging r367303:
------------------------------------------------------------------------ r367303 | kadircet | 2019-07-30 12:26:51 +0200 (Tue, 30 Jul 2019) | 15 lines [clangd] Ignore diags from builtin files Summary: This fixes a case where we show diagnostics on arbitrary lines, in an internal codebase. Open for ideas on unittesting this. Reviewers: ilya-biryukov Subscribers: MaskRay, jkorous, arphaman, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D64863 ------------------------------------------------------------------------ llvm-svn: 368682
1 parent ff20769 commit fcfd891

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

clang-tools-extra/clangd/Diagnostics.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/Lex/Lexer.h"
2121
#include "clang/Lex/Token.h"
2222
#include "llvm/ADT/ArrayRef.h"
23+
#include "llvm/ADT/DenseSet.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/ADT/Twine.h"
2526
#include "llvm/Support/Capacity.h"
@@ -107,8 +108,13 @@ Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
107108
return halfOpenToRange(M, R);
108109
}
109110

110-
void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info,
111+
// Returns whether the \p D is modified.
112+
bool adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info,
111113
const LangOptions &LangOpts) {
114+
// We only report diagnostics with at least error severity from headers.
115+
if (D.Severity < DiagnosticsEngine::Level::Error)
116+
return false;
117+
112118
const SourceLocation &DiagLoc = Info.getLocation();
113119
const SourceManager &SM = Info.getSourceManager();
114120
SourceLocation IncludeInMainFile;
@@ -119,13 +125,14 @@ void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info,
119125
IncludeLocation = GetIncludeLoc(IncludeLocation))
120126
IncludeInMainFile = IncludeLocation;
121127
if (IncludeInMainFile.isInvalid())
122-
return;
128+
return false;
123129

124130
// Update diag to point at include inside main file.
125131
D.File = SM.getFileEntryForID(SM.getMainFileID())->getName().str();
126132
D.Range.start = sourceLocToPosition(SM, IncludeInMainFile);
127133
D.Range.end = sourceLocToPosition(
128134
SM, Lexer::getLocForEndOfToken(IncludeInMainFile, 0, SM, LangOpts));
135+
D.InsideMainFile = true;
129136

130137
// Add a note that will point to real diagnostic.
131138
const auto *FE = SM.getFileEntryForID(SM.getFileID(DiagLoc));
@@ -138,6 +145,7 @@ void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info,
138145

139146
// Update message to mention original file.
140147
D.Message = llvm::Twine("in included file: ", D.Message).str();
148+
return true;
141149
}
142150

143151
bool isInsideMainFile(const clang::Diagnostic &D) {
@@ -465,15 +473,15 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
465473
}
466474

467475
bool InsideMainFile = isInsideMainFile(Info);
476+
SourceManager &SM = Info.getSourceManager();
468477

469478
auto FillDiagBase = [&](DiagBase &D) {
470479
D.Range = diagnosticRange(Info, *LangOpts);
471480
llvm::SmallString<64> Message;
472481
Info.FormatDiagnostic(Message);
473482
D.Message = Message.str();
474483
D.InsideMainFile = InsideMainFile;
475-
D.File = Info.getSourceManager().getFilename(Info.getLocation());
476-
auto &SM = Info.getSourceManager();
484+
D.File = SM.getFilename(Info.getLocation());
477485
D.AbsFile = getCanonicalPath(
478486
SM.getFileEntryForID(SM.getFileID(Info.getLocation())), SM);
479487
D.Severity = DiagLevel;
@@ -496,19 +504,18 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
496504
if (FixIt.RemoveRange.getBegin().isMacroID() ||
497505
FixIt.RemoveRange.getEnd().isMacroID())
498506
return false;
499-
if (!isInsideMainFile(FixIt.RemoveRange.getBegin(),
500-
Info.getSourceManager()))
507+
if (!isInsideMainFile(FixIt.RemoveRange.getBegin(), SM))
501508
return false;
502-
Edits.push_back(toTextEdit(FixIt, Info.getSourceManager(), *LangOpts));
509+
Edits.push_back(toTextEdit(FixIt, SM, *LangOpts));
503510
}
504511

505512
llvm::SmallString<64> Message;
506513
// If requested and possible, create a message like "change 'foo' to 'bar'".
507514
if (SyntheticMessage && Info.getNumFixItHints() == 1) {
508515
const auto &FixIt = Info.getFixItHint(0);
509516
bool Invalid = false;
510-
llvm::StringRef Remove = Lexer::getSourceText(
511-
FixIt.RemoveRange, Info.getSourceManager(), *LangOpts, &Invalid);
517+
llvm::StringRef Remove =
518+
Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
512519
llvm::StringRef Insert = FixIt.CodeToInsert;
513520
if (!Invalid) {
514521
llvm::raw_svector_ostream M(Message);
@@ -553,7 +560,9 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
553560
LastDiag = Diag();
554561
LastDiag->ID = Info.getID();
555562
FillDiagBase(*LastDiag);
556-
adjustDiagFromHeader(*LastDiag, Info, *LangOpts);
563+
LastDiagWasAdjusted = false;
564+
if (!InsideMainFile)
565+
LastDiagWasAdjusted = adjustDiagFromHeader(*LastDiag, Info, *LangOpts);
557566

558567
if (!Info.getFixItHints().empty())
559568
AddFix(true /* try to invent a message instead of repeating the diag */);
@@ -595,10 +604,9 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
595604
void StoreDiags::flushLastDiag() {
596605
if (!LastDiag)
597606
return;
598-
// Only keeps diagnostics inside main file or the first one coming from a
599-
// header.
600-
if (mentionsMainFile(*LastDiag) ||
601-
(LastDiag->Severity >= DiagnosticsEngine::Level::Error &&
607+
if (mentionsMainFile(*LastDiag) &&
608+
(!LastDiagWasAdjusted ||
609+
// Only report the first diagnostic coming from each particular header.
602610
IncludeLinesWithErrors.insert(LastDiag->Range.start.line).second)) {
603611
Output.push_back(std::move(*LastDiag));
604612
} else {

clang-tools-extra/clangd/Diagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ class StoreDiags : public DiagnosticConsumer {
145145
std::vector<Diag> Output;
146146
llvm::Optional<LangOptions> LangOpts;
147147
llvm::Optional<Diag> LastDiag;
148+
/// Set iff adjustDiagFromHeader resulted in changes to LastDiag.
149+
bool LastDiagWasAdjusted = false;
148150
llvm::DenseSet<int> IncludeLinesWithErrors;
149151
bool LastPrimaryDiagnosticWasSuppressed = false;
150152
};

clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,14 +928,26 @@ TEST(DiagsInHeaders, OnlyErrorOrFatal) {
928928
int x = 5/0;)cpp");
929929
TestTU TU = TestTU::withCode(Main.code());
930930
TU.AdditionalFiles = {{"a.h", Header.code()}};
931-
auto diags = TU.build().getDiagnostics();
932931
EXPECT_THAT(TU.build().getDiagnostics(),
933932
UnorderedElementsAre(AllOf(
934933
Diag(Main.range(), "in included file: C++ requires "
935934
"a type specifier for all declarations"),
936935
WithNote(Diag(Header.range(), "error occurred here")))));
937936
}
938937

938+
TEST(IgnoreDiags, FromNonWrittenSources) {
939+
Annotations Main(R"cpp(
940+
#include [["a.h"]]
941+
void foo() {})cpp");
942+
Annotations Header(R"cpp(
943+
int x = 5/0;
944+
int b = [[FOO]];)cpp");
945+
TestTU TU = TestTU::withCode(Main.code());
946+
TU.AdditionalFiles = {{"a.h", Header.code()}};
947+
TU.ExtraArgs = {"-DFOO=NOOO"};
948+
EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre());
949+
}
950+
939951
} // namespace
940952

941953
} // namespace clangd

0 commit comments

Comments
 (0)