diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -18,6 +18,7 @@ #include "Function.h" #include "GlobalCompilationDatabase.h" #include "Protocol.h" +#include "SemanticHighlighting.h" #include "TUScheduler.h" #include "XRefs.h" #include "index/Background.h" @@ -49,6 +50,11 @@ std::vector Diagnostics) = 0; /// Called whenever the file status is updated. virtual void onFileUpdated(PathRef File, const TUStatus &Status){}; + + /// Called by ClangdServer when some \p Highlightings for \p File are ready. + virtual void + onHighlightingsReady(PathRef File, + std::vector Highlightings) {} }; /// When set, used by ClangdServer to get clang-tidy options for each particular @@ -131,6 +137,9 @@ /// Clangd will execute compiler drivers matching one of these globs to /// fetch system include path. std::vector QueryDriverGlobs; + + /// Enable semantic highlighting features. + bool SemanticHighlighting = false; }; // Sensible default options for use in tests. // Features like indexing must be enabled if desired. @@ -304,7 +313,7 @@ // can be caused by missing includes (e.g. member access in incomplete type). bool SuggestMissingIncludes = false; bool EnableHiddenFeatures = false; - + // GUARDED_BY(CachedCompletionFuzzyFindRequestMutex) llvm::StringMap> CachedCompletionFuzzyFindRequestByFile; 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 @@ -48,8 +48,10 @@ // Update the FileIndex with new ASTs and plumb the diagnostics responses. struct UpdateIndexCallbacks : public ParsingCallbacks { - UpdateIndexCallbacks(FileIndex *FIndex, DiagnosticsConsumer &DiagConsumer) - : FIndex(FIndex), DiagConsumer(DiagConsumer) {} + UpdateIndexCallbacks(FileIndex *FIndex, DiagnosticsConsumer &DiagConsumer, + bool SemanticHighlighting) + : FIndex(FIndex), DiagConsumer(DiagConsumer), + SemanticHighlighting(SemanticHighlighting) {} void onPreambleAST(PathRef Path, ASTContext &Ctx, std::shared_ptr PP, @@ -61,6 +63,8 @@ void onMainAST(PathRef Path, ParsedAST &AST) override { if (FIndex) FIndex->updateMain(Path, AST); + if (SemanticHighlighting) + DiagConsumer.onHighlightingsReady(Path, getSemanticHighlightings(AST)); } void onDiagnostics(PathRef File, std::vector Diags) override { @@ -74,6 +78,7 @@ private: FileIndex *FIndex; DiagnosticsConsumer &DiagConsumer; + bool SemanticHighlighting; }; } // namespace @@ -82,6 +87,7 @@ Opts.UpdateDebounce = std::chrono::steady_clock::duration::zero(); // Faster! Opts.StorePreamblesInMemory = true; Opts.AsyncThreadsCount = 4; // Consistent! + Opts.SemanticHighlighting = true; return Opts; } @@ -102,10 +108,11 @@ // is parsed. // FIXME(ioeric): this can be slow and we may be able to index on less // critical paths. - WorkScheduler(CDB, Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory, - llvm::make_unique(DynamicIdx.get(), - DiagConsumer), - Opts.UpdateDebounce, Opts.RetentionPolicy) { + WorkScheduler( + CDB, Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory, + llvm::make_unique( + DynamicIdx.get(), DiagConsumer, Opts.SemanticHighlighting), + Opts.UpdateDebounce, Opts.RetentionPolicy) { // Adds an index to the stack, at higher priority than existing indexes. auto AddIndex = [&](SymbolIndex *Idx) { if (this->Index != nullptr) { diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -841,6 +841,30 @@ EXPECT_FALSE(PathResult.hasValue()); } +TEST(ClangdSemanticHighlightingTest, GeneratesHighlightsWhenFileChange) { + class HighlightingsCounterDiagConsumer : public DiagnosticsConsumer { + public: + std::atomic Count = {0}; + + void onDiagnosticsReady(PathRef, std::vector) override {} + void onHighlightingsReady( + PathRef File, std::vector Highlightings) override { + ++Count; + } + }; + + auto FooCpp = testPath("foo.cpp"); + MockFSProvider FS; + FS.Files[FooCpp] = ""; + + MockCompilationDatabase MCD; + HighlightingsCounterDiagConsumer DiagConsumer; + ClangdServer Server(MCD, FS, DiagConsumer, ClangdServer::optsForTest()); + Server.addDocument(FooCpp, "int a;"); + ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for server"; + ASSERT_EQ(DiagConsumer.Count, 1); +} + TEST_F(ClangdThreadingTest, NoConcurrentDiagnostics) { class NoConcurrentAccessDiagConsumer : public DiagnosticsConsumer { public: