diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -205,6 +205,7 @@ Inputs.Opts = std::move(Opts); Inputs.Index = Index; Inputs.ClangTidyProvider = ClangTidyProvider; + Inputs.Modules = Modules; bool NewFile = WorkScheduler->update(File, Inputs, WantDiags); // If we loaded Foo.h, we want to make sure Foo.cpp is indexed. if (NewFile && BackgroundIdx) diff --git a/clang-tools-extra/clangd/Compiler.h b/clang-tools-extra/clangd/Compiler.h --- a/clang-tools-extra/clangd/Compiler.h +++ b/clang-tools-extra/clangd/Compiler.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H #include "GlobalCompilationDatabase.h" +#include "Module.h" #include "TidyProvider.h" #include "index/Index.h" #include "support/ThreadsafeFS.h" @@ -54,6 +55,7 @@ const SymbolIndex *Index = nullptr; ParseOptions Opts = ParseOptions(); TidyProviderRef ClangTidyProvider = {}; + const ModuleSet *Modules = nullptr; }; /// Builds compiler invocation that could be used to build AST or preamble. diff --git a/clang-tools-extra/clangd/Diagnostics.h b/clang-tools-extra/clangd/Diagnostics.h --- a/clang-tools-extra/clangd/Diagnostics.h +++ b/clang-tools-extra/clangd/Diagnostics.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H +#include "Module.h" #include "Protocol.h" #include "support/Path.h" #include "clang/Basic/Diagnostic.h" @@ -145,6 +146,7 @@ /// diagnostics, such as promoting warnings to errors, or ignoring /// diagnostics. void setLevelAdjuster(LevelAdjuster Adjuster) { this->Adjuster = Adjuster; } + void setDiagAugmenters(const ModuleSet *Modules) { this->Modules = Modules; } private: void flushLastDiag(); @@ -157,6 +159,7 @@ llvm::Optional LastDiagLoc; // Valid only when LastDiag is set. bool LastDiagOriginallyError = false; // Valid only when LastDiag is set. SourceManager *OrigSrcMgr = nullptr; + const ModuleSet *Modules = nullptr; llvm::DenseSet> IncludedErrorLocations; bool LastPrimaryDiagnosticWasSuppressed = false; 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 @@ -746,6 +746,12 @@ LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(), ExtraFixes.end()); } + if (Modules) { + for (auto &M : *Modules) { + if (auto Action = M.augmentDiagFix(DiagLevel, Info)) + LastDiag->Actions.emplace_back(std::move(*Action)); + } + } } else { // Handle a note to an existing diagnostic. diff --git a/clang-tools-extra/clangd/Module.h b/clang-tools-extra/clangd/Module.h --- a/clang-tools-extra/clangd/Module.h +++ b/clang-tools-extra/clangd/Module.h @@ -9,9 +9,12 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H +#include "Protocol.h" #include "support/Function.h" #include "support/Threading.h" +#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/JSON.h" @@ -91,6 +94,15 @@ /// Called by the server when shutting down, and also by tests. virtual bool blockUntilIdle(Deadline) { return true; } + /// Called by auxilary threads as diagnostics encountered to generate fixes. + /// So this can be called concurrently from multiple threads. If a module + /// provides a code action with a custom, it should also register itself as + /// that commands handler. + virtual llvm::Optional + augmentDiagFix(DiagnosticsEngine::Level L, const clang::Diagnostic &Diag) { + return llvm::None; + } + protected: /// Accessors for modules to access shared server facilities they depend on. Facilities &facilities(); diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -262,6 +262,7 @@ CI->getLangOpts()->DelayedTemplateParsing = false; StoreDiags ASTDiags; + ASTDiags.setDiagAugmenters(Inputs.Modules); llvm::Optional Patch; if (Preamble) { diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -326,6 +326,7 @@ trace::Span Tracer("BuildPreamble"); SPAN_ATTACH(Tracer, "File", FileName); StoreDiags PreambleDiagnostics; + PreambleDiagnostics.setDiagAugmenters(Inputs.Modules); llvm::IntrusiveRefCntPtr PreambleDiagsEngine = CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(), &PreambleDiagnostics, false); diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -652,6 +652,7 @@ printArgv(Inputs.CompileCommand.CommandLine)); StoreDiags CompilerInvocationDiagConsumer; + CompilerInvocationDiagConsumer.setDiagAugmenters(Inputs.Modules); std::vector CC1Args; std::unique_ptr Invocation = buildCompilerInvocation( Inputs, CompilerInvocationDiagConsumer, &CC1Args); @@ -716,6 +717,7 @@ IdleASTs.take(this, &ASTAccessForRead); if (!AST) { StoreDiags CompilerInvocationDiagConsumer; + CompilerInvocationDiagConsumer.setDiagAugmenters(FileInputs.Modules); std::unique_ptr Invocation = buildCompilerInvocation(FileInputs, CompilerInvocationDiagConsumer); // Try rebuilding the AST.