Skip to content

Commit 4a4bbe8

Browse files
committed
[syntax-map] Fix array-of-object-literal syntax map, argument label keywords
Argument labels are allowed to use keywords, in which case we want to treat them as identifiers in the syntax map (except for '_'). This commit moves calculation of that into the original lexing instead of in the model walker, which makes it much more robust, since the model walker was only guessing about what was next on the the TokenNodes list. This fixes a bug where arrays of object literals would only have the first object correct (the following ones were identifiers), as well as some incorrect cases where we treated keywords as identifiers. rdar://problem/27726422
1 parent 223bd54 commit 4a4bbe8

File tree

3 files changed

+43
-15
lines changed

3 files changed

+43
-15
lines changed

lib/IDE/SyntaxModel.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,23 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
9494
}
9595

9696
switch(Tok.getKind()) {
97-
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
97+
#define KEYWORD(X) case tok::kw_##X:
9898
#include "swift/Parse/Tokens.def"
9999
#undef KEYWORD
100+
if (Tok.getKind() != tok::kw__ &&
101+
0 < I && I < Tokens.size() - 1 &&
102+
(Tokens[I-1].getKind() == tok::l_paren ||
103+
Tokens[I-1].getKind() == tok::comma) &&
104+
(Tokens[I+1].getKind() == tok::colon ||
105+
Tokens[I+1].getKind() == tok::identifier ||
106+
Tokens[I+1].isKeyword())) {
107+
// Keywords are allowed as argument labels and should be treated as
108+
// identifiers. The exception is '_' which is not a name.
109+
Kind = SyntaxNodeKind::Identifier;
110+
} else {
111+
Kind = SyntaxNodeKind::Keyword;
112+
}
113+
break;
100114

101115
#define POUND_OLD_OBJECT_LITERAL(Name, NewName, OldArg, NewArg) \
102116
case tok::pound_##Name:
@@ -453,9 +467,6 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
453467
E->getEndLoc()));
454468
passTokenNodesUntil(NR.getStart(),
455469
PassNodesBehavior::ExcludeNodeAtLocation);
456-
if (!TokenNodes.empty())
457-
const_cast<SyntaxNode&>(TokenNodes.front()).Kind = SyntaxNodeKind::
458-
Identifier;
459470
}
460471
else
461472
SN.Range = SN.BodyRange;
@@ -524,13 +535,8 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
524535
} else if (auto *Tup = dyn_cast<TupleExpr>(E)) {
525536
for (unsigned I = 0; I < Tup->getNumElements(); ++ I) {
526537
SourceLoc NameLoc = Tup->getElementNameLoc(I);
527-
if (NameLoc.isValid()) {
538+
if (NameLoc.isValid())
528539
passTokenNodesUntil(NameLoc, PassNodesBehavior::ExcludeNodeAtLocation);
529-
if (!TokenNodes.empty()) {
530-
const_cast<SyntaxNode&>(TokenNodes.front()).Kind = SyntaxNodeKind::
531-
Identifier;
532-
}
533-
}
534540
}
535541
}
536542

@@ -860,8 +866,6 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) {
860866
SourceLoc ArgStart = PD->getSourceRange().Start;
861867
SN.NameRange = CharSourceRange(ArgStart, PD->getArgumentName().getLength());
862868
passTokenNodesUntil(ArgStart, PassNodesBehavior::ExcludeNodeAtLocation);
863-
const_cast<SyntaxNode&>(TokenNodes.front()).Kind = SyntaxNodeKind::
864-
Identifier;
865869
}
866870
SN.Range = charSourceRangeFromSourceRange(SM, PD->getSourceRange());
867871
SN.Attrs = PD->getAttrs();

test/IDE/coloring.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ func test3(o: AnyObject) {
273273
let x = o as! MyCls
274274
}
275275

276-
// CHECK: <kw>func</kw> test4(<kw>inout</kw> a: <type>Int</type>) {{{$}}
276+
// CHECK: <kw>func</kw> test4(inout a: <type>Int</type>) {{{$}}
277277
func test4(inout a: Int) {
278278
// CHECK: <kw>if</kw> <kw>#available</kw> (<kw>OSX</kw> >= <float>10.10</float>, <kw>iOS</kw> >= <float>8.01</float>) {<kw>let</kw> OSX = <str>"iOS"</str>}}{{$}}
279279
if #available (OSX >= 10.10, iOS >= 8.01) {let OSX = "iOS"}}
@@ -501,20 +501,44 @@ let file = #fileLiteral(resourceName: "cloud.png")
501501
let black = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
502502
// CHECK: <kw>let</kw> black = <object-literal>#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)</object-literal>
503503

504+
let rgb = [#colorLiteral(red: 1, green: 0, blue: 0, alpha: 1),
505+
#colorLiteral(red: 0, green: 1, blue: 0, alpha: 1),
506+
#colorLiteral(red: 0, green: 0, blue: 1, alpha: 1)]
507+
// CHECK: <kw>let</kw> rgb = [<object-literal>#colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)</object-literal>,
508+
// CHECK: <object-literal>#colorLiteral(red: 0, green: 1, blue: 0, alpha: 1)</object-literal>,
509+
// CHECK: <object-literal>#colorLiteral(red: 0, green: 0, blue: 1, alpha: 1)</object-literal>]
510+
504511
"--\"\(x) --"
505512
// CHECK: <str>"--\"</str>\<anchor>(</anchor>x<anchor>)</anchor><str> --"</str>
506513

507514
func keywordAsLabel1(in: Int) {}
508515
// CHECK: <kw>func</kw> keywordAsLabel1(in: <type>Int</type>) {}
509516
func keywordAsLabel2(for: Int) {}
510517
// CHECK: <kw>func</kw> keywordAsLabel2(for: <type>Int</type>) {}
518+
func keywordAsLabel3(if: Int, for: Int) {}
519+
// CHECK: <kw>func</kw> keywordAsLabel3(if: <type>Int</type>, for: <type>Int</type>) {}
520+
func keywordAsLabel4(_: Int) {}
521+
// CHECK: <kw>func</kw> keywordAsLabel4(<kw>_</kw>: <type>Int</type>) {}
522+
func keywordAsLabel5(_: Int, for: Int) {}
523+
// CHECK: <kw>func</kw> keywordAsLabel5(<kw>_</kw>: <type>Int</type>, for: <type>Int</type>) {}
524+
func keywordAsLabel6(if let: Int) {}
525+
// CHECK: <kw>func</kw> keywordAsLabel6(if <kw>let</kw>: <type>Int</type>) {}
511526

512527
func foo1() {
513528
// CHECK: <kw>func</kw> foo1() {
514529
keywordAsLabel1(in: 1)
515530
// CHECK: keywordAsLabel1(in: <int>1</int>)
516531
keywordAsLabel2(for: 1)
517532
// CHECK: keywordAsLabel2(for: <int>1</int>)
533+
keywordAsLabel3(if: 1, for: 2)
534+
// CHECK: keywordAsLabel3(if: <int>1</int>, for: <int>2</int>)
535+
keywordAsLabel5(1, for: 2)
536+
// CHECK: keywordAsLabel5(<int>1</int>, for: <int>2</int>)
537+
538+
_ = (if: 0, for: 2)
539+
// CHECK: <kw>_</kw> = (if: <int>0</int>, for: <int>2</int>)
540+
_ = (_: 0, _: 2)
541+
// CHECK: <kw>_</kw> = (<kw>_</kw>: <int>0</int>, <kw>_</kw>: <int>2</int>)
518542
}
519543

520544
// Keep this as the last test

test/SourceKit/SyntaxMapData/syntaxmap-object-literals.swift.response

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
key.length: 40
3030
},
3131
{
32-
key.kind: source.lang.swift.syntaxtype.identifier,
32+
key.kind: source.lang.swift.syntaxtype.keyword,
3333
key.offset: 165,
3434
key.length: 3
3535
},
@@ -44,7 +44,7 @@
4444
key.length: 50
4545
},
4646
{
47-
key.kind: source.lang.swift.syntaxtype.identifier,
47+
key.kind: source.lang.swift.syntaxtype.keyword,
4848
key.offset: 228,
4949
key.length: 3
5050
},

0 commit comments

Comments
 (0)