[clang-tools-extra] a11ec00 - FoldingRanges: Handle LineFoldingsOnly clients.
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 29 10:03:59 PDT 2022
Author: Utkarsh Saxena
Date: 2022-08-29T19:03:48+02:00
New Revision: a11ec00afea327419ec1ab7c78ba6818d6c5bbf7
URL: https://github.com/llvm/llvm-project/commit/a11ec00afea327419ec1ab7c78ba6818d6c5bbf7
DIFF: https://github.com/llvm/llvm-project/commit/a11ec00afea327419ec1ab7c78ba6818d6c5bbf7.diff
LOG: FoldingRanges: Handle LineFoldingsOnly clients.
Do not fold the endline which contains tokens after the end of range.
Differential Revision: https://reviews.llvm.org/D131154
Added:
Modified:
clang-tools-extra/clangd/ClangdLSPServer.cpp
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/SemanticSelection.cpp
clang-tools-extra/clangd/SemanticSelection.h
clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 66bda05d00f71..e0129d99d9706 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -514,6 +514,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
Params.capabilities.HierarchicalDocumentSymbol;
SupportFileStatus = Params.initializationOptions.FileStatus;
HoverContentFormat = Params.capabilities.HoverContentFormat;
+ Opts.LineFoldingOnly = Params.capabilities.LineFoldingOnly;
SupportsOffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp;
if (Params.capabilities.WorkDoneProgress)
BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 2997823e75fc3..5c4263d0ee6cb 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -177,6 +177,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr),
ClangTidyProvider(Opts.ClangTidyProvider),
UseDirtyHeaders(Opts.UseDirtyHeaders),
+ LineFoldingOnly(Opts.LineFoldingOnly),
PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
WorkspaceRoot(Opts.WorkspaceRoot),
Transient(Opts.ImplicitCancellation ? TUScheduler::InvalidateOnUpdate
@@ -855,8 +856,9 @@ void ClangdServer::foldingRanges(llvm::StringRef File,
return CB(llvm::make_error<LSPError>(
"trying to compute folding ranges for non-added document",
ErrorCode::InvalidParams));
- auto Action = [CB = std::move(CB), Code = std::move(*Code)]() mutable {
- CB(clangd::getFoldingRanges(Code));
+ auto Action = [LineFoldingOnly = LineFoldingOnly, CB = std::move(CB),
+ Code = std::move(*Code)]() mutable {
+ CB(clangd::getFoldingRanges(Code, LineFoldingOnly));
};
// We want to make sure folding ranges are always available for all the open
// files, hence prefer runQuick to not wait for operations on other files.
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index b14391aab6680..6be0c930ded47 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -164,6 +164,9 @@ class ClangdServer {
/// Enable preview of FoldingRanges feature.
bool FoldingRanges = false;
+ // Whether the client supports folding only complete lines.
+ bool LineFoldingOnly = false;
+
FeatureModuleSet *FeatureModules = nullptr;
/// If true, use the dirty buffer contents when building Preambles.
bool UseDirtyHeaders = false;
@@ -429,6 +432,9 @@ class ClangdServer {
bool UseDirtyHeaders = false;
+ // Whether the client supports folding only complete lines.
+ bool LineFoldingOnly = false;
+
bool PreambleParseForwardingFunctions = false;
// GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 0109fa01e34e5..8b833c0f3f8b2 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -391,6 +391,10 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R,
}
}
}
+ if (auto *Folding = TextDocument->getObject("foldingRange")) {
+ if (auto LineFolding = Folding->getBoolean("lineFoldingOnly"))
+ R.LineFoldingOnly = *LineFolding;
+ }
if (auto *Rename = TextDocument->getObject("rename")) {
if (auto RenameSupport = Rename->getBoolean("prepareSupport"))
R.RenamePrepareSupport = *RenameSupport;
diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h
index 9a68a33cfb334..aa7c753a9f916 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -437,6 +437,12 @@ struct ClientCapabilities {
/// textDocument.signatureHelp
bool HasSignatureHelp = false;
+ /// Client signals that it only supports folding complete lines.
+ /// Client will ignore specified `startCharacter` and `endCharacter`
+ /// properties in a FoldingRange.
+ /// textDocument.foldingRange.lineFoldingOnly
+ bool LineFoldingOnly = false;
+
/// Client supports processing label offsets instead of a simple label string.
/// textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport
bool OffsetsInSignatureHelp = false;
diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp
index b82df8ebc2595..b00f9acf696c2 100644
--- a/clang-tools-extra/clangd/SemanticSelection.cpp
+++ b/clang-tools-extra/clangd/SemanticSelection.cpp
@@ -179,7 +179,7 @@ llvm::Expected<std::vector<FoldingRange>> getFoldingRanges(ParsedAST &AST) {
// statement bodies).
// Related issue: https://github.com/clangd/clangd/issues/310
llvm::Expected<std::vector<FoldingRange>>
-getFoldingRanges(const std::string &Code) {
+getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
auto OrigStream = pseudo::lex(Code, clang::pseudo::genericLangOpts());
auto DirectiveStructure = pseudo::DirectiveTree::parse(OrigStream);
@@ -192,15 +192,17 @@ getFoldingRanges(const std::string &Code) {
pseudo::pairBrackets(ParseableStream);
std::vector<FoldingRange> Result;
- auto ToFoldingRange = [](Position Start, Position End,
- llvm::StringLiteral Kind) {
+ auto AddFoldingRange = [&](Position Start, Position End,
+ llvm::StringLiteral Kind) {
+ if (Start.line >= End.line)
+ return;
FoldingRange FR;
FR.startLine = Start.line;
FR.startCharacter = Start.character;
FR.endLine = End.line;
FR.endCharacter = End.character;
FR.kind = Kind.str();
- return FR;
+ Result.push_back(FR);
};
auto OriginalToken = [&](const pseudo::Token &T) {
return OrigStream.tokens()[T.OriginalIndex];
@@ -211,8 +213,11 @@ getFoldingRanges(const std::string &Code) {
auto StartPosition = [&](const pseudo::Token &T) {
return offsetToPosition(Code, StartOffset(T));
};
+ auto EndOffset = [&](const pseudo::Token &T) {
+ return StartOffset(T) + OriginalToken(T).Length;
+ };
auto EndPosition = [&](const pseudo::Token &T) {
- return offsetToPosition(Code, StartOffset(T) + OriginalToken(T).Length);
+ return offsetToPosition(Code, EndOffset(T));
};
auto Tokens = ParseableStream.tokens();
// Brackets.
@@ -223,26 +228,43 @@ getFoldingRanges(const std::string &Code) {
if (Tok.Line < Paired->Line) {
Position Start = offsetToPosition(Code, 1 + StartOffset(Tok));
Position End = StartPosition(*Paired);
- Result.push_back(ToFoldingRange(Start, End, FoldingRange::REGION_KIND));
+ if (LineFoldingOnly)
+ End.line--;
+ AddFoldingRange(Start, End, FoldingRange::REGION_KIND);
}
}
}
+ auto IsBlockComment = [&](const pseudo::Token &T) {
+ assert(T.Kind == tok::comment);
+ return OriginalToken(T).Length >= 2 &&
+ Code.substr(StartOffset(T), 2) == "/*";
+ };
// Multi-line comments.
- for (const auto *T = Tokens.begin(); T != Tokens.end();) {
+ for (auto *T = Tokens.begin(); T != Tokens.end();) {
if (T->Kind != tok::comment) {
T++;
continue;
}
- Position Start = StartPosition(*T);
- Position LastCommentEnd = EndPosition(*T);
+ pseudo::Token *FirstComment = T;
+ // Show starting sentinals (// and /*) of the comment.
+ Position Start = offsetToPosition(Code, 2 + StartOffset(*FirstComment));
+ pseudo::Token *LastComment = T;
+ Position End = EndPosition(*T);
while (T != Tokens.end() && T->Kind == tok::comment &&
- StartPosition(*T).line <= LastCommentEnd.line + 1) {
- LastCommentEnd = EndPosition(*T);
+ StartPosition(*T).line <= End.line + 1) {
+ End = EndPosition(*T);
+ LastComment = T;
T++;
}
- if (Start.line < LastCommentEnd.line)
- Result.push_back(
- ToFoldingRange(Start, LastCommentEnd, FoldingRange::COMMENT_KIND));
+ if (IsBlockComment(*FirstComment)) {
+ if (LineFoldingOnly)
+ // Show last line of a block comment.
+ End.line--;
+ if (IsBlockComment(*LastComment))
+ // Show ending sentinal "*/" of the block comment.
+ End.character -= 2;
+ }
+ AddFoldingRange(Start, End, FoldingRange::COMMENT_KIND);
}
return Result;
}
diff --git a/clang-tools-extra/clangd/SemanticSelection.h b/clang-tools-extra/clangd/SemanticSelection.h
index 337d8d38a0e0d..dd9d3ea7e81d3 100644
--- a/clang-tools-extra/clangd/SemanticSelection.h
+++ b/clang-tools-extra/clangd/SemanticSelection.h
@@ -33,7 +33,7 @@ llvm::Expected<std::vector<FoldingRange>> getFoldingRanges(ParsedAST &AST);
/// Returns a list of ranges whose contents might be collapsible in an editor.
/// This version uses the pseudoparser which does not require the AST.
llvm::Expected<std::vector<FoldingRange>>
-getFoldingRanges(const std::string &Code);
+getFoldingRanges(const std::string &Code, bool LineFoldingOnly);
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
index de2960869b1e9..7faef6f95d8f9 100644
--- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
@@ -196,7 +196,7 @@ TEST(SemanticSelection, RunViaClangdServer) {
ElementsAre(SourceAnnotations.range("empty")));
}
-TEST(FoldingRanges, All) {
+TEST(FoldingRanges, ASTAll) {
const char *Tests[] = {
R"cpp(
#define FOO int foo() {\
@@ -265,7 +265,7 @@ TEST(FoldingRanges, All) {
}
}
-TEST(FoldingRangesPseudoParser, All) {
+TEST(FoldingRanges, PseudoParserWithoutLineFoldings) {
const char *Tests[] = {
R"cpp(
#define FOO int foo() {\
@@ -336,36 +336,123 @@ TEST(FoldingRangesPseudoParser, All) {
]]};
)cpp",
R"cpp(
- [[/* Multi
+ /*[[ Multi
* line
* comment
- */]]
+ ]]*/
)cpp",
R"cpp(
- [[// Comment
+ //[[ Comment
// 1]]
- [[// Comment
+ //[[ Comment
// 2]]
// No folding for single line comment.
- [[/* comment 3
- */]]
+ /*[[ comment 3
+ ]]*/
- [[/* comment 4
- */]]
+ /*[[ comment 4
+ ]]*/
+
+ /*[[ foo */
+ /* bar ]]*/
+
+ /*[[ foo */
+ // baz
+ /* bar ]]*/
+
+ /*[[ foo */
+ /* bar*/
+ // baz]]
+
+ //[[ foo
+ /* bar */]]
)cpp",
};
for (const char *Test : Tests) {
auto T = Annotations(Test);
- EXPECT_THAT(
- gatherFoldingRanges(llvm::cantFail(getFoldingRanges(T.code().str()))),
- UnorderedElementsAreArray(T.ranges()))
+ EXPECT_THAT(gatherFoldingRanges(llvm::cantFail(getFoldingRanges(
+ T.code().str(), /*LineFoldingsOnly=*/false))),
+ UnorderedElementsAreArray(T.ranges()))
<< Test;
}
}
+TEST(FoldingRanges, PseudoParserLineFoldingsOnly) {
+ const char *Tests[] = {
+ R"cpp(
+ void func(int a) {[[
+ a++;]]
+ }
+ )cpp",
+ R"cpp(
+ // Always exclude last line for brackets.
+ void func(int a) {[[
+ if(a == 1) {[[
+ a++;]]
+ } else if (a == 2){[[
+ a--;]]
+ } else { // No folding for 2 line bracketed ranges.
+ }]]
+ }
+ )cpp",
+ R"cpp(
+ /*[[ comment
+ * comment]]
+ */
+
+ /* No folding for this comment.
+ */
+
+ // No folding for this comment.
+
+ //[[ 2 single line comment.
+ // 2 single line comment.]]
+
+ //[[ >=2 line comments.
+ // >=2 line comments.
+ // >=2 line comments.]]
+
+ //[[ foo\
+ bar\
+ baz]]
+
+ /*[[ foo */
+ /* bar */]]
+ /* baz */
+
+ /*[[ foo */
+ /* bar]]
+ * This does not fold me */
+
+ //[[ foo
+ /* bar */]]
+ )cpp",
+ // FIXME: Support folding template arguments.
+ // R"cpp(
+ // template <[[typename foo, class bar]]> struct baz {};
+ // )cpp",
+
+ };
+ auto StripColumns = [](const std::vector<Range> &Ranges) {
+ std::vector<Range> Res;
+ for (Range R : Ranges) {
+ R.start.character = R.end.character = 0;
+ Res.push_back(R);
+ }
+ return Res;
+ };
+ for (const char *Test : Tests) {
+ auto T = Annotations(Test);
+ EXPECT_THAT(
+ StripColumns(gatherFoldingRanges(llvm::cantFail(
+ getFoldingRanges(T.code().str(), /*LineFoldingsOnly=*/true)))),
+ UnorderedElementsAreArray(StripColumns(T.ranges())))
+ << Test;
+ }
+}
} // namespace
} // namespace clangd
} // namespace clang
More information about the cfe-commits
mailing list