@@ -29,14 +29,35 @@ struct SiblingAlignInfo {
29
29
};
30
30
31
31
struct TokenInfo {
32
- const Token *StartOfLineTarget;
33
- const Token *StartOfLineBeforeTarget;
34
- TokenInfo (const Token *StartOfLineTarget,
35
- const Token *StartOfLineBeforeTarget) :
36
- StartOfLineTarget (StartOfLineTarget),
37
- StartOfLineBeforeTarget (StartOfLineBeforeTarget) {}
38
- TokenInfo () : TokenInfo(nullptr , nullptr ) {}
39
- operator bool () { return StartOfLineTarget && StartOfLineBeforeTarget; }
32
+ // The tokens appearing at the start of lines, from the first line to the
33
+ // line under indentation.
34
+ std::vector<const Token*> LineStarts;
35
+ const Token *getLineStarter (unsigned idx = 0 ) const {
36
+ auto it = LineStarts.rbegin () + idx;
37
+ return it < LineStarts.rend () ? *it : nullptr ;
38
+ }
39
+ operator bool () { return LineStarts.size () > 1 ; }
40
+ bool isRBraceDotsPattern () const {
41
+ for (auto It = LineStarts.rbegin (), end = LineStarts.rend ();
42
+ It + 1 < end; ++It) {
43
+ auto * CurrentLine = *It;
44
+ auto * PreviousLine = *(It + 1 );
45
+ if (CurrentLine->getKind () == tok::period &&
46
+ PreviousLine->getKind () == tok::period) {
47
+ // If the previous line starts with dot too, move further up.
48
+ continue ;
49
+ } else if (CurrentLine->getKind () == tok::period &&
50
+ PreviousLine->getKind () == tok::r_brace &&
51
+ PreviousLine + 1 == CurrentLine) {
52
+ // Check if the previous line starts with '}' and the period of the
53
+ // current line is immediately after the '}'
54
+ return true ;
55
+ } else {
56
+ return false ;
57
+ }
58
+ }
59
+ return false ;
60
+ }
40
61
};
41
62
42
63
using StringBuilder = llvm::SmallString<64 >;
@@ -285,17 +306,16 @@ class FormatContext {
285
306
return false ;
286
307
287
308
if (TInfo) {
288
- if (TInfo.StartOfLineTarget ->getKind () == tok::l_brace &&
289
- isKeywordPossibleDeclStart (*TInfo.StartOfLineBeforeTarget ) &&
290
- TInfo.StartOfLineBeforeTarget ->isKeyword ())
309
+ if (TInfo.getLineStarter () ->getKind () == tok::l_brace &&
310
+ isKeywordPossibleDeclStart (*TInfo.getLineStarter ( 1 ) ) &&
311
+ TInfo.getLineStarter ( 1 ) ->isKeyword ())
291
312
return false ;
292
313
// VStack {
293
314
// ...
294
315
// }
295
316
// .onAppear { <---- No indentation here.
296
- if (TInfo.StartOfLineTarget ->getKind () == tok::period &&
297
- TInfo.StartOfLineBeforeTarget ->getKind () == tok::r_brace &&
298
- TInfo.StartOfLineBeforeTarget + 1 == TInfo.StartOfLineTarget ) {
317
+ // .onAppear1 { <---- No indentation here.
318
+ if (TInfo.isRBraceDotsPattern ()) {
299
319
return false ;
300
320
}
301
321
}
@@ -365,7 +385,7 @@ class FormatContext {
365
385
SignatureEnd = SD->getSignatureSourceRange ().End ;
366
386
}
367
387
if (SignatureEnd.isValid () && TInfo &&
368
- TInfo.StartOfLineTarget ->getLoc () == SignatureEnd) {
388
+ TInfo.getLineStarter () ->getLoc () == SignatureEnd) {
369
389
return false ;
370
390
}
371
391
@@ -862,7 +882,7 @@ class CodeFormatter {
862
882
863
883
// If having sibling locs to align with, respect siblings.
864
884
auto isClosingSquare =
865
- ToInfo && ToInfo.StartOfLineTarget ->getKind () == tok::r_square;
885
+ ToInfo && ToInfo.getLineStarter () ->getKind () == tok::r_square;
866
886
if (!isClosingSquare && FC.HasSibling ()) {
867
887
StringRef Line = swift::ide::getTextForLine (LineIndex, Text, /* Trim*/ true );
868
888
StringBuilder Builder;
@@ -940,33 +960,37 @@ class TokenInfoCollector {
940
960
SourceManager &SM;
941
961
ArrayRef<Token> Tokens;
942
962
unsigned Line;
943
-
944
- struct Comparator {
945
- SourceManager &SM;
946
- Comparator (SourceManager &SM) : SM(SM) {}
947
- bool operator ()(const Token &T, unsigned Line) const {
948
- return SM.getLineNumber (T.getLoc ()) < Line;
949
- }
950
- bool operator ()(unsigned Line, const Token &T) const {
951
- return Line < SM.getLineNumber (T.getLoc ());
952
- }
953
- };
954
-
963
+ // The location of the end of the line under indentation, we don't need to
964
+ // collect tokens after this location.
965
+ SourceLoc EndLimit;
955
966
public:
956
- TokenInfoCollector (SourceManager &SM, ArrayRef<Token> Tokens,
957
- unsigned Line) : SM(SM), Tokens(Tokens), Line(Line) {}
967
+ TokenInfoCollector (SourceManager &SM,
968
+ unsigned BufferId,
969
+ ArrayRef<Token> Tokens, unsigned Line):
970
+ SM (SM), Tokens(Tokens), Line(Line) {
971
+ if (auto Offset = SM.resolveOffsetForEndOfLine (BufferId, Line)) {
972
+ EndLimit = SM.getLocForOffset (BufferId, *Offset);
973
+ }
974
+ }
958
975
959
976
TokenInfo collect () {
960
- if (Line == 0 )
977
+ if (EndLimit. isInvalid ()) {
961
978
return TokenInfo ();
962
- Comparator Comp (SM);
963
- auto LineMatch = [this ] (const Token* T, unsigned Line) {
964
- return T != Tokens.end () && SM.getLineNumber (T->getLoc ()) == Line;
965
- };
966
- auto TargetIt = std::lower_bound (Tokens.begin (), Tokens.end (), Line, Comp);
967
- auto LineBefore = std::lower_bound (Tokens.begin (), TargetIt, Line - 1 , Comp);
968
- if (LineMatch (TargetIt, Line) && LineMatch (LineBefore, Line - 1 ))
969
- return TokenInfo (TargetIt, LineBefore);
979
+ }
980
+ TokenInfo Result;
981
+ for (auto &T: Tokens) {
982
+ if (!T.isAtStartOfLine ())
983
+ continue ;
984
+ if (SM.isBeforeInBuffer (EndLimit, T.getLoc ())) {
985
+ if (!Result.LineStarts .empty ()) {
986
+ if (SM.getLineNumber (Result.getLineStarter ()->getLoc ()) == Line) {
987
+ return Result;
988
+ }
989
+ }
990
+ return TokenInfo ();
991
+ }
992
+ Result.LineStarts .push_back (&T);
993
+ }
970
994
return TokenInfo ();
971
995
}
972
996
};
@@ -1051,7 +1075,8 @@ std::pair<LineRange, std::string> swift::ide::reformat(LineRange Range,
1051
1075
FormatContext FC = walker.walkToLocation (Loc);
1052
1076
CodeFormatter CF (Options);
1053
1077
unsigned Line = Range.startLine ();
1054
- return CF.indent (Line, FC, Text, TokenInfoCollector (SM, walker.getTokens (),
1078
+ return CF.indent (Line, FC, Text, TokenInfoCollector (SM, SourceBufferID,
1079
+ walker.getTokens (),
1055
1080
Line).collect ());
1056
1081
}
1057
1082
0 commit comments