Skip to content

Commit 2d22a37

Browse files
authored
Merge pull request #24986 from nkcsgexi/object-literal-syntax
SourceKit/SyntaxMap: properly handle object literal syntax for highlighting
2 parents 6a204b7 + d3a192f commit 2d22a37

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)