Skip to content

Commit 947c6c9

Browse files
author
Nathan Hawes
authored
Merge pull request #29769 from nathawes/fix-syntax-model-assertion-failures
[SourceKit] Fix SyntaxModel assertion failure due to consuming tokens twice or out of order
2 parents e467514 + 5e1985c commit 947c6c9

File tree

2 files changed

+60
-12
lines changed

2 files changed

+60
-12
lines changed

lib/IDE/SyntaxModel.cpp

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -670,8 +670,13 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
670670
// from the `VarDecl` and the `PatternBindingDecl` entries.
671671
// We take over visitation here to avoid walking the `PatternBindingDecl` ones.
672672
for (auto c : CLE->getCaptureList()) {
673-
if (auto *VD = c.Var)
673+
if (auto *VD = c.Var) {
674+
// We're skipping over the PatternBindingDecl so we need to handle the
675+
// the VarDecl's attributes that we'd normally process visiting the PBD.
676+
if (!handleAttrs(VD->getAttrs()))
677+
return { false, nullptr };
674678
VD->walk(*this);
679+
}
675680
}
676681
if (auto *CE = CLE->getClosureBody())
677682
CE->walk(*this);
@@ -862,8 +867,14 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) {
862867
if (D->isImplicit())
863868
return false;
864869

865-
if (!handleAttrs(D->getAttrs()))
866-
return false;
870+
// The attributes of EnumElementDecls and VarDecls are handled when visiting
871+
// their parent EnumCaseDecl/PatternBindingDecl (which the attributes are
872+
// attached to syntactically).
873+
if (!isa<EnumElementDecl>(D) &&
874+
!(isa<VarDecl>(D) && cast<VarDecl>(D)->getParentPatternBinding())) {
875+
if (!handleAttrs(D->getAttrs()))
876+
return false;
877+
}
867878

868879
if (isa<AccessorDecl>(D)) {
869880
// Don't push structure nodes for accessors.
@@ -948,6 +959,21 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) {
948959
SN.TypeRange = charSourceRangeFromSourceRange(SM,
949960
PD->getTypeSourceRangeForDiagnostics());
950961
pushStructureNode(SN, PD);
962+
} else if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
963+
// Process the attributes of one of the contained VarDecls. Attributes that
964+
// are syntactically attached to the PatternBindingDecl end up on the
965+
// contained VarDecls.
966+
VarDecl *Contained = nullptr;
967+
for (auto idx : range(PBD->getNumPatternEntries())) {
968+
PBD->getPattern(idx)->forEachVariable([&](VarDecl *VD) -> void {
969+
Contained = VD;
970+
});
971+
if (Contained) {
972+
if (!handleAttrs(Contained->getAttrs()))
973+
return false;
974+
break;
975+
}
976+
}
951977
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
952978
const DeclContext *DC = VD->getDeclContext();
953979
SyntaxStructureNode SN;
@@ -1012,15 +1038,9 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) {
10121038

10131039
// We need to handle the special case where attributes semantically
10141040
// attach to enum element decls while syntactically locate before enum case decl.
1015-
for (auto *EnumElemD : EnumCaseD->getElements()) {
1016-
for (auto *Att : EnumElemD->getAttrs()) {
1017-
if (Att->isDeclModifier() &&
1018-
SM.isBeforeInBuffer(Att->getLocation(), D->getSourceRange().Start)) {
1019-
passNonTokenNode({SyntaxNodeKind::AttributeBuiltin,
1020-
charSourceRangeFromSourceRange(SM,
1021-
Att->getLocation())});
1022-
}
1023-
}
1041+
if (!EnumCaseD->getElements().empty()) {
1042+
if (!handleAttrs(EnumCaseD->getElements().front()->getAttrs()))
1043+
return false;
10241044
}
10251045
if (pushStructureNode(SN, D)) {
10261046
// FIXME: ASTWalker walks enum elements as members of the enum decl, not

test/IDE/coloring.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,3 +494,31 @@ func typeAttr3(a: @ escaping () -> Int) {}
494494

495495
// CHECK: <kw>func</kw> typeAttr2(a: @ <comment-block>/*this is fine...*/</comment-block> escaping () -> <type>Int</type>, b: <attr-builtin>@ escaping</attr-builtin> () -> <type>Int</type>) {}
496496
func typeAttr2(a: @ /*this is fine...*/ escaping () -> Int, b: @ escaping () -> Int) {}
497+
498+
// CHECK: <attr-builtin>@available</attr-builtin>(<kw>iOS</kw> <int>99</int>, *)
499+
// CHECK: <kw>var</kw> iHave = <int>10</int>, multipleVars = <int>20</int>
500+
@available(iOS 99, *)
501+
var iHave = 10, multipleVars = 20
502+
503+
enum MultipleCaseElements {
504+
// CHECK: <attr-builtin>@available</attr-builtin>(<kw>iOS</kw> <int>99</int>, *)
505+
// CHECK: <kw>case</kw> foo, bar
506+
@available(iOS 99, *)
507+
case foo, bar
508+
}
509+
510+
protocol P {}
511+
enum E {
512+
// CHECK: <attr-builtin>@available</attr-builtin>(<kw>iOS</kw> <int>99</int>, *)
513+
// CHECK: <kw>case</kw> a(<type>P</type>)
514+
@available(iOS 99, *)
515+
case a(P)
516+
}
517+
518+
// Ideally this would be attr-builtin, but we don't actually have the attribute
519+
// in the AST at all.
520+
//
521+
// CHECK: <attr-id>@available</attr-id>(<kw>iOS</kw> <int>99</int>, *)
522+
// CHECK: <kw>var</kw> <kw>_</kw> = <int>10</int>
523+
@available(iOS 99, *)
524+
var _ = 10

0 commit comments

Comments
 (0)