Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 78 additions & 3 deletions clang-tools-extra/clangd/SemanticSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
#include "Protocol.h"
#include "Selection.h"
#include "SourceCode.h"
#include "support/Bracket.h"
#include "support/DirectiveTree.h"
#include "support/Token.h"
#include "clang/AST/DeclBase.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Tooling/Syntax/BuildTree.h"
#include "clang/Tooling/Syntax/Nodes.h"
#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
Expand All @@ -22,9 +26,6 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
#include "support/Bracket.h"
#include "support/DirectiveTree.h"
#include "support/Token.h"
#include <optional>
#include <queue>
#include <vector>
Expand Down Expand Up @@ -163,6 +164,69 @@ llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST &AST, Position Pos) {
return std::move(Head);
}

class PragmaRegionFinder {
// Record the token range of a region:
//
// #pragma region name[[
// ...
// ]]#pragma endregion
std::vector<Token::Range> &Ranges;
const TokenStream &Code;
// Stack of starting token (the name of the region) indices for nested #pragma
// region.
std::vector<unsigned> Stack;

public:
PragmaRegionFinder(std::vector<Token::Range> &Ranges, const TokenStream &Code)
: Ranges(Ranges), Code(Code) {}

void walk(const DirectiveTree &T) {
for (const auto &C : T.Chunks)
std::visit(*this, C);
}

void operator()(const DirectiveTree::Code &C) {}

void operator()(const DirectiveTree::Directive &D) {
// Get the tokens that make up this directive.
auto Tokens = Code.tokens(D.Tokens);
if (Tokens.empty())
return;
const Token &HashToken = Tokens.front();
assert(HashToken.Kind == tok::hash);
const Token &Pragma = HashToken.nextNC();
if (Pragma.text() != "pragma")
return;
const Token &Value = Pragma.nextNC();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there can be a comment between pragma and region...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nextNC API will skip the comment.


// Handle "#pragma region name"
if (Value.text() == "region") {
// Find the last token at the same line.
const Token *T = &Value.next();
while (T < Tokens.end() && T->Line == Pragma.Line)
T = &T->next();
--T;
Stack.push_back(T->OriginalIndex);
return;
}

// Handle "#pragma endregion"
if (Value.text() == "endregion") {
if (Stack.empty())
return; // unmatched end region; ignore.

unsigned StartIdx = Stack.back();
Stack.pop_back();
Ranges.push_back(Token::Range{StartIdx, HashToken.OriginalIndex});
}
}

void operator()(const DirectiveTree::Conditional &C) {
for (const auto &[_, SubTree] : C.Branches)
walk(SubTree);
}
};

// FIXME(kirillbobyrev): Collect comments, PP conditional regions, includes and
// other code regions (e.g. public/private/protected sections of classes,
// control flow statement bodies).
Expand Down Expand Up @@ -286,6 +350,17 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
}
AddFoldingRange(Start, End, FoldingRange::COMMENT_KIND);
}

// #pragma region
std::vector<Token::Range> Ranges;
PragmaRegionFinder(Ranges, OrigStream).walk(DirectiveStructure);
auto Ts = OrigStream.tokens();
for (const auto &R : Ranges) {
auto End = StartPosition(Ts[R.End]);
if (LineFoldingOnly)
End.line--;
AddFoldingRange(EndPosition(Ts[R.Begin]), End, FoldingRange::REGION_KIND);
}
return Result;
}

Expand Down
22 changes: 22 additions & 0 deletions clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,22 @@ TEST(FoldingRanges, PseudoParserWithoutLineFoldings) {
Variable = 3;
#
)cpp",
R"cpp(
#pragma region R1[[

#pragma region R2[[
constexpr int a = 2;
]]#pragma endregion

]]#pragma endregion
)cpp",
R"cpp(
#pragma region[[
]]#pragma endregion

#pragma /*comment1*/ region /*comment2*/name[[
]]#pragma endregion
)cpp",
};
for (const char *Test : Tests) {
auto T = Annotations(Test);
Expand Down Expand Up @@ -470,6 +486,12 @@ TEST(FoldingRanges, PseudoParserLineFoldingsOnly) {
//[[ foo
/* bar */]]
)cpp",
R"cpp(
#pragma region abc[[
constexpr int a = 2;
]]
#pragma endregion
)cpp",
// FIXME: Support folding template arguments.
// R"cpp(
// template <[[typename foo, class bar]]> struct baz {};
Expand Down