Skip to content

Commit d3a192f

Browse files
committed
SourceKit/SyntaxMap: properly handle object literal syntax for highlighting
We should use parser to figure out the end position of object literal expression instead of scanning through token stream, which crashes sourcekitd when the syntax is invalid. Fixing: rdar://48390913
1 parent ad79bba commit d3a192f

File tree

2 files changed

+29
-16
lines changed

2 files changed

+29
-16
lines changed

lib/IDE/SyntaxModel.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
5656
std::vector<SyntaxNode> Nodes;
5757
SourceLoc AttrLoc;
5858
SourceLoc UnaryMinusLoc;
59-
auto LiteralStartLoc = Optional<SourceLoc>();
6059
for (unsigned I = 0, E = Tokens.size(); I != E; ++I) {
6160
auto &Tok = Tokens[I];
6261
// Ignore empty string literals between interpolations, e.g. "\(1)\(2)"
@@ -85,16 +84,6 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
8584
Loc = Tok.getLoc();
8685
Length = Tok.getLength();
8786

88-
if (LiteralStartLoc.hasValue() && Length.hasValue()) {
89-
if (Tok.getKind() != tok::r_paren)
90-
continue;
91-
Kind = SyntaxNodeKind::ObjectLiteral;
92-
Nodes.emplace_back(Kind, CharSourceRange(SM, LiteralStartLoc.getValue(),
93-
Tok.getRange().getEnd()));
94-
LiteralStartLoc = Optional<SourceLoc>();
95-
continue;
96-
}
97-
9887
switch(Tok.getKind()) {
9988
#define KEYWORD(X) case tok::kw_##X:
10089
#include "swift/Syntax/TokenKinds.def"
@@ -105,8 +94,8 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
10594

10695
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) case tok::pound_##Name:
10796
#include "swift/Syntax/TokenKinds.def"
108-
LiteralStartLoc = Loc;
109-
continue;
97+
Kind = SyntaxNodeKind::Keyword;
98+
break;
11099

111100
#define POUND_COND_DIRECTIVE_KEYWORD(Name) case tok::pound_##Name:
112101
#include "swift/Syntax/TokenKinds.def"
@@ -260,6 +249,9 @@ class ModelASTWalker : public ASTWalker {
260249
Optional<SyntaxNode> parseFieldNode(StringRef Text, StringRef OrigText,
261250
SourceLoc OrigLoc);
262251
llvm::DenseSet<ASTNode> VisitedNodesInsideIfConfig;
252+
/// When non-zero, we should avoid passing tokens as syntax nodes since a parent of several tokens
253+
/// is considered as one, e.g. object literal expression.
254+
uint8_t AvoidPassingSyntaxToken = 0;
263255

264256
public:
265257
SyntaxModelWalker &Walker;
@@ -494,8 +486,9 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
494486
SN.NameRange = CharSourceRange(SM, NRStart, NREnd);
495487
SN.BodyRange =
496488
innerCharSourceRangeFromSourceRange(SM, ObjectE->getSourceRange());
489+
// Consider the object literal as a single syntax token for highlighting.
490+
passNonTokenNode({SyntaxNodeKind::ObjectLiteral, SN.Range});
497491
pushStructureNode(SN, E);
498-
499492
} else if (auto *ArrayE = dyn_cast<ArrayExpr>(E)) {
500493
SyntaxStructureNode SN;
501494
SN.Kind = SyntaxStructureKind::ArrayExpression;
@@ -1152,8 +1145,10 @@ bool ModelASTWalker::passTokenNodesUntil(SourceLoc Loc,
11521145
}
11531146
break;
11541147
}
1155-
if (!passNode(TokenNodes[I]))
1156-
return false;
1148+
if (!AvoidPassingSyntaxToken) {
1149+
if (!passNode(TokenNodes[I]))
1150+
return false;
1151+
}
11571152
}
11581153

11591154
TokenNodes = TokenNodes.slice(I);
@@ -1200,9 +1195,15 @@ bool ModelASTWalker::passNode(const SyntaxNode &Node) {
12001195
return Walker.walkToNodePost(Node);
12011196
}
12021197

1198+
static bool shouldAvoidPssingSyntaxToken(const SyntaxStructureNode &Node) {
1199+
return Node.Kind == SyntaxStructureKind::ObjectLiteralExpression;
1200+
}
1201+
12031202
bool ModelASTWalker::pushStructureNode(const SyntaxStructureNode &Node,
12041203
const ASTNodeType& ASTNode) {
12051204
SubStructureStack.emplace_back(Node, ASTNode);
1205+
if (shouldAvoidPssingSyntaxToken(Node))
1206+
AvoidPassingSyntaxToken ++;
12061207

12071208
if (!passTokenNodesUntil(Node.Range.getStart(), ExcludeNodeAtLocation))
12081209
return false;
@@ -1215,6 +1216,12 @@ bool ModelASTWalker::pushStructureNode(const SyntaxStructureNode &Node,
12151216
bool ModelASTWalker::popStructureNode() {
12161217
assert(!SubStructureStack.empty());
12171218
SyntaxStructureNode Node = SubStructureStack.back().StructureNode;
1219+
SWIFT_DEFER {
1220+
if (shouldAvoidPssingSyntaxToken(Node)) {
1221+
assert(AvoidPassingSyntaxToken);
1222+
AvoidPassingSyntaxToken --;
1223+
}
1224+
};
12181225
SubStructureStack.pop_back();
12191226

12201227
// VarDecls are popped before we see their TypeRepr, so if we pass the token

test/IDE/coloring.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ func bar(x: Int) -> (Int, Float) {
262262
foo(Float())
263263
}
264264

265+
// CHECK: <object-literal>#colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)</object-literal>
266+
#colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
267+
265268
class GenC<T1,T2> {}
266269

267270
func test() {
@@ -277,6 +280,9 @@ func test2(x: Int) {
277280
"\(x)"
278281
}
279282

283+
// CHECK: <kw>#colorLiteral</kw>
284+
#colorLiteral
285+
280286
// CHECK: <kw>class</kw> Observers {
281287
class Observers {
282288
// CHECK: <kw>var</kw> p1 : <type>Int</type> {

0 commit comments

Comments
 (0)