Skip to content

Commit 152eeaa

Browse files
committed
[Sema] Add a fixit for diagnosis "variable used within its own initial value".
This fixit checks if a decl with the identical name can be found in the parent type context; if can, we add "self." to try to resolve the issue. rdar://25389852
1 parent 395b370 commit 152eeaa

File tree

5 files changed

+103
-54
lines changed

5 files changed

+103
-54
lines changed

include/swift/Parse/Parser.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,9 @@ class Parser {
697697
return AlreadyHandledDecls.erase(D);
698698
}
699699

700-
ParserStatus parseDecl(SmallVectorImpl<Decl*> &Entries, ParseDeclOptions Flags);
700+
ParserStatus parseDecl(ParseDeclOptions Flags,
701+
llvm::function_ref<void(Decl*)> Handler);
702+
701703
void parseDeclDelayed();
702704

703705
ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
@@ -750,9 +752,9 @@ class Parser {
750752
DeclAttributes &Attributes);
751753
ParserStatus parseDeclEnumCase(ParseDeclOptions Flags, DeclAttributes &Attributes,
752754
SmallVectorImpl<Decl *> &decls);
753-
bool parseNominalDeclMembers(SmallVectorImpl<Decl *> &memberDecls,
754-
SourceLoc LBLoc, SourceLoc &RBLoc,
755-
Diag<> ErrorDiag, ParseDeclOptions flags);
755+
bool parseNominalDeclMembers(SourceLoc LBLoc, SourceLoc &RBLoc,
756+
Diag<> ErrorDiag, ParseDeclOptions flags,
757+
llvm::function_ref<void(Decl*)> handler);
756758
ParserResult<StructDecl>
757759
parseDeclStruct(ParseDeclOptions Flags, DeclAttributes &Attributes);
758760
ParserResult<ClassDecl>

lib/Parse/ParseDecl.cpp

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,8 +1931,13 @@ void Parser::delayParseFromBeginningToHere(ParserPosition BeginParserPosition,
19311931
/// decl-import
19321932
/// decl-operator
19331933
/// \endverbatim
1934-
ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
1935-
ParseDeclOptions Flags) {
1934+
ParserStatus Parser::parseDecl(ParseDeclOptions Flags,
1935+
llvm::function_ref<void(Decl*)> Handler) {
1936+
Decl* LastDecl = nullptr;
1937+
auto InternalHandler = [&](Decl *D) {
1938+
LastDecl = D;
1939+
Handler(D);
1940+
};
19361941
ParserPosition BeginParserPosition;
19371942
if (isCodeCompletionFirstPass())
19381943
BeginParserPosition = getParserPosition();
@@ -2115,12 +2120,15 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
21152120
Status = DeclResult;
21162121
break;
21172122
case tok::kw_let:
2118-
case tok::kw_var:
2123+
case tok::kw_var: {
2124+
llvm::SmallVector<Decl *, 4> Entries;
21192125
Status = parseDeclVar(Flags, Attributes, Entries, StaticLoc,
21202126
StaticSpelling, tryLoc);
21212127
StaticLoc = SourceLoc(); // we handled static if present.
21222128
MayNeedOverrideCompletion = true;
2129+
std::for_each(Entries.begin(), Entries.end(), InternalHandler);
21232130
break;
2131+
}
21242132
case tok::kw_typealias:
21252133
DeclResult = parseDeclTypeAlias(Flags, Attributes);
21262134
Status = DeclResult;
@@ -2133,9 +2141,12 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
21332141
DeclResult = parseDeclEnum(Flags, Attributes);
21342142
Status = DeclResult;
21352143
break;
2136-
case tok::kw_case:
2144+
case tok::kw_case: {
2145+
llvm::SmallVector<Decl *, 4> Entries;
21372146
Status = parseDeclEnumCase(Flags, Attributes, Entries);
2147+
std::for_each(Entries.begin(), Entries.end(), InternalHandler);
21382148
break;
2149+
}
21392150
case tok::kw_struct:
21402151
DeclResult = parseDeclStruct(Flags, Attributes);
21412152
Status = DeclResult;
@@ -2162,10 +2173,10 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
21622173

21632174
if (auto ICD = IfConfigResult.getPtrOrNull()) {
21642175
// The IfConfigDecl is ahead of its members in source order.
2165-
Entries.push_back(ICD);
2176+
InternalHandler(ICD);
21662177
// Copy the active members into the entries list.
21672178
for (auto activeMember : ICD->getActiveMembers()) {
2168-
Entries.push_back(activeMember);
2179+
InternalHandler(activeMember);
21692180
}
21702181
}
21712182
break;
@@ -2185,15 +2196,18 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
21852196
MayNeedOverrideCompletion = true;
21862197
break;
21872198

2188-
case tok::kw_subscript:
2199+
case tok::kw_subscript: {
21892200
if (StaticLoc.isValid()) {
21902201
diagnose(Tok, diag::subscript_static, StaticSpelling)
21912202
.fixItRemove(SourceRange(StaticLoc));
21922203
StaticLoc = SourceLoc();
21932204
}
2205+
llvm::SmallVector<Decl *, 4> Entries;
21942206
Status = parseDeclSubscript(Flags, Attributes, Entries);
2207+
std::for_each(Entries.begin(), Entries.end(), InternalHandler);
21952208
MayNeedOverrideCompletion = true;
21962209
break;
2210+
}
21972211

21982212
case tok::code_complete:
21992213
MayNeedOverrideCompletion = true;
@@ -2261,20 +2275,20 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
22612275
if (DeclResult.isNonNull()) {
22622276
Decl *D = DeclResult.get();
22632277
if (!declWasHandledAlready(D))
2264-
Entries.push_back(DeclResult.get());
2278+
InternalHandler(DeclResult.get());
22652279
}
22662280

22672281
if (Tok.is(tok::semi)) {
22682282
SourceLoc TrailingSemiLoc = consumeToken(tok::semi);
22692283
if (Status.isSuccess())
2270-
Entries.back()->TrailingSemiLoc = TrailingSemiLoc;
2284+
LastDecl->TrailingSemiLoc = TrailingSemiLoc;
22712285
}
22722286

22732287
if (Status.isSuccess()) {
22742288
// If we parsed 'class' or 'static', but didn't handle it above, complain
22752289
// about it.
22762290
if (StaticLoc.isValid())
2277-
diagnose(Entries.back()->getLoc(), diag::decl_not_static,
2291+
diagnose(LastDecl->getLoc(), diag::decl_not_static,
22782292
StaticSpelling)
22792293
.fixItRemove(SourceRange(StaticLoc));
22802294
}
@@ -2309,8 +2323,7 @@ void Parser::parseDeclDelayed() {
23092323
Scope S(this, DelayedState->takeScope());
23102324
ContextChange CC(*this, DelayedState->ParentContext);
23112325

2312-
SmallVector<Decl *, 2> Entries;
2313-
parseDecl(Entries, ParseDeclOptions(DelayedState->Flags));
2326+
parseDecl(ParseDeclOptions(DelayedState->Flags), [](Decl *D) {});
23142327
}
23152328

23162329
/// \brief Parse an 'import' declaration, doing no token skipping on error.
@@ -2609,7 +2622,6 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
26092622
trailingWhereClause);
26102623
ext->getAttrs() = Attributes;
26112624

2612-
SmallVector<Decl*, 8> MemberDecls;
26132625
SourceLoc LBLoc, RBLoc;
26142626
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_extension)) {
26152627
LBLoc = PreviousLoc;
@@ -2627,7 +2639,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
26272639
ParseDeclOptions Options(PD_HasContainerType |
26282640
PD_InExtension);
26292641

2630-
return parseDecl(MemberDecls, Options);
2642+
return parseDecl(Options, [&] (Decl *D) {ext->addMember(D);});
26312643
});
26322644
// Don't propagate the code completion bit from members: we cannot help
26332645
// code completion inside a member decl, and our callers cannot do
@@ -2637,8 +2649,6 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
26372649
}
26382650

26392651
ext->setBraces({LBLoc, RBLoc});
2640-
for (auto member : MemberDecls)
2641-
ext->addMember(member);
26422652

26432653
if (!DCC.movedToTopLevel() && !(Flags & PD_AllowTopLevel)) {
26442654
diagnose(ExtensionLoc, diag::decl_inner_scope);
@@ -2834,7 +2844,7 @@ ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
28342844
ParserStatus Status;
28352845
while (Tok.isNot(tok::pound_else) && Tok.isNot(tok::pound_endif) &&
28362846
Tok.isNot(tok::pound_elseif)) {
2837-
Status = parseDecl(Decls, Flags);
2847+
Status = parseDecl(Flags, [&](Decl *D) {Decls.push_back(D);});
28382848
if (Status.isError()) {
28392849
diagnose(Tok, diag::expected_close_to_if_directive);
28402850
skipUntilConditionalBlockClose();
@@ -4654,7 +4664,6 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
46544664
UD->setInherited(Context.AllocateCopy(Inherited));
46554665
}
46564666

4657-
SmallVector<Decl*, 8> MemberDecls;
46584667
SourceLoc LBLoc, RBLoc;
46594668
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_enum)) {
46604669
LBLoc = PreviousLoc;
@@ -4664,15 +4673,13 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
46644673
ContextChange CC(*this, UD);
46654674
Scope S(this, ScopeKind::ClassBody);
46664675
ParseDeclOptions Options(PD_HasContainerType | PD_AllowEnumElement | PD_InEnum);
4667-
if (parseNominalDeclMembers(MemberDecls, LBLoc, RBLoc,
4676+
if (parseNominalDeclMembers(LBLoc, RBLoc,
46684677
diag::expected_rbrace_enum,
4669-
Options))
4678+
Options, [&] (Decl *D) { UD->addMember(D); }))
46704679
Status.setIsParseError();
46714680
}
46724681

46734682
UD->setBraces({LBLoc, RBLoc});
4674-
for (auto member : MemberDecls)
4675-
UD->addMember(member);
46764683

46774684
addToScope(UD);
46784685

@@ -4851,9 +4858,14 @@ ParserStatus Parser::parseDeclEnumCase(ParseDeclOptions Flags,
48514858
/// \verbatim
48524859
/// decl*
48534860
/// \endverbatim
4854-
bool Parser::parseNominalDeclMembers(SmallVectorImpl<Decl *> &memberDecls,
4855-
SourceLoc LBLoc, SourceLoc &RBLoc,
4856-
Diag<> ErrorDiag, ParseDeclOptions flags) {
4861+
bool Parser::parseNominalDeclMembers(SourceLoc LBLoc, SourceLoc &RBLoc,
4862+
Diag<> ErrorDiag, ParseDeclOptions flags,
4863+
llvm::function_ref<void(Decl*)> handler) {
4864+
Decl *lastDecl = nullptr;
4865+
auto internalHandler = [&](Decl *D) {
4866+
lastDecl = D;
4867+
handler(D);
4868+
};
48574869
bool previousHadSemi = true;
48584870
parseList(tok::r_brace, LBLoc, RBLoc, tok::semi, /*OptionalSep=*/true,
48594871
/*AllowSepAfterLast=*/false, ErrorDiag, [&]() -> ParserStatus {
@@ -4867,11 +4879,11 @@ bool Parser::parseNominalDeclMembers(SmallVectorImpl<Decl *> &memberDecls,
48674879
}
48684880

48694881
previousHadSemi = false;
4870-
if (parseDecl(memberDecls, flags).isError())
4882+
if (parseDecl(flags, internalHandler).isError())
48714883
return makeParserError();
48724884

48734885
// Check whether the previous declaration had a semicolon after it.
4874-
if (!memberDecls.empty() && memberDecls.back()->TrailingSemiLoc.isValid())
4886+
if (lastDecl && lastDecl->TrailingSemiLoc.isValid())
48754887
previousHadSemi = true;
48764888

48774889
return makeParserSuccess();
@@ -4935,7 +4947,6 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
49354947
SD->setInherited(Context.AllocateCopy(Inherited));
49364948
}
49374949

4938-
SmallVector<Decl*, 8> MemberDecls;
49394950
SourceLoc LBLoc, RBLoc;
49404951
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_struct)) {
49414952
LBLoc = PreviousLoc;
@@ -4946,15 +4957,13 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
49464957
ContextChange CC(*this, SD);
49474958
Scope S(this, ScopeKind::StructBody);
49484959
ParseDeclOptions Options(PD_HasContainerType | PD_InStruct);
4949-
if (parseNominalDeclMembers(MemberDecls, LBLoc, RBLoc,
4960+
if (parseNominalDeclMembers(LBLoc, RBLoc,
49504961
diag::expected_rbrace_struct,
4951-
Options))
4962+
Options, [&](Decl *D) {SD->addMember(D);}))
49524963
Status.setIsParseError();
49534964
}
49544965

49554966
SD->setBraces({LBLoc, RBLoc});
4956-
for (auto member : MemberDecls)
4957-
SD->addMember(member);
49584967

49594968
addToScope(SD);
49604969

@@ -5018,7 +5027,6 @@ ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
50185027
CD->setInherited(Context.AllocateCopy(Inherited));
50195028
}
50205029

5021-
SmallVector<Decl*, 8> MemberDecls;
50225030
SourceLoc LBLoc, RBLoc;
50235031
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_class)) {
50245032
LBLoc = PreviousLoc;
@@ -5030,18 +5038,17 @@ ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
50305038
Scope S(this, ScopeKind::ClassBody);
50315039
ParseDeclOptions Options(PD_HasContainerType | PD_AllowDestructor |
50325040
PD_InClass);
5033-
if (parseNominalDeclMembers(MemberDecls, LBLoc, RBLoc,
5034-
diag::expected_rbrace_class,
5035-
Options))
5041+
auto Handler = [&] (Decl *D) {
5042+
CD->addMember(D);
5043+
if (isa<DestructorDecl>(D))
5044+
CD->setHasDestructor();
5045+
};
5046+
if (parseNominalDeclMembers(LBLoc, RBLoc, diag::expected_rbrace_class,
5047+
Options, Handler))
50365048
Status.setIsParseError();
50375049
}
50385050

50395051
CD->setBraces({LBLoc, RBLoc});
5040-
for (auto member : MemberDecls) {
5041-
CD->addMember(member);
5042-
if (isa<DestructorDecl>(member))
5043-
CD->setHasDestructor();
5044-
}
50455052

50465053
addToScope(CD);
50475054

@@ -5120,9 +5127,6 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
51205127

51215128
// Parse the body.
51225129
{
5123-
// The list of protocol elements.
5124-
SmallVector<Decl*, 8> Members;
5125-
51265130
SourceLoc LBraceLoc;
51275131
SourceLoc RBraceLoc;
51285132
if (parseToken(tok::l_brace, LBraceLoc, diag::expected_lbrace_protocol)) {
@@ -5135,16 +5139,14 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
51355139
PD_DisallowNominalTypes |
51365140
PD_DisallowInit |
51375141
PD_InProtocol);
5138-
if (parseNominalDeclMembers(Members, LBraceLoc, RBraceLoc,
5142+
if (parseNominalDeclMembers(LBraceLoc, RBraceLoc,
51395143
diag::expected_rbrace_protocol,
5140-
Options))
5144+
Options, [&](Decl *D) {Proto->addMember(D);}))
51415145
Status.setIsParseError();
51425146
}
51435147

51445148
// Install the protocol elements.
51455149
Proto->setBraces({LBraceLoc, RBraceLoc});
5146-
for (auto member : Members)
5147-
Proto->addMember(member);
51485150
}
51495151

51505152
if (Flags & PD_DisallowNominalTypes) {

lib/Parse/ParseExpr.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,17 @@ DeclName Parser::parseUnqualifiedDeclName(bool allowInit,
16161616
return DeclName(Context, baseName, argumentLabels);
16171617
}
16181618

1619+
static bool shouldAddSelfFixit(DeclContext* Current, DeclName Name) {
1620+
if (Current->isTypeContext() || !Current->getInnermostTypeContext())
1621+
return false;
1622+
if (auto *Nominal = Current->getInnermostTypeContext()->
1623+
getAsNominalTypeOrNominalTypeExtensionContext()){
1624+
// FIXME: we cannot resolve members appear later in the body of the nominal.
1625+
return !Nominal->lookupDirect(Name).empty();
1626+
}
1627+
return false;
1628+
}
1629+
16191630
/// expr-identifier:
16201631
/// unqualified-decl-name generic-args?
16211632
Expr *Parser::parseExprIdentifier() {
@@ -1662,7 +1673,11 @@ Expr *Parser::parseExprIdentifier() {
16621673
} else {
16631674
for (auto activeVar : DisabledVars) {
16641675
if (activeVar->getFullName() == name) {
1665-
diagnose(loc.getBaseNameLoc(), DisabledVarReason);
1676+
auto diag = diagnose(loc.getBaseNameLoc(), DisabledVarReason);
1677+
if (DisabledVarReason.ID == diag::var_init_self_referential.ID
1678+
&& shouldAddSelfFixit(CurDeclContext, name)) {
1679+
diag.fixItInsert(loc.getBaseNameLoc(), "self.");
1680+
}
16661681
return new (Context) ErrorExpr(loc.getSourceRange());
16671682
}
16681683
}

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
295295
&& Tok.isNot(tok::pound_if, tok::pound_setline,
296296
tok::pound_sourceLocation)) {
297297
ParserStatus Status =
298-
parseDecl(TmpDecls, IsTopLevel ? PD_AllowTopLevel : PD_Default);
298+
parseDecl(IsTopLevel ? PD_AllowTopLevel : PD_Default,
299+
[&](Decl *D) {TmpDecls.push_back(D);});
299300
if (Status.isError()) {
300301
NeedParseErrorRecovery = true;
301302
if (Status.hasCodeCompletion() && IsTopLevel &&
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend -parse -verify %s
2+
3+
class A1 {
4+
func foo1() {}
5+
func foo2() {
6+
var foo1 = foo1() // expected-error {{variable used within its own initial value}}{{16-16=self.}}
7+
}
8+
}
9+
10+
class A2 {
11+
var foo1 = 2
12+
func foo2() {
13+
var foo1 = foo1 // expected-error {{variable used within its own initial value}}{{16-16=self.}}
14+
}
15+
}
16+
17+
class A3 {
18+
func foo2() {
19+
// FIXME: this should also add fixit.
20+
var foo1 = foo1() // expected-error {{variable used within its own initial value}}{{none}}
21+
}
22+
func foo1() {}
23+
}
24+
25+
class A4 {
26+
func foo2() {
27+
var foo1 = foo1 // expected-error {{variable used within its own initial value}}{{none}}
28+
}
29+
}

0 commit comments

Comments
 (0)