[clang-tools-extra] [clangd] Add code action to suppress clang-tidy diagnostics (PR #188796)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 26 09:50:01 PDT 2026
https://github.com/Lancern created https://github.com/llvm/llvm-project/pull/188796
This patch adds code actions to suppress diagnostics generated by clang-tidy. There are two variants of the code action. The first one suppresses such diagnostics by appending `// NOLINT(check-name)` to the end of the source line. The second one suppresses such diagnostics by inserting a source line containing `// NOLINTNEXTLINE(check-name)` before the source line of the diagnostics.
A previous PR #114661 attempted to land similar feature, but it ends up being closed by its author.
Assisted-by: Github Copilot / Claude Opus 4.6
>From aabe3c3bb0de4f2a32efb19bb5ab79448da903c1 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Fri, 27 Mar 2026 00:44:36 +0800
Subject: [PATCH] [clangd] Add code action to suppress clang-tidy diagnostics
This patch adds code actions to suppress diagnostics generated by clang-tidy.
There are two variants of the code action. The first one suppresses such
diagnostics by appending `// NOLINT(check-name)` to the end of the source line.
The second one suppresses such diagnostics by inserting a source line containing
`// NOLINTNEXTLINE(check-name)` before the source line of the diagnostics.
A previous PR #114661 attempted to land similar feature, but it ends up being
closed by its author.
Assisted-by: Github Copilot / Claude Opus 4.6
---
clang-tools-extra/clangd/Diagnostics.cpp | 72 +++++++-
clang-tools-extra/clangd/Diagnostics.h | 3 +-
clang-tools-extra/clangd/ParsedAST.cpp | 4 +-
clang-tools-extra/clangd/Preamble.cpp | 4 +-
clang-tools-extra/clangd/TUScheduler.cpp | 9 +-
.../clangd/test/diagnostics-tidy.test | 78 ++++++++-
clang-tools-extra/clangd/tool/Check.cpp | 2 +-
.../clangd/unittests/ClangdLSPServerTests.cpp | 161 ++++++++++++++++--
.../clangd/unittests/CompilerTests.cpp | 2 +-
clang-tools-extra/clangd/unittests/TestTU.cpp | 2 +-
10 files changed, 309 insertions(+), 28 deletions(-)
diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp
index f68092b9a0886..bf638c52d00aa 100644
--- a/clang-tools-extra/clangd/Diagnostics.cpp
+++ b/clang-tools-extra/clangd/Diagnostics.cpp
@@ -571,7 +571,73 @@ int getSeverity(DiagnosticsEngine::Level L) {
llvm_unreachable("Unknown diagnostic level!");
}
-std::vector<Diag> StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) {
+// For clang-tidy diagnostics, generates a fix that suppresses the diagnostic
+// on the current line by appending a NOLINT comment.
+static std::optional<Fix> makeNolintFix(llvm::StringRef Code, const Diag &D) {
+ if (D.Source != Diag::ClangTidy || D.Name.empty() || !D.InsideMainFile)
+ return std::nullopt;
+
+ llvm::Expected<size_t> StartOffset = positionToOffset(Code, D.Range.start);
+ if (!StartOffset) {
+ llvm::consumeError(StartOffset.takeError());
+ return std::nullopt;
+ }
+ size_t LineEnd = Code.find('\n', *StartOffset);
+ if (LineEnd == llvm::StringRef::npos)
+ LineEnd = Code.size();
+ Position InsertPos = offsetToPosition(Code, LineEnd);
+
+ TextEdit Edit;
+ Edit.range = {InsertPos, InsertPos};
+ Edit.newText = llvm::formatv(" // NOLINT({0})", D.Name);
+
+ Fix F;
+ F.Message = llvm::formatv("suppress this warning with NOLINT");
+ F.Edits.push_back(std::move(Edit));
+
+ return F;
+}
+
+// For clang-tidy diagnostics, generates a fix that suppresses the diagnostic on
+// the current line by inserting a NOLINTNEXTLINE comment before the current
+// line.
+static std::optional<Fix> makeNolintNextLineFix(llvm::StringRef Code,
+ const Diag &D) {
+ if (D.Source != Diag::ClangTidy || D.Name.empty() || !D.InsideMainFile)
+ return std::nullopt;
+
+ llvm::Expected<size_t> StartOffset = positionToOffset(Code, D.Range.start);
+ if (!StartOffset) {
+ llvm::consumeError(StartOffset.takeError());
+ return std::nullopt;
+ }
+ size_t LineStart = Code.rfind('\n', *StartOffset);
+ if (LineStart == llvm::StringRef::npos)
+ LineStart = 0;
+ else
+ ++LineStart;
+
+ size_t LineTextStart = Code.find_first_not_of(" \t", LineStart);
+ if (LineTextStart == llvm::StringRef::npos || LineTextStart > *StartOffset)
+ LineTextStart = *StartOffset;
+
+ size_t Indentation = LineTextStart - LineStart;
+ Position InsertPos = offsetToPosition(Code, LineStart);
+
+ TextEdit Edit;
+ Edit.range = {InsertPos, InsertPos};
+ Edit.newText = std::string(Indentation, ' ');
+ Edit.newText.append(llvm::formatv("// NOLINTNEXTLINE({0})\n", D.Name));
+
+ Fix F;
+ F.Message = llvm::formatv("suppress this warning with NOLINTNEXTLINE");
+ F.Edits.push_back(std::move(Edit));
+
+ return F;
+}
+
+std::vector<Diag> StoreDiags::take(llvm::StringRef Code,
+ const clang::tidy::ClangTidyContext *Tidy) {
// Do not forget to emit a pending diagnostic if there is one.
flushLastDiag();
@@ -605,6 +671,10 @@ std::vector<Diag> StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) {
if (!TidyDiag.empty()) {
Diag.Name = std::move(TidyDiag);
Diag.Source = Diag::ClangTidy;
+ if (auto NolintFix = makeNolintFix(Code, Diag))
+ Diag.Fixes.push_back(std::move(*NolintFix));
+ if (auto NolintNextLineFix = makeNolintNextLineFix(Code, Diag))
+ Diag.Fixes.push_back(std::move(*NolintNextLineFix));
// clang-tidy bakes the name into diagnostic messages. Strip it out.
// It would be much nicer to make clang-tidy not do this.
auto CleanMessage = [&](std::string &Msg) {
diff --git a/clang-tools-extra/clangd/Diagnostics.h b/clang-tools-extra/clangd/Diagnostics.h
index d433abb530151..641468c2a8974 100644
--- a/clang-tools-extra/clangd/Diagnostics.h
+++ b/clang-tools-extra/clangd/Diagnostics.h
@@ -138,7 +138,8 @@ std::optional<std::string> getDiagnosticDocURI(Diag::DiagSource, unsigned ID,
class StoreDiags : public DiagnosticConsumer {
public:
// The ClangTidyContext populates Source and Name for clang-tidy diagnostics.
- std::vector<Diag> take(const clang::tidy::ClangTidyContext *Tidy = nullptr);
+ std::vector<Diag> take(llvm::StringRef Code,
+ const clang::tidy::ClangTidyContext *Tidy = nullptr);
void BeginSourceFile(const LangOptions &Opts,
const Preprocessor *PP) override;
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 4e873f1257a17..41b6977b71930 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -471,7 +471,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
if (!Clang) {
// The last diagnostic contains information about the reason of this
// failure.
- std::vector<Diag> Diags(ASTDiags.take());
+ std::vector<Diag> Diags(ASTDiags.take(Inputs.Contents));
elog("Failed to prepare a compiler instance: {0}",
!Diags.empty() ? static_cast<DiagBase &>(Diags.back()).Message
: "unknown error");
@@ -748,7 +748,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
llvm::append_range(Diags, Patch->patchedDiags());
// Finally, add diagnostics coming from the AST.
{
- std::vector<Diag> D = ASTDiags.take(&*CTContext);
+ std::vector<Diag> D = ASTDiags.take(Inputs.Contents, &*CTContext);
Diags.insert(Diags.end(), D.begin(), D.end());
}
ParsedAST Result(Filename, Inputs.Version, std::move(Preamble),
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index f5e512793e98e..984c9369fe27b 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -661,7 +661,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
log("Built preamble of size {0} for file {1} version {2} in {3} seconds",
BuiltPreamble->getSize(), FileName, Inputs.Version,
PreambleTimer.getTime());
- std::vector<Diag> Diags = PreambleDiagnostics.take();
+ std::vector<Diag> Diags = PreambleDiagnostics.take(Inputs.Contents);
auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
Result->Version = Inputs.Version;
Result->CompileCommand = Inputs.CompileCommand;
@@ -708,7 +708,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
elog("Could not build a preamble for file {0} version {1}: {2}", FileName,
Inputs.Version, BuiltPreamble.getError().message());
- for (const Diag &D : PreambleDiagnostics.take()) {
+ for (const Diag &D : PreambleDiagnostics.take(Inputs.Contents)) {
if (D.Severity < DiagnosticsEngine::Error)
continue;
// Not an ideal way to show errors, but better than nothing!
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index 0661ecb58008e..ee4f786503960 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -918,7 +918,7 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags,
if (!CC1Args.empty())
vlog("Driver produced command: cc1 {0}", printArgv(CC1Args));
std::vector<Diag> CompilerInvocationDiags =
- CompilerInvocationDiagConsumer.take();
+ CompilerInvocationDiagConsumer.take(Inputs.Contents);
if (!Invocation) {
elog("Could not build CompilerInvocation for file {0}", FileName);
// Remove the old AST if it's still in cache.
@@ -995,9 +995,10 @@ void ASTWorker::runWithAST(
// return a compatible preamble as ASTWorker::update blocks.
std::optional<ParsedAST> NewAST;
if (Invocation) {
- NewAST = ParsedAST::build(FileName, FileInputs, std::move(Invocation),
- CompilerInvocationDiagConsumer.take(),
- getPossiblyStalePreamble());
+ NewAST = ParsedAST::build(
+ FileName, FileInputs, std::move(Invocation),
+ CompilerInvocationDiagConsumer.take(FileInputs.Contents),
+ getPossiblyStalePreamble());
++ASTBuildCount;
}
AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
diff --git a/clang-tools-extra/clangd/test/diagnostics-tidy.test b/clang-tools-extra/clangd/test/diagnostics-tidy.test
index e592c9a0be7c3..864d028d8ad4d 100644
--- a/clang-tools-extra/clangd/test/diagnostics-tidy.test
+++ b/clang-tools-extra/clangd/test/diagnostics-tidy.test
@@ -11,7 +11,7 @@
# CHECK-NEXT: "codeDescription": {
# CHECK-NEXT: "href": "https://clang.llvm.org/extra/clang-tidy/checks/bugprone/sizeof-expression.html"
# CHECK-NEXT: },
-# CHECK-NEXT: "message": "Suspicious usage of 'sizeof(K)'; did you mean 'K'?",
+# CHECK-NEXT: "message": "Suspicious usage of 'sizeof(K)'; did you mean 'K'? (fixes available)",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 16,
@@ -30,6 +30,82 @@
# CHECK-NEXT: "version": 0
# CHECK-NEXT: }
---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":1,"character":6},"end":{"line":1,"character":16}},"context":{"diagnostics":[{"range":{"start":{"line":1,"character":6},"end":{"line":1,"character":16}},"severity":2,"message":"Suspicious usage of 'sizeof(K)'; did you mean 'K'? (fixes available)","code":"bugprone-sizeof-expression","source":"clang-tidy"}]}}}
+# CHECK: {
+# CHECK: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file:///{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": " // NOLINT(bugprone-sizeof-expression)",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 17,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 17,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyFix",
+# CHECK-NEXT: "title": "Apply fix: suppress this warning with NOLINT"
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file:///{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "// NOLINTNEXTLINE(bugprone-sizeof-expression)\n",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 0,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 0,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyFix",
+# CHECK-NEXT: "title": "Apply fix: suppress this warning with NOLINTNEXTLINE"
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "file": "file:///{{.*}}/foo.c",
+# CHECK-NEXT: "selection": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 16,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 6,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "tweakID": "ExtractVariable"
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyTweak",
+# CHECK-NEXT: "title": "Extract subexpression to variable"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+---
{"jsonrpc":"2.0","id":2,"method":"sync","params":null}
---
{"jsonrpc":"2.0","method":"textDocument/didClose","params":{"textDocument":{"uri":"test:///foo.c"}}}
diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp
index 03c4f58a49c9c..35695e9b4e995 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -227,7 +227,7 @@ class Checker {
log("Parsing command...");
Invocation =
buildCompilerInvocation(Inputs, CaptureInvocationDiags, &CC1Args);
- auto InvocationDiags = CaptureInvocationDiags.take();
+ auto InvocationDiags = CaptureInvocationDiags.take(Inputs.Contents);
ErrCount += showErrors(InvocationDiags);
log("internal (cc1) args are: {0}", printArgv(CC1Args));
if (!Invocation) {
diff --git a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
index 95bf5e54fc792..b743f3d312496 100644
--- a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
@@ -223,23 +223,37 @@ TEST_F(LSPTest, ClangTidyRename) {
ASSERT_TRUE(Diags && !Diags->empty());
auto RenameDiag = Diags->front();
- auto RenameCommand =
- (*Client
- .call("textDocument/codeAction",
- llvm::json::Object{
- {"textDocument", Client.documentID("foo.cpp")},
- {"context",
- llvm::json::Object{
- {"diagnostics", llvm::json::Array{RenameDiag}}}},
- {"range", Source.range()}})
- .takeValue()
- .getAsArray())[0];
-
- ASSERT_EQ((*RenameCommand.getAsObject())["title"],
+ auto CodeActions =
+ *Client
+ .call("textDocument/codeAction",
+ llvm::json::Object{
+ {"textDocument", Client.documentID("foo.cpp")},
+ {"context",
+ llvm::json::Object{
+ {"diagnostics", llvm::json::Array{RenameDiag}}}},
+ {"range", Source.range()}})
+ .takeValue()
+ .getAsArray();
+
+ // Find the rename code action by title.
+ const llvm::json::Value *RenameCommand = nullptr;
+ for (const auto &CA : CodeActions) {
+ if (const auto *Obj = CA.getAsObject()) {
+ if (auto Title = Obj->getString("title")) {
+ if (Title->starts_with("Apply fix: change")) {
+ RenameCommand = &CA;
+ break;
+ }
+ }
+ }
+ }
+ ASSERT_NE(RenameCommand, nullptr);
+
+ ASSERT_EQ(*RenameCommand->getAsObject()->getString("title"),
"Apply fix: change 'foo' to 'Foo'");
Client.expectServerCall("workspace/applyEdit");
- Client.call("workspace/executeCommand", RenameCommand);
+ Client.call("workspace/executeCommand", *RenameCommand);
Client.sync();
auto Params = Client.takeCallParams("workspace/applyEdit");
@@ -281,6 +295,125 @@ TEST_F(LSPTest, ClangTidyCrash_Issue109367) {
Client.sync();
}
+TEST_F(LSPTest, ClangTidyNolintCodeAction) {
+ // This test requires clang-tidy checks to be linked in.
+ if (!CLANGD_TIDY_CHECKS)
+ return;
+ Annotations Source(R"cpp(
+ int *$diag[[p]] = 0;$comment[[]]
+ )cpp");
+ constexpr auto ClangTidyProvider = [](tidy::ClangTidyOptions &ClangTidyOpts,
+ llvm::StringRef) {
+ ClangTidyOpts.Checks = {"-*,modernize-use-nullptr"};
+ };
+ Opts.ClangTidyProvider = ClangTidyProvider;
+ auto &Client = start();
+ Client.didOpen("foo.cpp", Source.code());
+
+ auto Diags = Client.diagnostics("foo.cpp");
+ ASSERT_TRUE(Diags && !Diags->empty());
+ auto UnusedDiag = Diags->front();
+
+ auto CodeActions =
+ Client
+ .call("textDocument/codeAction",
+ llvm::json::Object{
+ {"textDocument", Client.documentID("foo.cpp")},
+ {"context",
+ llvm::json::Object{
+ {"diagnostics", llvm::json::Array{UnusedDiag}}}},
+ {"range", Source.range("diag")}})
+ .takeValue();
+
+ // Find the NOLINT code action.
+ const llvm::json::Object *NolintAction = nullptr;
+ for (const auto &CA : *CodeActions.getAsArray()) {
+ if (const auto *Obj = CA.getAsObject()) {
+ if (auto Title = Obj->getString("title")) {
+ if (Title->contains("NOLINT") && !Title->contains("NOLINTNEXTLINE")) {
+ NolintAction = Obj;
+ break;
+ }
+ }
+ }
+ }
+ ASSERT_NE(NolintAction, nullptr) << "Expected a NOLINT code action";
+ EXPECT_EQ(NolintAction->getString("title"),
+ "Apply fix: suppress this warning with NOLINT");
+
+ auto Uri = [&](llvm::StringRef Path) {
+ return Client.uri(Path).getAsString().value().str();
+ };
+ llvm::json::Array ExpectedArguments = llvm::json::Array{llvm::json::Object{
+ {"changes",
+ llvm::json::Object{{Uri("foo.cpp"),
+ llvm::json::Array{llvm::json::Object{
+ {"range", Source.range("comment")},
+ {"newText", " // NOLINT(modernize-use-nullptr)"},
+ }}}}}}};
+ EXPECT_EQ(*NolintAction->getArray("arguments"), ExpectedArguments);
+}
+
+TEST_F(LSPTest, ClangTidyNolintNextLineCodeAction) {
+ // This test requires clang-tidy checks to be linked in.
+ if (!CLANGD_TIDY_CHECKS)
+ return;
+ Annotations Source(R"cpp(
+$comment[[]] int *$diag[[p]] = 0;
+ )cpp");
+ constexpr auto ClangTidyProvider = [](tidy::ClangTidyOptions &ClangTidyOpts,
+ llvm::StringRef) {
+ ClangTidyOpts.Checks = {"-*,modernize-use-nullptr"};
+ };
+ Opts.ClangTidyProvider = ClangTidyProvider;
+ auto &Client = start();
+ Client.didOpen("foo.cpp", Source.code());
+
+ auto Diags = Client.diagnostics("foo.cpp");
+ ASSERT_TRUE(Diags && !Diags->empty());
+ auto UnusedDiag = Diags->front();
+
+ auto CodeActions =
+ Client
+ .call("textDocument/codeAction",
+ llvm::json::Object{
+ {"textDocument", Client.documentID("foo.cpp")},
+ {"context",
+ llvm::json::Object{
+ {"diagnostics", llvm::json::Array{UnusedDiag}}}},
+ {"range", Source.range("diag")}})
+ .takeValue();
+
+ // Find the NOLINT code action.
+ const llvm::json::Object *NolintAction = nullptr;
+ for (const auto &CA : *CodeActions.getAsArray()) {
+ if (const auto *Obj = CA.getAsObject()) {
+ if (auto Title = Obj->getString("title")) {
+ if (Title->contains("NOLINTNEXTLINE")) {
+ NolintAction = Obj;
+ break;
+ }
+ }
+ }
+ }
+ ASSERT_NE(NolintAction, nullptr) << "Expected a NOLINTNEXTLINE code action";
+ EXPECT_EQ(NolintAction->getString("title"),
+ "Apply fix: suppress this warning with NOLINTNEXTLINE");
+
+ auto Uri = [&](llvm::StringRef Path) {
+ return Client.uri(Path).getAsString().value().str();
+ };
+ llvm::json::Array ExpectedArguments = llvm::json::Array{llvm::json::Object{
+ {"changes",
+ llvm::json::Object{
+ {Uri("foo.cpp"),
+ llvm::json::Array{llvm::json::Object{
+ {"range", Source.range("comment")},
+ {"newText", " // NOLINTNEXTLINE(modernize-use-nullptr)\n"},
+ }}}}}}};
+ EXPECT_EQ(*NolintAction->getArray("arguments"), ExpectedArguments);
+}
+
TEST_F(LSPTest, IncomingCalls) {
Annotations Code(R"cpp(
void calle^e(int);
diff --git a/clang-tools-extra/clangd/unittests/CompilerTests.cpp b/clang-tools-extra/clangd/unittests/CompilerTests.cpp
index 9c8ad8d70b47b..0534a9f711c80 100644
--- a/clang-tools-extra/clangd/unittests/CompilerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CompilerTests.cpp
@@ -126,7 +126,7 @@ TEST(BuildCompilerInvocation, SuppressDiags) {
Cfg.Diagnostics.Suppress = {"drv_unknown_argument"};
WithContextValue SuppressFilterWithCfg(Config::Key, std::move(Cfg));
EXPECT_NE(buildCompilerInvocation(Inputs, Diags), nullptr);
- EXPECT_THAT(Diags.take(), IsEmpty());
+ EXPECT_THAT(Diags.take(Inputs.Contents), IsEmpty());
}
} // namespace
} // namespace clangd
diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp
index e2c2e3f000b66..28a7175c160d7 100644
--- a/clang-tools-extra/clangd/unittests/TestTU.cpp
+++ b/clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -128,7 +128,7 @@ ParsedAST TestTU::build() const {
/*StoreInMemory=*/true,
/*PreambleCallback=*/nullptr);
auto AST = ParsedAST::build(testPath(Filename), Inputs, std::move(CI),
- Diags.take(), Preamble);
+ Diags.take(Inputs.Contents), Preamble);
if (!AST) {
llvm::errs() << "Failed to build code:\n" << Code;
std::abort();
More information about the cfe-commits
mailing list