diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp --- a/clang-tools-extra/clangd/SemanticSelection.cpp +++ b/clang-tools-extra/clangd/SemanticSelection.cpp @@ -179,10 +179,10 @@ // Related issue: https://github.com/clangd/clangd/issues/310 llvm::Expected> getFoldingRanges(const std::string &Code) { - auto OrigStream = clang::pseudo::lex(Code, clang::pseudo::genericLangOpts()); + auto OrigStream = pseudo::lex(Code, clang::pseudo::genericLangOpts()); - auto DirectiveStructure = clang::pseudo::DirectiveTree::parse(OrigStream); - clang::pseudo::chooseConditionalBranches(DirectiveStructure, OrigStream); + auto DirectiveStructure = pseudo::DirectiveTree::parse(OrigStream); + pseudo::chooseConditionalBranches(DirectiveStructure, OrigStream); // FIXME: Provide ranges in the disabled-PP regions as well. auto Preprocessed = DirectiveStructure.stripDirectives(OrigStream); @@ -191,26 +191,49 @@ pseudo::pairBrackets(ParseableStream); std::vector Result; - for (const auto &Tok : ParseableStream.tokens()) { + auto ToFoldingRange = [](Position Start, Position End, std::string Kind) { + FoldingRange FR; + FR.startLine = Start.line; + FR.startCharacter = Start.character; + FR.endLine = End.line; + FR.endCharacter = End.character; + FR.kind = Kind; + return FR; + }; + auto OriginalToken = [&](const pseudo::Token &T) { + return OrigStream.tokens()[T.OriginalIndex]; + }; + auto StartOffset = [&](const pseudo::Token &T) { + return OriginalToken(T).text().data() - Code.data(); + }; + auto Tokens = ParseableStream.tokens(); + // Brackets. + for (const auto &Tok : Tokens) { if (auto *Paired = Tok.pair()) { // Process only token at the start of the range. Avoid ranges on a single // line. if (Tok.Line < Paired->Line) { - Position Start = offsetToPosition( - Code, - OrigStream.tokens()[Tok.OriginalIndex].text().data() - Code.data()); - Position End = offsetToPosition( - Code, OrigStream.tokens()[Paired->OriginalIndex].text().data() - - Code.data()); - FoldingRange FR; - FR.startLine = Start.line; - FR.startCharacter = Start.character + 1; - FR.endLine = End.line; - FR.endCharacter = End.character; - Result.push_back(FR); + Position Start = offsetToPosition(Code, 1 + StartOffset(Tok)); + Position End = offsetToPosition(Code, StartOffset(*Paired)); + Result.push_back(ToFoldingRange(Start, End, "region")); } } } + // Multi-line comments. + for (const auto *T = Tokens.begin(); T != Tokens.end();) { + if (T->Kind != tok::comment) { + T++; + continue; + } + Position Start = offsetToPosition(Code, StartOffset(*T)); + Position End; + while (T->Kind == tok::comment && T != Tokens.end()) { + End = offsetToPosition(Code, StartOffset(*T) + OriginalToken(*T).Length); + T++; + } + if (Start.line < End.line) + Result.push_back(ToFoldingRange(Start, End, "comment")); + } return Result; } diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp @@ -335,6 +335,26 @@ ]]} \ ]]}; )cpp", + R"cpp( + int a; + [[/* Multi + line + comment */]] + + int b; + [[/* Multi + * line + * comment + */]] + + int c; + [[// A comment + // expanding more than + + // one + + // line.]] + )cpp", }; for (const char *Test : Tests) { auto T = Annotations(Test);