jvikstrom created this revision.
jvikstrom added reviewers: hokein, ilya-biryukov.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, MaskRay,
javed.absar.
Herald added a project: clang.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D63821
Files:
clang-tools-extra/clangd/ClangdLSPServer.cpp
clang-tools-extra/clangd/ClangdLSPServer.h
clang-tools-extra/clangd/ClangdServer.cpp
clang-tools-extra/clangd/ClangdServer.h
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/TUScheduler.cpp
clang-tools-extra/clangd/TUScheduler.h
clang-tools-extra/clangd/unittests/ClangdTests.cpp
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
clang-tools-extra/clangd/unittests/XRefsTests.cpp
Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -10,6 +10,7 @@
#include "Compiler.h"
#include "Matchers.h"
#include "Protocol.h"
+#include "SemanticHighlighting.h"
#include "SyncAPI.h"
#include "TestFS.h"
#include "TestTU.h"
@@ -33,9 +34,13 @@
using ::testing::Matcher;
using ::testing::UnorderedElementsAreArray;
-class IgnoreDiagnostics : public DiagnosticsConsumer {
+class IgnoreDiagnostics : public DiagnosticsConsumer, public HighlightingsConsumer {
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {}
+
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
};
MATCHER_P2(FileRange, File, Range, "") {
@@ -539,7 +544,7 @@
IgnoreDiagnostics DiagConsumer;
MockFSProvider FS;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
// Fill the filesystem.
auto FooCpp = testPath("src/foo.cpp");
@@ -1791,7 +1796,7 @@
MockFSProvider FS;
IgnoreDiagnostics DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
const char *SourceContents = R"cpp(
@@ -1866,7 +1871,7 @@
MockFSProvider FS;
IgnoreDiagnostics DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
// The trigger locations must be the same.
Index: clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Annotations.h"
+#include "ClangdServer.h"
#include "Context.h"
#include "Matchers.h"
#include "TUScheduler.h"
@@ -44,9 +45,10 @@
void updateWithCallback(TUScheduler &S, PathRef File,
llvm::StringRef Contents, WantDiagnostics WD,
+ bool WantHighlight,
llvm::unique_function<void()> CB) {
WithContextValue Ctx(llvm::make_scope_exit(std::move(CB)));
- S.update(File, getInputs(File, Contents), WD);
+ S.update(File, getInputs(File, Contents), WD, WantHighlight);
}
static Key<llvm::unique_function<void(PathRef File, std::vector<Diag>)>>
@@ -71,7 +73,7 @@
/// any. The TUScheduler should be created with captureDiags as a
/// DiagsCallback for this to work.
void updateWithDiags(TUScheduler &S, PathRef File, ParseInputs Inputs,
- WantDiagnostics WD,
+ WantDiagnostics WD, bool WantHighlight,
llvm::unique_function<void(std::vector<Diag>)> CB) {
Path OrigFile = File.str();
WithContextValue Ctx(
@@ -82,13 +84,13 @@
CB(std::move(Diags));
},
std::move(CB)));
- S.update(File, std::move(Inputs), WD);
+ S.update(File, std::move(Inputs), WD, WantHighlight);
}
void updateWithDiags(TUScheduler &S, PathRef File, llvm::StringRef Contents,
- WantDiagnostics WD,
+ WantDiagnostics WD, bool WantHighlight,
llvm::unique_function<void(std::vector<Diag>)> CB) {
- return updateWithDiags(S, File, getInputs(File, Contents), WD,
+ return updateWithDiags(S, File, getInputs(File, Contents), WD, WantHighlight,
std::move(CB));
}
@@ -113,7 +115,7 @@
Files[Missing] = "";
EXPECT_EQ(S.getContents(Added), "");
- S.update(Added, getInputs(Added, "x"), WantDiagnostics::No);
+ S.update(Added, getInputs(Added, "x"), WantDiagnostics::No, false);
EXPECT_EQ(S.getContents(Added), "x");
// Assert each operation for missing file is an error (even if it's available
@@ -161,20 +163,20 @@
/*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(),
ASTRetentionPolicy());
auto Path = testPath("foo.cpp");
- updateWithDiags(S, Path, "", WantDiagnostics::Yes,
+ updateWithDiags(S, Path, "", WantDiagnostics::Yes, false,
[&](std::vector<Diag>) { Ready.wait(); });
- updateWithDiags(S, Path, "request diags", WantDiagnostics::Yes,
+ updateWithDiags(S, Path, "request diags", WantDiagnostics::Yes, false,
[&](std::vector<Diag>) { ++CallbackCount; });
- updateWithDiags(S, Path, "auto (clobbered)", WantDiagnostics::Auto,
+ updateWithDiags(S, Path, "auto (clobbered)", WantDiagnostics::Auto, false,
[&](std::vector<Diag>) {
ADD_FAILURE()
<< "auto should have been cancelled by auto";
});
- updateWithDiags(S, Path, "request no diags", WantDiagnostics::No,
+ updateWithDiags(S, Path, "request no diags", WantDiagnostics::No, false,
[&](std::vector<Diag>) {
ADD_FAILURE() << "no diags should not be called back";
});
- updateWithDiags(S, Path, "auto (produces)", WantDiagnostics::Auto,
+ updateWithDiags(S, Path, "auto (produces)", WantDiagnostics::Auto, false,
[&](std::vector<Diag>) { ++CallbackCount; });
Ready.notify();
@@ -192,16 +194,16 @@
ASTRetentionPolicy());
// FIXME: we could probably use timeouts lower than 1 second here.
auto Path = testPath("foo.cpp");
- updateWithDiags(S, Path, "auto (debounced)", WantDiagnostics::Auto,
+ updateWithDiags(S, Path, "auto (debounced)", WantDiagnostics::Auto, false,
[&](std::vector<Diag>) {
ADD_FAILURE()
<< "auto should have been debounced and canceled";
});
std::this_thread::sleep_for(std::chrono::milliseconds(200));
- updateWithDiags(S, Path, "auto (timed out)", WantDiagnostics::Auto,
+ updateWithDiags(S, Path, "auto (timed out)", WantDiagnostics::Auto, false,
[&](std::vector<Diag>) { ++CallbackCount; });
std::this_thread::sleep_for(std::chrono::seconds(2));
- updateWithDiags(S, Path, "auto (shut down)", WantDiagnostics::Auto,
+ updateWithDiags(S, Path, "auto (shut down)", WantDiagnostics::Auto, false,
[&](std::vector<Diag>) { ++CallbackCount; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
@@ -230,7 +232,7 @@
// Schedule two updates (A, B) and two preamble reads (stale, consistent).
// The stale read should see A, and the consistent read should see B.
// (We recognize the preambles by their included files).
- updateWithCallback(S, Path, "#include <A>", WantDiagnostics::Yes, [&]() {
+ updateWithCallback(S, Path, "#include <A>", WantDiagnostics::Yes, false, [&]() {
// This callback runs in between the two preamble updates.
// This blocks update B, preventing it from winning the race
@@ -243,7 +245,8 @@
// If the second read was stale, it would usually see A.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
- S.update(Path, getInputs(Path, "#include <B>"), WantDiagnostics::Yes);
+ S.update(Path, getInputs(Path, "#include <B>"),
+ WantDiagnostics::Yes, false);
S.runWithPreamble("StaleRead", Path, TUScheduler::Stale,
[&](Expected<InputsAndPreamble> Pre) {
@@ -289,7 +292,7 @@
auto T = cancelableTask();
WithContext C(std::move(T.first));
updateWithDiags(
- S, Path, "//" + ID, WantDiagnostics::Yes,
+ S, Path, "//" + ID, WantDiagnostics::Yes, false,
[&, ID](std::vector<Diag> Diags) { DiagsSeen.push_back(ID); });
return std::move(T.second);
};
@@ -313,7 +316,7 @@
return std::move(T.second);
};
- updateWithCallback(S, Path, "", WantDiagnostics::Yes,
+ updateWithCallback(S, Path, "", WantDiagnostics::Yes, false,
[&]() { Proceed.wait(); });
// The second parens indicate cancellation, where present.
Update("U1")();
@@ -381,7 +384,7 @@
{
WithContextValue WithNonce(NonceKey, ++Nonce);
updateWithDiags(
- S, File, Inputs, WantDiagnostics::Auto,
+ S, File, Inputs, WantDiagnostics::Auto, false,
[File, Nonce, &Mut, &TotalUpdates](std::vector<Diag>) {
EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce));
@@ -460,16 +463,16 @@
// Build one file in advance. We will not access it later, so it will be the
// one that the cache will evict.
- updateWithCallback(S, Foo, SourceContents, WantDiagnostics::Yes,
+ updateWithCallback(S, Foo, SourceContents, WantDiagnostics::Yes, false,
[&BuiltASTCounter]() { ++BuiltASTCounter; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
ASSERT_EQ(BuiltASTCounter.load(), 1);
// Build two more files. Since we can retain only 2 ASTs, these should be the
// ones we see in the cache later.
- updateWithCallback(S, Bar, SourceContents, WantDiagnostics::Yes,
+ updateWithCallback(S, Bar, SourceContents, WantDiagnostics::Yes, false,
[&BuiltASTCounter]() { ++BuiltASTCounter; });
- updateWithCallback(S, Baz, SourceContents, WantDiagnostics::Yes,
+ updateWithCallback(S, Baz, SourceContents, WantDiagnostics::Yes, false,
[&BuiltASTCounter]() { ++BuiltASTCounter; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
ASSERT_EQ(BuiltASTCounter.load(), 3);
@@ -478,7 +481,7 @@
ASSERT_THAT(S.getFilesWithCachedAST(), UnorderedElementsAre(Bar, Baz));
// Access the old file again.
- updateWithCallback(S, Foo, OtherSourceContents, WantDiagnostics::Yes,
+ updateWithCallback(S, Foo, OtherSourceContents, WantDiagnostics::Yes, false,
[&BuiltASTCounter]() { ++BuiltASTCounter; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
ASSERT_EQ(BuiltASTCounter.load(), 4);
@@ -506,7 +509,7 @@
int main() {}
)cpp";
auto WithEmptyPreamble = R"cpp(int main() {})cpp";
- S.update(Foo, getInputs(Foo, WithPreamble), WantDiagnostics::Auto);
+ S.update(Foo, getInputs(Foo, WithPreamble), WantDiagnostics::Auto, false);
S.runWithPreamble(
"getNonEmptyPreamble", Foo, TUScheduler::Stale,
[&](Expected<InputsAndPreamble> Preamble) {
@@ -519,7 +522,7 @@
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
// Update the file which results in an empty preamble.
- S.update(Foo, getInputs(Foo, WithEmptyPreamble), WantDiagnostics::Auto);
+ S.update(Foo, getInputs(Foo, WithEmptyPreamble), WantDiagnostics::Auto, false);
// Wait for the preamble is being built.
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
S.runWithPreamble(
@@ -550,7 +553,7 @@
constexpr int ReadsToSchedule = 10;
std::mutex PreamblesMut;
std::vector<const void *> Preambles(ReadsToSchedule, nullptr);
- S.update(Foo, getInputs(Foo, NonEmptyPreamble), WantDiagnostics::Auto);
+ S.update(Foo, getInputs(Foo, NonEmptyPreamble), WantDiagnostics::Auto, false);
for (int I = 0; I < ReadsToSchedule; ++I) {
S.runWithPreamble(
"test", Foo, TUScheduler::Stale,
@@ -588,7 +591,7 @@
auto DoUpdate = [&](std::string Contents) -> bool {
std::atomic<bool> Updated(false);
Updated = false;
- updateWithDiags(S, Source, Contents, WantDiagnostics::Yes,
+ updateWithDiags(S, Source, Contents, WantDiagnostics::Yes, false,
[&Updated](std::vector<Diag>) { Updated = true; });
bool UpdateFinished = S.blockUntilIdle(timeoutSeconds(10));
if (!UpdateFinished)
@@ -630,7 +633,7 @@
auto Contents = "int a; int b;";
updateWithDiags(
- S, FooCpp, Contents, WantDiagnostics::No,
+ S, FooCpp, Contents, WantDiagnostics::No, false,
[](std::vector<Diag>) { ADD_FAILURE() << "Should not be called."; });
S.runWithAST("touchAST", FooCpp, [](Expected<InputsAndAST> IA) {
// Make sure the AST was actually built.
@@ -641,7 +644,7 @@
// Even though the inputs didn't change and AST can be reused, we need to
// report the diagnostics, as they were not reported previously.
std::atomic<bool> SeenDiags(false);
- updateWithDiags(S, FooCpp, Contents, WantDiagnostics::Auto,
+ updateWithDiags(S, FooCpp, Contents, WantDiagnostics::Auto, false,
[&](std::vector<Diag>) { SeenDiags = true; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
ASSERT_TRUE(SeenDiags);
@@ -649,7 +652,7 @@
// Subsequent request does not get any diagnostics callback because the same
// diags have previously been reported and the inputs didn't change.
updateWithDiags(
- S, FooCpp, Contents, WantDiagnostics::Auto,
+ S, FooCpp, Contents, WantDiagnostics::Auto, false,
[&](std::vector<Diag>) { ADD_FAILURE() << "Should not be called."; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
}
@@ -667,7 +670,7 @@
}
TEST_F(TUSchedulerTests, TUStatus) {
- class CaptureTUStatus : public DiagnosticsConsumer {
+ class CaptureTUStatus : public DiagnosticsConsumer, public HighlightingsConsumer {
public:
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {}
@@ -677,6 +680,10 @@
AllStatus.push_back(Status);
}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
+
std::vector<TUStatus> allStatus() {
std::lock_guard<std::mutex> Lock(Mutex);
return AllStatus;
@@ -688,7 +695,7 @@
} CaptureTUStatus;
MockFSProvider FS;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, CaptureTUStatus, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, CaptureTUStatus, CaptureTUStatus, ClangdServer::optsForTest());
Annotations Code("int m^ain () {}");
// We schedule the following tasks in the queue:
Index: clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
+++ clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
@@ -26,9 +26,12 @@
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
-class IgnoreDiagnostics : public DiagnosticsConsumer {
+class IgnoreDiagnostics : public DiagnosticsConsumer, public HighlightingsConsumer {
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
};
// GMock helpers for matching SymbolInfos items.
@@ -58,7 +61,7 @@
class WorkspaceSymbolsTest : public ::testing::Test {
public:
WorkspaceSymbolsTest()
- : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {
+ : Server(CDB, FSProvider, DiagConsumer, DiagConsumer, optsForTests()) {
// Make sure the test root directory is created.
FSProvider.Files[testPath("unused")] = "";
CDB.ExtraClangFlags = {"-xc++"};
@@ -321,7 +324,7 @@
class DocumentSymbolsTest : public ::testing::Test {
public:
DocumentSymbolsTest()
- : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {}
+ : Server(CDB, FSProvider, DiagConsumer, DiagConsumer, optsForTests()) {}
protected:
MockFSProvider FSProvider;
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -13,6 +13,7 @@
#include "Matchers.h"
#include "Protocol.h"
#include "Quality.h"
+#include "SemanticHighlighting.h"
#include "SourceCode.h"
#include "SyncAPI.h"
#include "TestFS.h"
@@ -42,9 +43,12 @@
using ::testing::Not;
using ::testing::UnorderedElementsAre;
-class IgnoreDiagnostics : public DiagnosticsConsumer {
+class IgnoreDiagnostics : public DiagnosticsConsumer, public HighlightingsConsumer {
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
};
// GMock helpers for matching completion items.
@@ -139,7 +143,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
return completions(Server, Text, std::move(IndexSymbols), std::move(Opts),
FilePath);
}
@@ -624,7 +628,7 @@
FS.Files[BarHeader] = "";
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto BarURI = URI::create(BarHeader).toString();
Symbol Sym = cls("ns::X");
Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
@@ -663,7 +667,7 @@
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
Symbol SymX = cls("ns::X");
Symbol SymY = cls("ns::Y");
std::string BarHeader = testPath("bar.h");
@@ -691,7 +695,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
FS.Files[testPath("bar.h")] =
R"cpp(namespace ns { struct preamble { int member; }; })cpp";
@@ -743,7 +747,7 @@
IgnoreDiagnostics DiagConsumer;
ClangdServer::Options Opts = ClangdServer::optsForTest();
Opts.BuildDynamicSymbolIndex = true;
- ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, Opts);
FS.Files[testPath("foo_header.h")] = R"cpp(
#pragma once
@@ -776,7 +780,7 @@
IgnoreDiagnostics DiagConsumer;
auto Opts = ClangdServer::optsForTest();
Opts.BuildDynamicSymbolIndex = true;
- ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, Opts);
FS.Files[testPath("foo.h")] = R"cpp(
namespace ns { class XYZ {}; void foo(int x) {} }
@@ -955,7 +959,7 @@
ClangdServer::Options Opts = ClangdServer::optsForTest();
Opts.StaticIndex = Index.get();
- ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, Opts);
auto File = testPath("foo.cpp");
runAddDocument(Server, File, Text);
return llvm::cantFail(runSignatureHelp(Server, File, Point));
@@ -1394,7 +1398,7 @@
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
Annotations Source(R"cpp(
#include "foo.h"
@@ -1429,7 +1433,7 @@
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
Annotations Source(R"cpp(
// We ignore namespace comments, for rationale see CodeCompletionStrings.h.
@@ -1497,7 +1501,7 @@
MockFSProvider FS;
FS.Files[FooCpp] = "// empty file";
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
// Run completion outside the file range.
Position Pos;
Pos.line = 100;
@@ -1618,7 +1622,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
CodeCompleteOptions Opts;
Opts.IncludeFixIts = true;
@@ -1658,7 +1662,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
CodeCompleteOptions Opts;
Opts.IncludeFixIts = true;
@@ -1738,7 +1742,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
constexpr const char *TestCodes[] = {
R"cpp(
@@ -1895,7 +1899,7 @@
IgnoreDiagnostics DiagConsumer;
ClangdServer::Options Opts = ClangdServer::optsForTest();
Opts.BuildDynamicSymbolIndex = true;
- ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, Opts);
FS.Files[testPath("foo.h")] = R"cpp(
struct Foo {
@@ -2065,7 +2069,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto File = testPath("foo.cpp");
Annotations Test(R"cpp(
@@ -2127,7 +2131,7 @@
FS.Files[FooHeader] = "";
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
std::string DeclFile = URI::create(testPath("foo")).toString();
Symbol sym = func("Func");
@@ -2158,7 +2162,7 @@
std::string FooHeader = testPath("foo.h");
FS.Files[FooHeader] = "#define CLANGD_PREAMBLE_HEADER x\n";
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto Results = completions(
R"cpp(#include "foo.h"
#define CLANGD_PREAMBLE_MAIN x
@@ -2279,7 +2283,7 @@
std::string BarHeader = testPath("sub/bar.h");
FS.Files[BarHeader] = "";
IgnoreDiagnostics DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto Results = completions(Server,
R"cpp(
#include "^"
Index: clang-tools-extra/clangd/unittests/ClangdTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -59,7 +59,7 @@
return false;
}
-class ErrorCheckingDiagConsumer : public DiagnosticsConsumer {
+class ErrorCheckingDiagConsumer : public DiagnosticsConsumer, public HighlightingsConsumer {
public:
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {
@@ -73,6 +73,10 @@
return HadErrorInLastDiags;
}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
+
private:
std::mutex Mutex;
bool HadErrorInLastDiags = false;
@@ -80,7 +84,7 @@
/// For each file, record whether the last published diagnostics contained at
/// least one error.
-class MultipleErrorCheckingDiagConsumer : public DiagnosticsConsumer {
+class MultipleErrorCheckingDiagConsumer : public DiagnosticsConsumer, public HighlightingsConsumer {
public:
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {
@@ -101,6 +105,10 @@
return Result;
}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
+
void clear() {
std::lock_guard<std::mutex> Lock(Mutex);
LastDiagsHadError.clear();
@@ -144,7 +152,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
for (const auto &FileWithContents : ExtraFiles)
FS.Files[testPath(FileWithContents.first)] = FileWithContents.second;
@@ -196,7 +204,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
const auto SourceContents = R"cpp(
#include "foo.h"
@@ -231,7 +239,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
const auto SourceContents = R"cpp(
#include "foo.h"
@@ -274,17 +282,20 @@
}
mutable int Got;
} FS;
- struct DiagConsumer : public DiagnosticsConsumer {
+ struct DiagConsumer : public DiagnosticsConsumer, public HighlightingsConsumer {
void onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) override {
Got = Context::current().getExisting(Secret);
}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
int Got;
} DiagConsumer;
MockCompilationDatabase CDB;
// Verify that the context is plumbed to the FS provider and diagnostics.
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
{
WithContextValue Entrypoint(Secret, 42);
Server.addDocument(testPath("foo.cpp"), "void main(){}");
@@ -305,7 +316,7 @@
{"-xc++", "-target", "x86_64-linux-unknown",
"-m64", "--gcc-toolchain=/randomusr",
"-stdlib=libstdc++"});
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
// Just a random gcc version string
SmallString<8> Version("4.9.3");
@@ -350,7 +361,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
const auto SourceContents1 = R"cpp(
@@ -386,7 +397,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
const auto SourceContents = R"cpp(
@@ -438,7 +449,7 @@
MockFSProvider FS;
MockCompilationDatabase CDB;
MultipleErrorCheckingDiagConsumer DiagConsumer;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
auto BarCpp = testPath("bar.cpp");
@@ -482,7 +493,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
Path FooCpp = testPath("foo.cpp");
const auto SourceContents = R"cpp(
@@ -518,7 +529,7 @@
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
// clang cannot create CompilerInvocation if we pass two files in the
@@ -589,7 +600,7 @@
bool HadErrorsInLastDiags = false;
};
- class TestDiagConsumer : public DiagnosticsConsumer {
+ class TestDiagConsumer : public DiagnosticsConsumer, public HighlightingsConsumer {
public:
TestDiagConsumer() : Stats(FilesCount, FileStat()) {}
@@ -610,6 +621,10 @@
Stats[FileIndex].HadErrorsInLastDiags = HadError;
}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
+
std::vector<FileStat> takeFileStats() {
std::lock_guard<std::mutex> Lock(Mutex);
return std::move(Stats);
@@ -635,7 +650,7 @@
TestDiagConsumer DiagConsumer;
{
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
// Prepare some random distributions for the test.
std::random_device RandGen;
@@ -769,7 +784,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto SourceContents = R"cpp(
#include "foo.h"
@@ -842,7 +857,7 @@
}
TEST_F(ClangdThreadingTest, NoConcurrentDiagnostics) {
- class NoConcurrentAccessDiagConsumer : public DiagnosticsConsumer {
+ class NoConcurrentAccessDiagConsumer : public DiagnosticsConsumer, public HighlightingsConsumer {
public:
std::atomic<int> Count = {0};
@@ -864,6 +879,10 @@
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
+ virtual void
+ onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {}
+
private:
std::mutex Mutex;
@@ -894,7 +913,7 @@
NoConcurrentAccessDiagConsumer DiagConsumer(std::move(StartSecondPromise));
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
Server.addDocument(FooCpp, SourceContentsWithErrors);
StartSecond.wait();
Server.addDocument(FooCpp, SourceContentsWithoutErrors);
@@ -906,7 +925,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto Path = testPath("foo.cpp");
std::string Code = R"cpp(
@@ -935,7 +954,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto SourcePath = testPath("source/foo.cpp");
auto HeaderPath = testPath("headers/foo.h");
@@ -1010,7 +1029,7 @@
ListenStatsFSProvider FS(CountStats);
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto SourcePath = testPath("foo.cpp");
auto HeaderPath = testPath("foo.h");
@@ -1046,7 +1065,7 @@
"random-plugin",
};
OverlayCDB OCDB(&CDB);
- ClangdServer Server(OCDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(OCDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
const auto SourceContents = "int main() { return 0; }";
@@ -1061,7 +1080,7 @@
MockFSProvider FS;
ErrorCheckingDiagConsumer DiagConsumer;
MockCompilationDatabase CDB;
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
Annotations Code(R"cpp(
@@ -1131,7 +1150,7 @@
Notification CanReturnCommand;
DelayedCompilationDatabase CDB(CanReturnCommand);
- ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ ClangdServer Server(CDB, FS, DiagConsumer, DiagConsumer, ClangdServer::optsForTest());
auto FooCpp = testPath("foo.cpp");
Annotations Code(R"cpp(
Index: clang-tools-extra/clangd/TUScheduler.h
===================================================================
--- clang-tools-extra/clangd/TUScheduler.h
+++ clang-tools-extra/clangd/TUScheduler.h
@@ -12,6 +12,7 @@
#include "ClangdUnit.h"
#include "Function.h"
#include "GlobalCompilationDatabase.h"
+#include "SemanticHighlighting.h"
#include "Threading.h"
#include "index/CanonicalIncludes.h"
#include "llvm/ADT/Optional.h"
@@ -115,6 +116,10 @@
/// Called whenever the TU status is updated.
virtual void onFileUpdated(PathRef File, const TUStatus &Status) {}
+
+ // Called whenever some highlightings for \p File are updated
+ virtual void onHighlightings(PathRef File,
+ std::vector<HighlightingToken> Highlightings) {}
};
/// Handles running tasks for ClangdServer and managing the resources (e.g.,
@@ -148,7 +153,8 @@
/// If diagnostics are requested (Yes), and the context is cancelled
/// before they are prepared, they may be skipped if eventual-consistency
/// permits it (i.e. WantDiagnostics is downgraded to Auto).
- void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD);
+ void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD,
+ bool WantHighlightings);
/// Remove \p File from the list of tracked files and schedule removal of its
/// resources. Pending diagnostics for closed files may not be delivered, even
Index: clang-tools-extra/clangd/TUScheduler.cpp
===================================================================
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -175,7 +175,7 @@
bool StorePreamblesInMemory, ParsingCallbacks &Callbacks);
~ASTWorker();
- void update(ParseInputs Inputs, WantDiagnostics);
+ void update(ParseInputs Inputs, WantDiagnostics, bool WantHighlightings);
void
runWithAST(llvm::StringRef Name,
llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action);
@@ -361,7 +361,8 @@
#endif
}
-void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
+void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags,
+ bool WantHighlightings) {
llvm::StringRef TaskName = "Update";
auto Task = [=]() mutable {
// Get the actual command as `Inputs` does not have a command.
@@ -423,6 +424,7 @@
std::lock_guard<std::mutex> Lock(Mutex);
LastBuiltPreamble = NewPreamble;
}
+
// Before doing the expensive AST reparse, we want to release our reference
// to the old preamble, so it can be freed if there are no other references
// to it.
@@ -452,19 +454,21 @@
}
}
- // We only need to build the AST if diagnostics were requested.
- if (WantDiags == WantDiagnostics::No)
+ // We only need to build the AST if diagnostics were requested or if new
+ // syntax highlights should be generated.
+ if (WantDiags == WantDiagnostics::No && !WantHighlightings)
return;
{
std::lock_guard<std::mutex> Lock(DiagsMu);
- // No need to rebuild the AST if we won't send the diagnotics. However,
- // note that we don't prevent preamble rebuilds.
- if (!ReportDiagnostics)
+ // No need to rebuild the AST if we won't send the diagnotics or generate
+ // syntax highlights. However, note that we don't prevent preamble
+ // rebuilds.
+ if (!ReportDiagnostics && !WantHighlightings)
return;
}
- // Get the AST for diagnostics.
+ // Get the AST.
llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
if (!AST) {
llvm::Optional<ParsedAST> NewAST =
@@ -481,19 +485,26 @@
Details.ReuseAST = true;
emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
}
+
// We want to report the diagnostics even if this update was cancelled.
// It seems more useful than making the clients wait indefinitely if they
// spam us with updates.
// Note *AST can still be null if buildAST fails.
if (*AST) {
- {
+ if(ReportDiagnostics) {
std::lock_guard<std::mutex> Lock(DiagsMu);
if (ReportDiagnostics)
Callbacks.onDiagnostics(FileName, (*AST)->getDiagnostics());
+ DiagsWereReported = true;
}
+
+ if (WantHighlightings) {
+ std::vector<HighlightingToken> Highlightings = getSemanticHighlightings(**AST);
+ Callbacks.onHighlightings(FileName, Highlightings);
+ }
+
trace::Span Span("Running main AST callback");
Callbacks.onMainAST(FileName, **AST);
- DiagsWereReported = true;
}
// Stash the AST in the cache for further use.
IdleASTs.put(this, std::move(*AST));
@@ -861,7 +872,7 @@
}
void TUScheduler::update(PathRef File, ParseInputs Inputs,
- WantDiagnostics WantDiags) {
+ WantDiagnostics WantDiags, bool WantHighlightings) {
std::unique_ptr<FileData> &FD = Files[File];
if (!FD) {
// Create a new worker to process the AST-related tasks.
@@ -874,7 +885,7 @@
} else {
FD->Contents = Inputs.Contents;
}
- FD->Worker->update(std::move(Inputs), WantDiags);
+ FD->Worker->update(std::move(Inputs), WantDiags, WantHighlightings);
}
void TUScheduler::remove(PathRef File) {
Index: clang-tools-extra/clangd/SemanticHighlighting.h
===================================================================
--- clang-tools-extra/clangd/SemanticHighlighting.h
+++ clang-tools-extra/clangd/SemanticHighlighting.h
@@ -30,6 +30,10 @@
// Returns all HighlightingTokens from an AST. Only generates highlights for the
// main AST.
std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST);
+// Returns a map where all HighlightingKinds are mapped to a vector of TextMate
+// scopes.
+std::map<HighlightingKind, std::vector<std::string>>
+getSemanticHighlightingScopes();
} // namespace clangd
} // namespace clang
Index: clang-tools-extra/clangd/SemanticHighlighting.cpp
===================================================================
--- clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -74,5 +74,11 @@
return HighlightingTokenCollector(AST).collectTokens();
}
+std::map<HighlightingKind, std::vector<std::string>>
+getSemanticHighlightingScopes() {
+ return {{HighlightingKind::Variable, {"variable"}},
+ {HighlightingKind::Function, {"entity.name.function"}}};
+}
+
} // namespace clangd
} // namespace clang
Index: clang-tools-extra/clangd/ClangdServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdServer.h
+++ 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"
@@ -51,6 +52,15 @@
virtual void onFileUpdated(PathRef File, const TUStatus &Status){};
};
+class HighlightingsConsumer {
+public:
+ virtual ~HighlightingsConsumer() = default;
+
+ // Called by ClangdServer when some \p Highlightings for \p File are ready.
+ virtual void onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) = 0;
+};
+
/// When set, used by ClangdServer to get clang-tidy options for each particular
/// file. Must be thread-safe. We use this instead of ClangTidyOptionsProvider
/// to allow reading tidy configs from the VFS used for parsing.
@@ -131,6 +141,10 @@
/// Clangd will execute compiler drivers matching one of these globs to
/// fetch system include path.
std::vector<std::string> QueryDriverGlobs;
+
+ // If true Clangd will generate semantic highlightings for the current
+ // document when it changes.
+ bool SemanticHighlightingEnabled = false;
};
// Sensible default options for use in tests.
// Features like indexing must be enabled if desired.
@@ -148,9 +162,13 @@
/// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on a
/// worker thread. Therefore, instances of \p DiagConsumer must properly
/// synchronize access to shared state.
+ /// If semantic highlighting is enabled ClangdServer also generates semantic
+ /// highlightings for the file after each parsing request. When highlightings
+ /// are done generating they are sent to \p HConsumer
ClangdServer(const GlobalCompilationDatabase &CDB,
const FileSystemProvider &FSProvider,
- DiagnosticsConsumer &DiagConsumer, const Options &Opts);
+ DiagnosticsConsumer &DiagConsumer,
+ HighlightingsConsumer &HConsumer, const Options &Opts);
/// Add a \p File to the list of tracked C++ files or update the contents if
/// \p File is already tracked. Also schedules parsing of the AST for it on a
@@ -304,6 +322,9 @@
// can be caused by missing includes (e.g. member access in incomplete type).
bool SuggestMissingIncludes = false;
bool EnableHiddenFeatures = false;
+
+ // If this is true semantic highlighting will be generated.
+ bool SemanticHighlightingEnabled = false;
// GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
llvm::StringMap<llvm::Optional<FuzzyFindRequest>>
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -48,8 +48,9 @@
// 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,
+ HighlightingsConsumer &HConsumer)
+ : FIndex(FIndex), DiagConsumer(DiagConsumer), HConsumer(HConsumer) {}
void onPreambleAST(PathRef Path, ASTContext &Ctx,
std::shared_ptr<clang::Preprocessor> PP,
@@ -71,9 +72,15 @@
DiagConsumer.onFileUpdated(File, Status);
}
+ virtual void onHighlightings(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override {
+ HConsumer.onHighlightingsReady(File, Highlightings);
+ }
+
private:
FileIndex *FIndex;
DiagnosticsConsumer &DiagConsumer;
+ HighlightingsConsumer &HConsumer;
};
} // namespace
@@ -88,7 +95,7 @@
ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
const FileSystemProvider &FSProvider,
DiagnosticsConsumer &DiagConsumer,
- const Options &Opts)
+ HighlightingsConsumer &HConsumer, const Options &Opts)
: FSProvider(FSProvider),
DynamicIdx(Opts.BuildDynamicSymbolIndex
? new FileIndex(Opts.HeavyweightDynamicSymbolIndex)
@@ -96,6 +103,7 @@
GetClangTidyOptions(Opts.GetClangTidyOptions),
SuggestMissingIncludes(Opts.SuggestMissingIncludes),
EnableHiddenFeatures(Opts.HiddenFeatures),
+ SemanticHighlightingEnabled(Opts.SemanticHighlightingEnabled),
WorkspaceRoot(Opts.WorkspaceRoot),
// Pass a callback into `WorkScheduler` to extract symbols from a newly
// parsed file and rebuild the file index synchronously each time an AST
@@ -103,8 +111,8 @@
// 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<UpdateIndexCallbacks>(DynamicIdx.get(),
- DiagConsumer),
+ llvm::make_unique<UpdateIndexCallbacks>(
+ DynamicIdx.get(), DiagConsumer, HConsumer),
Opts.UpdateDebounce, Opts.RetentionPolicy) {
// Adds an index to the stack, at higher priority than existing indexes.
auto AddIndex = [&](SymbolIndex *Idx) {
@@ -145,7 +153,7 @@
Inputs.Contents = Contents;
Inputs.Opts = std::move(Opts);
Inputs.Index = Index;
- WorkScheduler.update(File, Inputs, WantDiags);
+ WorkScheduler.update(File, Inputs, WantDiags, SemanticHighlightingEnabled);
}
void ClangdServer::removeDocument(PathRef File) { WorkScheduler.remove(File); }
Index: clang-tools-extra/clangd/ClangdLSPServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.h
+++ clang-tools-extra/clangd/ClangdLSPServer.h
@@ -16,6 +16,7 @@
#include "GlobalCompilationDatabase.h"
#include "Path.h"
#include "Protocol.h"
+#include "SemanticHighlighting.h"
#include "Transport.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/Optional.h"
@@ -31,7 +32,7 @@
/// MessageHandler binds the implemented LSP methods (e.g. onInitialize) to
/// corresponding JSON-RPC methods ("initialize").
/// The server also supports $/cancelRequest (MessageHandler provides this).
-class ClangdLSPServer : private DiagnosticsConsumer {
+class ClangdLSPServer : private DiagnosticsConsumer, private HighlightingsConsumer {
public:
/// If \p CompileCommandsDir has a value, compile_commands.json will be
/// loaded only from \p CompileCommandsDir. Otherwise, clangd will look
@@ -56,6 +57,10 @@
void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
void onFileUpdated(PathRef File, const TUStatus &Status) override;
+ // Implement HighlightingsConsumer
+ void onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) override;
+
// LSP methods. Notifications have signature void(const Params&).
// Calls have signature void(const Params&, Callback<Response>).
void onInitialize(const InitializeParams &, Callback<llvm::json::Value>);
Index: clang-tools-extra/clangd/ClangdLSPServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -347,7 +347,7 @@
CDB.emplace(BaseCDB.get(), Params.initializationOptions.fallbackFlags,
ClangdServerOpts.ResourceDir);
Server.emplace(*CDB, FSProvider, static_cast<DiagnosticsConsumer &>(*this),
- ClangdServerOpts);
+ static_cast<HighlightingsConsumer &>(*this), ClangdServerOpts);
applyConfiguration(Params.initializationOptions.ConfigSettings);
CCOpts.EnableSnippets = Params.capabilities.CompletionSnippets;
@@ -1063,6 +1063,11 @@
return true;
}
+void ClangdLSPServer::onHighlightingsReady(PathRef File,
+ std::vector<HighlightingToken> Highlightings) {
+
+}
+
void ClangdLSPServer::onDiagnosticsReady(PathRef File,
std::vector<Diag> Diagnostics) {
auto URI = URIForFile::canonicalize(File, /*TUPath=*/File);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits