kadircet created this revision. kadircet added a reviewer: sammccall. Herald added subscribers: usaxena95, arphaman, javed.absar. kadircet requested review of this revision. Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov. Herald added a project: clang.
These can be invoked at different stages while building an AST to let FeatureModules implement features on top of it. The patch also introduces a sawDiagnostic hook, which can mutate the final clangd::Diag while reading a clang::Diagnostic. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D98499 Files: clang-tools-extra/clangd/Compiler.h clang-tools-extra/clangd/Diagnostics.cpp clang-tools-extra/clangd/Diagnostics.h clang-tools-extra/clangd/FeatureModule.h clang-tools-extra/clangd/ParsedAST.cpp clang-tools-extra/clangd/Preamble.cpp clang-tools-extra/clangd/TUScheduler.cpp clang-tools-extra/clangd/tool/Check.cpp clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp clang-tools-extra/clangd/unittests/TestTU.cpp clang-tools-extra/clangd/unittests/TestTU.h
Index: clang-tools-extra/clangd/unittests/TestTU.h =================================================================== --- clang-tools-extra/clangd/unittests/TestTU.h +++ clang-tools-extra/clangd/unittests/TestTU.h @@ -25,6 +25,7 @@ #include "support/Path.h" #include "llvm/ADT/StringMap.h" #include "gtest/gtest.h" +#include <memory> #include <string> #include <utility> #include <vector> @@ -76,6 +77,8 @@ // to eliminate this option some day. bool OverlayRealFileSystemForModules = false; + std::vector<std::unique_ptr<FeatureModule::ParseASTHooks>> Hooks; + // By default, build() will report Error diagnostics as GTest errors. // Suppress this behavior by adding an 'error-ok' comment to the code. ParsedAST build() const; Index: clang-tools-extra/clangd/unittests/TestTU.cpp =================================================================== --- clang-tools-extra/clangd/unittests/TestTU.cpp +++ clang-tools-extra/clangd/unittests/TestTU.cpp @@ -36,6 +36,7 @@ FS.Files[ImportThunk] = ThunkContents; ParseInputs Inputs; + Inputs.ASTHooks = Hooks; auto &Argv = Inputs.CompileCommand.CommandLine; Argv = {"clang"}; // FIXME: this shouldn't need to be conditional, but it breaks a @@ -97,6 +98,7 @@ MockFS FS; auto Inputs = inputs(FS); StoreDiags Diags; + Diags.setASTHooks(Inputs.ASTHooks); auto CI = buildCompilerInvocation(Inputs, Diags); assert(CI && "Failed to build compilation invocation."); if (OverlayRealFileSystemForModules) Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -1346,6 +1346,24 @@ }); } +TEST(ParsedASTTest, ModuleSawDiag) { + static constexpr const llvm::StringLiteral KDiagMsg = "StampedDiag"; + struct Hooks : public FeatureModule::ParseASTHooks { + void sawDiagnostic(const clang::Diagnostic &Info, + clangd::Diag &Diag) override { + Diag.Message = KDiagMsg.str(); + } + }; + + Annotations Code("[[test]]; /* error-ok */"); + TestTU TU; + TU.Code = Code.code().str(); + TU.Hooks.emplace_back(new Hooks); + + auto AST = TU.build(); + EXPECT_THAT(AST.getDiagnostics(), + testing::Contains(Diag(Code.range(), KDiagMsg.str()))); +} } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/tool/Check.cpp =================================================================== --- clang-tools-extra/clangd/tool/Check.cpp +++ clang-tools-extra/clangd/tool/Check.cpp @@ -46,6 +46,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Path.h" +#include <memory> namespace clang { namespace clangd { @@ -119,13 +120,17 @@ } // Prepare inputs and build CompilerInvocation (parsed compile command). - bool buildInvocation(const ThreadsafeFS &TFS, - llvm::Optional<std::string> Contents) { - StoreDiags CaptureInvocationDiags; + bool buildInvocation( + const ThreadsafeFS &TFS, llvm::Optional<std::string> Contents, + llvm::ArrayRef<std::unique_ptr<FeatureModule::ParseASTHooks>> Hooks) { std::vector<std::string> CC1Args; Inputs.CompileCommand = Cmd; Inputs.TFS = &TFS; Inputs.ClangTidyProvider = Opts.ClangTidyProvider; + Inputs.ASTHooks = Hooks; + + StoreDiags CaptureInvocationDiags; + CaptureInvocationDiags.setASTHooks(Hooks); if (Contents.hasValue()) { Inputs.Contents = *Contents; log("Imaginary source file contents:\n{0}", Inputs.Contents); @@ -252,7 +257,15 @@ Opts.ConfigProvider, nullptr); WithContext Ctx(ContextProvider("")); Checker C(File, Opts); - if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) || + std::vector<std::unique_ptr<FeatureModule::ParseASTHooks>> Hooks; + if (Opts.FeatureModules) { + for (auto &M : *Opts.FeatureModules) { + if (auto H = M.astHooks()) + Hooks.push_back(std::move(H)); + } + } + + if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents, Hooks) || !C.buildAST()) return false; C.testLocationFeatures(); Index: clang-tools-extra/clangd/TUScheduler.cpp =================================================================== --- clang-tools-extra/clangd/TUScheduler.cpp +++ clang-tools-extra/clangd/TUScheduler.cpp @@ -804,6 +804,7 @@ printArgv(Inputs.CompileCommand.CommandLine)); StoreDiags CompilerInvocationDiagConsumer; + CompilerInvocationDiagConsumer.setASTHooks(Inputs.ASTHooks); std::vector<std::string> CC1Args; std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation( Inputs, CompilerInvocationDiagConsumer, &CC1Args); @@ -868,6 +869,7 @@ IdleASTs.take(this, &ASTAccessForRead); if (!AST) { StoreDiags CompilerInvocationDiagConsumer; + CompilerInvocationDiagConsumer.setASTHooks(FileInputs.ASTHooks); std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(FileInputs, CompilerInvocationDiagConsumer); // Try rebuilding the AST. Index: clang-tools-extra/clangd/Preamble.cpp =================================================================== --- clang-tools-extra/clangd/Preamble.cpp +++ clang-tools-extra/clangd/Preamble.cpp @@ -326,6 +326,7 @@ trace::Span Tracer("BuildPreamble"); SPAN_ATTACH(Tracer, "File", FileName); StoreDiags PreambleDiagnostics; + PreambleDiagnostics.setASTHooks(Inputs.ASTHooks); llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine = CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(), &PreambleDiagnostics, false); Index: clang-tools-extra/clangd/ParsedAST.cpp =================================================================== --- clang-tools-extra/clangd/ParsedAST.cpp +++ clang-tools-extra/clangd/ParsedAST.cpp @@ -262,6 +262,7 @@ CI->getLangOpts()->DelayedTemplateParsing = false; StoreDiags ASTDiags; + ASTDiags.setASTHooks(Inputs.ASTHooks); llvm::Optional<PreamblePatch> Patch; if (Preamble) { @@ -316,7 +317,7 @@ Check->registerMatchers(&CTFinder); } - const Config& Cfg = Config::current(); + const Config &Cfg = Config::current(); ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { if (Cfg.Diagnostics.SuppressAll || Index: clang-tools-extra/clangd/FeatureModule.h =================================================================== --- clang-tools-extra/clangd/FeatureModule.h +++ clang-tools-extra/clangd/FeatureModule.h @@ -11,6 +11,7 @@ #include "support/Function.h" #include "support/Threading.h" +#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" @@ -25,6 +26,7 @@ class SymbolIndex; class ThreadsafeFS; class TUScheduler; +struct Diag; /// A FeatureModule contributes a vertical feature to clangd. /// @@ -96,6 +98,20 @@ virtual void contributeTweaks(std::vector<std::unique_ptr<class Tweak>> &Out) {} + /// Various hooks that can be invoked by ASTWorker thread while building an + /// AST. These hooks are always called from a single thread, so + /// implementations don't need to be thread-safe. + struct ParseASTHooks { + virtual ~ParseASTHooks() = default; + + /// Called everytime a diagnostic is encountered. Modules can use this + /// modify the final diagnostic, or store some information to surface code + /// actions later on. + virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &) {} + }; + /// Can be called asynchronously before building an AST. + virtual std::unique_ptr<ParseASTHooks> astHooks() { return nullptr; } + protected: /// Accessors for modules to access shared server facilities they depend on. Facilities &facilities(); Index: clang-tools-extra/clangd/Diagnostics.h =================================================================== --- clang-tools-extra/clangd/Diagnostics.h +++ 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 "FeatureModule.h" #include "Protocol.h" #include "support/Path.h" #include "clang/Basic/Diagnostic.h" @@ -22,6 +23,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/SourceMgr.h" #include <cassert> +#include <memory> #include <string> namespace clang { @@ -142,6 +144,10 @@ /// diagnostics, such as promoting warnings to errors, or ignoring /// diagnostics. void setLevelAdjuster(LevelAdjuster Adjuster) { this->Adjuster = Adjuster; } + void setASTHooks( + llvm::ArrayRef<std::unique_ptr<FeatureModule::ParseASTHooks>> Hooks) { + this->Hooks = Hooks; + } private: void flushLastDiag(); @@ -157,6 +163,7 @@ llvm::DenseSet<std::pair<unsigned, unsigned>> IncludedErrorLocations; bool LastPrimaryDiagnosticWasSuppressed = false; + llvm::ArrayRef<std::unique_ptr<FeatureModule::ParseASTHooks>> Hooks; }; /// Determine whether a (non-clang-tidy) diagnostic is suppressed by config. Index: clang-tools-extra/clangd/Diagnostics.cpp =================================================================== --- clang-tools-extra/clangd/Diagnostics.cpp +++ clang-tools-extra/clangd/Diagnostics.cpp @@ -744,6 +744,8 @@ LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(), ExtraFixes.end()); } + for (auto &Hook : Hooks) + Hook->sawDiagnostic(Info, *LastDiag); } else { // Handle a note to an existing diagnostic. Index: clang-tools-extra/clangd/Compiler.h =================================================================== --- clang-tools-extra/clangd/Compiler.h +++ clang-tools-extra/clangd/Compiler.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H +#include "FeatureModule.h" #include "GlobalCompilationDatabase.h" #include "TidyProvider.h" #include "index/Index.h" @@ -22,6 +23,8 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/PrecompiledPreamble.h" #include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/ArrayRef.h" +#include <memory> namespace clang { namespace clangd { @@ -54,6 +57,7 @@ const SymbolIndex *Index = nullptr; ParseOptions Opts = ParseOptions(); TidyProviderRef ClangTidyProvider = {}; + llvm::ArrayRef<std::unique_ptr<FeatureModule::ParseASTHooks>> ASTHooks; }; /// Builds compiler invocation that could be used to build AST or preamble.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits