|
11 | 11 | #include "Protocol.h" |
12 | 12 | #include "Selection.h" |
13 | 13 | #include "SourceCode.h" |
| 14 | +#include "support/Bracket.h" |
| 15 | +#include "support/DirectiveTree.h" |
| 16 | +#include "support/Token.h" |
14 | 17 | #include "clang/AST/DeclBase.h" |
15 | 18 | #include "clang/Basic/SourceLocation.h" |
16 | 19 | #include "clang/Basic/SourceManager.h" |
| 20 | +#include "clang/Basic/TokenKinds.h" |
17 | 21 | #include "clang/Tooling/Syntax/BuildTree.h" |
18 | 22 | #include "clang/Tooling/Syntax/Nodes.h" |
19 | 23 | #include "clang/Tooling/Syntax/TokenBufferTokenManager.h" |
|
22 | 26 | #include "llvm/ADT/StringRef.h" |
23 | 27 | #include "llvm/Support/Casting.h" |
24 | 28 | #include "llvm/Support/Error.h" |
25 | | -#include "support/Bracket.h" |
26 | | -#include "support/DirectiveTree.h" |
27 | | -#include "support/Token.h" |
28 | 29 | #include <optional> |
29 | 30 | #include <queue> |
30 | 31 | #include <vector> |
@@ -163,6 +164,69 @@ llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST &AST, Position Pos) { |
163 | 164 | return std::move(Head); |
164 | 165 | } |
165 | 166 |
|
| 167 | +class PragmaRegionFinder { |
| 168 | + // Record the token range of a region: |
| 169 | + // |
| 170 | + // #pragma region name[[ |
| 171 | + // ... |
| 172 | + // ]]#pragma endregion |
| 173 | + std::vector<Token::Range> &Ranges; |
| 174 | + const TokenStream &Code; |
| 175 | + // Stack of starting token (the name of the region) indices for nested #pragma |
| 176 | + // region. |
| 177 | + std::vector<unsigned> Stack; |
| 178 | + |
| 179 | +public: |
| 180 | + PragmaRegionFinder(std::vector<Token::Range> &Ranges, const TokenStream &Code) |
| 181 | + : Ranges(Ranges), Code(Code) {} |
| 182 | + |
| 183 | + void walk(const DirectiveTree &T) { |
| 184 | + for (const auto &C : T.Chunks) |
| 185 | + std::visit(*this, C); |
| 186 | + } |
| 187 | + |
| 188 | + void operator()(const DirectiveTree::Code &C) {} |
| 189 | + |
| 190 | + void operator()(const DirectiveTree::Directive &D) { |
| 191 | + // Get the tokens that make up this directive. |
| 192 | + auto Tokens = Code.tokens(D.Tokens); |
| 193 | + if (Tokens.empty()) |
| 194 | + return; |
| 195 | + const Token &HashToken = Tokens.front(); |
| 196 | + assert(HashToken.Kind == tok::hash); |
| 197 | + const Token &Pragma = HashToken.nextNC(); |
| 198 | + if (Pragma.text() != "pragma") |
| 199 | + return; |
| 200 | + const Token &Value = Pragma.nextNC(); |
| 201 | + |
| 202 | + // Handle "#pragma region name" |
| 203 | + if (Value.text() == "region") { |
| 204 | + // Find the last token at the same line. |
| 205 | + const Token *T = &Value.next(); |
| 206 | + while (T < Tokens.end() && T->Line == Pragma.Line) |
| 207 | + T = &T->next(); |
| 208 | + --T; |
| 209 | + Stack.push_back(T->OriginalIndex); |
| 210 | + return; |
| 211 | + } |
| 212 | + |
| 213 | + // Handle "#pragma endregion" |
| 214 | + if (Value.text() == "endregion") { |
| 215 | + if (Stack.empty()) |
| 216 | + return; // unmatched end region; ignore. |
| 217 | + |
| 218 | + unsigned StartIdx = Stack.back(); |
| 219 | + Stack.pop_back(); |
| 220 | + Ranges.push_back(Token::Range{StartIdx, HashToken.OriginalIndex}); |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + void operator()(const DirectiveTree::Conditional &C) { |
| 225 | + for (const auto &[_, SubTree] : C.Branches) |
| 226 | + walk(SubTree); |
| 227 | + } |
| 228 | +}; |
| 229 | + |
166 | 230 | // FIXME(kirillbobyrev): Collect comments, PP conditional regions, includes and |
167 | 231 | // other code regions (e.g. public/private/protected sections of classes, |
168 | 232 | // control flow statement bodies). |
@@ -286,6 +350,17 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) { |
286 | 350 | } |
287 | 351 | AddFoldingRange(Start, End, FoldingRange::COMMENT_KIND); |
288 | 352 | } |
| 353 | + |
| 354 | + // #pragma region |
| 355 | + std::vector<Token::Range> Ranges; |
| 356 | + PragmaRegionFinder(Ranges, OrigStream).walk(DirectiveStructure); |
| 357 | + auto Ts = OrigStream.tokens(); |
| 358 | + for (const auto &R : Ranges) { |
| 359 | + auto End = StartPosition(Ts[R.End]); |
| 360 | + if (LineFoldingOnly) |
| 361 | + End.line--; |
| 362 | + AddFoldingRange(EndPosition(Ts[R.Begin]), End, FoldingRange::REGION_KIND); |
| 363 | + } |
289 | 364 | return Result; |
290 | 365 | } |
291 | 366 |
|
|
0 commit comments