[clang-tools-extra] 3f6a904 - [clangd] Inactive regions support via dedicated protocol
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 14 00:12:47 PDT 2023
Author: Nathan Ridge
Date: 2023-04-14T03:12:36-04:00
New Revision: 3f6a904b2f3d8e974b223097956bb1ea51822782
URL: https://github.com/llvm/llvm-project/commit/3f6a904b2f3d8e974b223097956bb1ea51822782
DIFF: https://github.com/llvm/llvm-project/commit/3f6a904b2f3d8e974b223097956bb1ea51822782.diff
LOG: [clangd] Inactive regions support via dedicated protocol
This implements the server side of the approach discussed at
https://github.com/clangd/vscode-clangd/pull/193#issuecomment-1044315732
Differential Revision: https://reviews.llvm.org/D143974
Added:
Modified:
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/Protocol.cpp
clang-tools-extra/clangd/Protocol.h
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/refactor/tweaks/AnnotateHighlightings.cpp
clang-tools-extra/clangd/tool/Check.cpp
clang-tools-extra/clangd/unittests/ClangdTests.cpp
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 860519d21b0e0..6ead59a7ec90e 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -494,6 +494,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation;
Opts.ImplicitCancellation = !Params.capabilities.CancelsStaleRequests;
+ Opts.PublishInactiveRegions = Params.capabilities.InactiveRegions;
if (Opts.UseDirBasedCDB) {
DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
@@ -582,6 +583,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
{"memoryUsageProvider", true}, // clangd extension
{"compilationDatabase", // clangd extension
llvm::json::Object{{"automaticReload", true}}},
+ {"inactiveRegionsProvider", true}, // clangd extension
{"callHierarchyProvider", true},
{"clangdInlayHintsProvider", true},
{"inlayHintProvider", true},
@@ -1625,6 +1627,8 @@ void ClangdLSPServer::bindMethods(LSPBinder &Bind,
ApplyWorkspaceEdit = Bind.outgoingMethod("workspace/applyEdit");
PublishDiagnostics = Bind.outgoingNotification("textDocument/publishDiagnostics");
+ if (Caps.InactiveRegions)
+ PublishInactiveRegions = Bind.outgoingNotification("textDocument/inactiveRegions");
ShowMessage = Bind.outgoingNotification("window/showMessage");
NotifyFileStatus = Bind.outgoingNotification("textDocument/clangd.fileStatus");
CreateWorkDoneProgress = Bind.outgoingMethod("window/workDoneProgress/create");
@@ -1722,6 +1726,15 @@ void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version,
PublishDiagnostics(Notification);
}
+void ClangdLSPServer::onInactiveRegionsReady(
+ PathRef File, std::vector<Range> InactiveRegions) {
+ InactiveRegionsParams Notification;
+ Notification.TextDocument = {URIForFile::canonicalize(File, /*TUPath=*/File)};
+ Notification.InactiveRegions = std::move(InactiveRegions);
+
+ PublishInactiveRegions(Notification);
+}
+
void ClangdLSPServer::onBackgroundIndexProgress(
const BackgroundQueue::Stats &Stats) {
static const char ProgressToken[] = "backgroundIndexProgress";
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h
index 39ee1b9a3fbce..cd5bb662c3931 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -83,6 +83,8 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
void onFileUpdated(PathRef File, const TUStatus &Status) override;
void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) override;
void onSemanticsMaybeChanged(PathRef File) override;
+ void onInactiveRegionsReady(PathRef File,
+ std::vector<Range> InactiveRegions) override;
// LSP methods. Notifications have signature void(const Params&).
// Calls have signature void(const Params&, Callback<Response>).
@@ -180,6 +182,7 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
LSPBinder::OutgoingNotification<ShowMessageParams> ShowMessage;
LSPBinder::OutgoingNotification<PublishDiagnosticsParams> PublishDiagnostics;
LSPBinder::OutgoingNotification<FileStatus> NotifyFileStatus;
+ LSPBinder::OutgoingNotification<InactiveRegionsParams> PublishInactiveRegions;
LSPBinder::OutgoingMethod<WorkDoneProgressCreateParams, std::nullptr_t>
CreateWorkDoneProgress;
LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressBegin>>
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 193e92ca71864..7c5042b8414b4 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -61,9 +61,11 @@ namespace {
struct UpdateIndexCallbacks : public ParsingCallbacks {
UpdateIndexCallbacks(FileIndex *FIndex,
ClangdServer::Callbacks *ServerCallbacks,
- const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks)
+ const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks,
+ bool CollectInactiveRegions)
: FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
- Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks) {}
+ Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks),
+ CollectInactiveRegions(CollectInactiveRegions) {}
void onPreambleAST(PathRef Path, llvm::StringRef Version,
const CompilerInvocation &CI, ASTContext &Ctx,
@@ -113,6 +115,10 @@ struct UpdateIndexCallbacks : public ParsingCallbacks {
Publish([&]() {
ServerCallbacks->onDiagnosticsReady(Path, AST.version(),
std::move(Diagnostics));
+ if (CollectInactiveRegions) {
+ ServerCallbacks->onInactiveRegionsReady(
+ Path, std::move(AST.getMacros().SkippedRanges));
+ }
});
}
@@ -139,6 +145,7 @@ struct UpdateIndexCallbacks : public ParsingCallbacks {
const ThreadsafeFS &TFS;
std::shared_ptr<StdLibSet> Stdlib;
AsyncTaskRunner *Tasks;
+ bool CollectInactiveRegions;
};
class DraftStoreFS : public ThreadsafeFS {
@@ -189,6 +196,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
LineFoldingOnly(Opts.LineFoldingOnly),
PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
ImportInsertions(Opts.ImportInsertions),
+ PublishInactiveRegions(Opts.PublishInactiveRegions),
WorkspaceRoot(Opts.WorkspaceRoot),
Transient(Opts.ImplicitCancellation ? TUScheduler::InvalidateOnUpdate
: TUScheduler::NoInvalidation),
@@ -201,7 +209,8 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
WorkScheduler.emplace(CDB, TUScheduler::Options(Opts),
std::make_unique<UpdateIndexCallbacks>(
DynamicIdx.get(), Callbacks, TFS,
- IndexTasks ? &*IndexTasks : nullptr));
+ IndexTasks ? &*IndexTasks : nullptr,
+ PublishInactiveRegions));
// Adds an index to the stack, at higher priority than existing indexes.
auto AddIndex = [&](SymbolIndex *Idx) {
if (this->Index != nullptr) {
@@ -956,12 +965,17 @@ void ClangdServer::documentLinks(PathRef File,
void ClangdServer::semanticHighlights(
PathRef File, Callback<std::vector<HighlightingToken>> CB) {
- auto Action =
- [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
- if (!InpAST)
- return CB(InpAST.takeError());
- CB(clangd::getSemanticHighlightings(InpAST->AST));
- };
+
+ auto Action = [CB = std::move(CB),
+ PublishInactiveRegions = PublishInactiveRegions](
+ llvm::Expected<InputsAndAST> InpAST) mutable {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ // Include inactive regions in semantic highlighting tokens only if the
+ // client doesn't support a dedicated protocol for being informed about
+ // them.
+ CB(clangd::getSemanticHighlightings(InpAST->AST, !PublishInactiveRegions));
+ };
WorkScheduler->runWithAST("SemanticHighlights", File, std::move(Action),
Transient);
}
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index b87ff0bf54b70..f47216a051769 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -84,6 +84,11 @@ class ClangdServer {
/// build finishes, we can provide more accurate semantic tokens, so we
/// should tell the client to refresh.
virtual void onSemanticsMaybeChanged(PathRef File) {}
+
+ /// Called by ClangdServer when some \p InactiveRegions for \p File are
+ /// ready.
+ virtual void onInactiveRegionsReady(PathRef File,
+ std::vector<Range> InactiveRegions) {}
};
/// Creates a context provider that loads and installs config.
/// Errors in loading config are reported as diagnostics via Callbacks.
@@ -175,6 +180,10 @@ class ClangdServer {
/// instead of #include.
bool ImportInsertions = false;
+ /// Whether to collect and publish information about inactive preprocessor
+ /// regions in the document.
+ bool PublishInactiveRegions = false;
+
explicit operator TUScheduler::Options() const;
};
// Sensible default options for use in tests.
@@ -440,6 +449,8 @@ class ClangdServer {
bool ImportInsertions = false;
+ bool PublishInactiveRegions = false;
+
// GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
llvm::StringMap<std::optional<FuzzyFindRequest>>
CachedCompletionFuzzyFindRequestByFile;
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index d3e92a4dbd7d6..4b2472ad4be04 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -338,6 +338,13 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R,
SemanticHighlighting->getBoolean("semanticHighlighting"))
R.TheiaSemanticHighlighting = *SemanticHighlightingSupport;
}
+ if (auto *InactiveRegions =
+ TextDocument->getObject("inactiveRegionsCapabilities")) {
+ if (auto InactiveRegionsSupport =
+ InactiveRegions->getBoolean("inactiveRegions")) {
+ R.InactiveRegions = *InactiveRegionsSupport;
+ }
+ }
if (TextDocument->getObject("semanticTokens"))
R.SemanticTokens = true;
if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
@@ -1174,6 +1181,12 @@ bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R,
O.map("previousResultId", R.previousResultId);
}
+llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) {
+ return llvm::json::Object{
+ {"textDocument", InactiveRegions.TextDocument},
+ {"regions", std::move(InactiveRegions.InactiveRegions)}};
+}
+
llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
const DocumentHighlight &V) {
O << V.range;
diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h
index 2f38c61aec896..eb271676e651f 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -516,6 +516,10 @@ struct ClientCapabilities {
/// Whether the client implementation supports a refresh request sent from the
/// server to the client.
bool SemanticTokenRefreshSupport = false;
+
+ /// Whether the client supports the textDocument/inactiveRegions
+ /// notification. This is a clangd extension.
+ bool InactiveRegions = false;
};
bool fromJSON(const llvm::json::Value &, ClientCapabilities &,
llvm::json::Path);
@@ -1736,6 +1740,16 @@ struct SemanticTokensOrDelta {
};
llvm::json::Value toJSON(const SemanticTokensOrDelta &);
+/// Parameters for the inactive regions (server-side) push notification.
+/// This is a clangd extension.
+struct InactiveRegionsParams {
+ /// The textdocument these inactive regions belong to.
+ TextDocumentIdentifier TextDocument;
+ /// The inactive regions that should be sent.
+ std::vector<Range> InactiveRegions;
+};
+llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions);
+
struct SelectionRangeParams {
/// The text document.
TextDocumentIdentifier textDocument;
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 2122cb86c2834..f884a6b019231 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -357,9 +357,10 @@ resolveConflict(ArrayRef<HighlightingToken> Tokens) {
/// Consumes source locations and maps them to text ranges for highlightings.
class HighlightingsBuilder {
public:
- HighlightingsBuilder(const ParsedAST &AST)
+ HighlightingsBuilder(const ParsedAST &AST, bool IncludeInactiveRegionTokens)
: TB(AST.getTokens()), SourceMgr(AST.getSourceManager()),
- LangOpts(AST.getLangOpts()) {}
+ LangOpts(AST.getLangOpts()),
+ IncludeInactiveRegionTokens(IncludeInactiveRegionTokens) {}
HighlightingToken &addToken(SourceLocation Loc, HighlightingKind Kind) {
auto Range = getRangeForSourceLocation(Loc);
@@ -458,6 +459,9 @@ class HighlightingsBuilder {
TokRef = TokRef.drop_front(Conflicting.size());
}
+ if (!IncludeInactiveRegionTokens)
+ return NonConflicting;
+
const auto &SM = AST.getSourceManager();
StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
@@ -531,6 +535,7 @@ class HighlightingsBuilder {
const syntax::TokenBuffer &TB;
const SourceManager &SourceMgr;
const LangOptions &LangOpts;
+ bool IncludeInactiveRegionTokens;
std::vector<HighlightingToken> Tokens;
std::map<Range, llvm::SmallVector<HighlightingModifier, 1>> ExtraModifiers;
const HeuristicResolver *Resolver = nullptr;
@@ -1096,10 +1101,11 @@ class CollectExtraHighlightings
};
} // namespace
-std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) {
+std::vector<HighlightingToken>
+getSemanticHighlightings(ParsedAST &AST, bool IncludeInactiveRegionTokens) {
auto &C = AST.getASTContext();
// Add highlightings for AST nodes.
- HighlightingsBuilder Builder(AST);
+ HighlightingsBuilder Builder(AST, IncludeInactiveRegionTokens);
// Highlight 'decltype' and 'auto' as their underlying types.
CollectExtraHighlightings(Builder).TraverseAST(C);
// Highlight all decls and references coming from the AST.
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h
index a6620e8e347b6..10dd1193001bb 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.h
+++ b/clang-tools-extra/clangd/SemanticHighlighting.h
@@ -106,7 +106,8 @@ bool operator<(const HighlightingToken &L, const HighlightingToken &R);
// Returns all HighlightingTokens from an AST. Only generates highlights for the
// main AST.
-std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST);
+std::vector<HighlightingToken>
+getSemanticHighlightings(ParsedAST &AST, bool IncludeInactiveRegionTokens);
std::vector<SemanticToken> toSemanticTokens(llvm::ArrayRef<HighlightingToken>,
llvm::StringRef Code);
diff --git a/clang-tools-extra/clangd/refactor/tweaks/AnnotateHighlightings.cpp b/clang-tools-extra/clangd/refactor/tweaks/AnnotateHighlightings.cpp
index 2a34e43f980ba..3a320260238b6 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/AnnotateHighlightings.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/AnnotateHighlightings.cpp
@@ -47,14 +47,16 @@ Expected<Tweak::Effect> AnnotateHighlightings::apply(const Selection &Inputs) {
// Now we hit the TUDecl case where commonAncestor() returns null
// intendedly. We only annotate tokens in the main file, so use the default
// traversal scope (which is the top level decls of the main file).
- HighlightingTokens = getSemanticHighlightings(*Inputs.AST);
+ HighlightingTokens = getSemanticHighlightings(
+ *Inputs.AST, /*IncludeInactiveRegionTokens=*/true);
} else {
// Store the existing scopes.
const auto &BackupScopes = Inputs.AST->getASTContext().getTraversalScope();
// Narrow the traversal scope to the selected node.
Inputs.AST->getASTContext().setTraversalScope(
{const_cast<Decl *>(CommonDecl)});
- HighlightingTokens = getSemanticHighlightings(*Inputs.AST);
+ HighlightingTokens = getSemanticHighlightings(
+ *Inputs.AST, /*IncludeInactiveRegionTokens=*/true);
// Restore the traversal scope.
Inputs.AST->getASTContext().setTraversalScope(BackupScopes);
}
diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp
index 33ae3b1612b97..4a6f6f8857aa0 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -344,7 +344,8 @@ class Checker {
void buildSemanticHighlighting(std::optional<Range> LineRange) {
log("Building semantic highlighting");
- auto Highlights = getSemanticHighlightings(*AST);
+ auto Highlights =
+ getSemanticHighlightings(*AST, /*IncludeInactiveRegionTokens=*/true);
for (const auto HL : Highlights)
if (!LineRange || LineRange->contains(HL.R))
vlog(" {0} {1} {2}", HL.R, HL.Kind, HL.Modifiers);
diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
index 194fde9fc4e46..c6b464fb78746 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -1310,6 +1310,50 @@ TEST(ClangdServer, RespectsTweakFormatting) {
});
N.wait();
}
+
+TEST(ClangdServer, InactiveRegions) {
+ struct InactiveRegionsCallback : ClangdServer::Callbacks {
+ std::vector<std::vector<Range>> FoundInactiveRegions;
+
+ void onInactiveRegionsReady(PathRef FIle,
+ std::vector<Range> InactiveRegions) override {
+ FoundInactiveRegions.push_back(std::move(InactiveRegions));
+ }
+ };
+
+ MockFS FS;
+ MockCompilationDatabase CDB;
+ CDB.ExtraClangFlags.push_back("-DCMDMACRO");
+ auto Opts = ClangdServer::optsForTest();
+ Opts.PublishInactiveRegions = true;
+ InactiveRegionsCallback Callback;
+ ClangdServer Server(CDB, FS, Opts, &Callback);
+ Annotations Source(R"cpp(
+#define PREAMBLEMACRO 42
+#if PREAMBLEMACRO > 40
+ #define ACTIVE
+$inactive1[[#else
+ #define INACTIVE
+#endif]]
+int endPreamble;
+$inactive2[[#ifndef CMDMACRO
+ int inactiveInt;
+#endif]]
+#undef CMDMACRO
+$inactive3[[#ifdef CMDMACRO
+ int inactiveInt2;
+#else]]
+ int activeInt;
+#endif
+ )cpp");
+ Server.addDocument(testPath("foo.cpp"), Source.code());
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+ EXPECT_THAT(Callback.FoundInactiveRegions,
+ ElementsAre(ElementsAre(Source.range("inactive1"),
+ Source.range("inactive2"),
+ Source.range("inactive3"))));
+}
+
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 975378118b7ad..cd912bc220345 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -89,7 +89,8 @@ void checkHighlightings(llvm::StringRef Code,
for (auto File : AdditionalFiles)
TU.AdditionalFiles.insert({File.first, std::string(File.second)});
auto AST = TU.build();
- auto Actual = getSemanticHighlightings(AST);
+ auto Actual =
+ getSemanticHighlightings(AST, /*IncludeInactiveRegionTokens=*/true);
for (auto &Token : Actual)
Token.Modifiers &= ModifierMask;
More information about the cfe-commits
mailing list