Skip to content

Commit ba0e575

Browse files
authored
Merge pull request #20904 from rintaro/ast-lookupvisibledecls-forward
[AST] Don't suggest unusable values for typo correction and code completion
2 parents a127d1b + a54d2ff commit ba0e575

File tree

4 files changed

+110
-29
lines changed

4 files changed

+110
-29
lines changed

lib/AST/LookupVisibleDecls.cpp

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -942,11 +942,10 @@ static void lookupVisibleMemberDecls(
942942
Consumer.foundDecl(DeclAndReason.D, DeclAndReason.Reason);
943943
}
944944

945-
void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer,
946-
const DeclContext *DC,
947-
LazyResolver *TypeResolver,
948-
bool IncludeTopLevel,
949-
SourceLoc Loc) {
945+
static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
946+
const DeclContext *DC,
947+
LazyResolver *TypeResolver,
948+
bool IncludeTopLevel, SourceLoc Loc) {
950949
const ModuleDecl &M = *DC->getParentModule();
951950
const SourceManager &SM = DC->getASTContext().SourceMgr;
952951
auto Reason = DeclVisibilityKind::MemberOfCurrentNominal;
@@ -1067,6 +1066,65 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer,
10671066
}
10681067
}
10691068

1069+
void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer,
1070+
const DeclContext *DC,
1071+
LazyResolver *TypeResolver,
1072+
bool IncludeTopLevel,
1073+
SourceLoc Loc) {
1074+
if (Loc.isInvalid()) {
1075+
lookupVisibleDeclsImpl(Consumer, DC, TypeResolver, IncludeTopLevel, Loc);
1076+
return;
1077+
}
1078+
1079+
// Filtering out unusable values.
1080+
class LocalConsumer : public VisibleDeclConsumer {
1081+
const SourceManager &SM;
1082+
SourceLoc Loc;
1083+
VisibleDeclConsumer &Consumer;
1084+
1085+
bool isUsableValue(ValueDecl *VD, DeclVisibilityKind Reason) {
1086+
1087+
// Check "use within its own initial value" case.
1088+
if (auto *varD = dyn_cast<VarDecl>(VD))
1089+
if (auto *PBD = varD->getParentPatternBinding())
1090+
if (!PBD->isImplicit() &&
1091+
SM.rangeContainsTokenLoc(PBD->getSourceRange(), Loc))
1092+
return false;
1093+
1094+
switch (Reason) {
1095+
case DeclVisibilityKind::LocalVariable:
1096+
// Use of 'TypeDecl's before declaration is allowed.
1097+
if (isa<TypeDecl>(VD))
1098+
return true;
1099+
1100+
return SM.isBeforeInBuffer(VD->getLoc(), Loc);
1101+
1102+
case DeclVisibilityKind::VisibleAtTopLevel:
1103+
// TODO: Implement forward reference rule for script mode? Currently,
1104+
// it's not needed because the rest of the file hasn't been parsed.
1105+
// See: https://bugs.swift.org/browse/SR-284 for the rule.
1106+
return true;
1107+
1108+
default:
1109+
// Other visibility kind are always usable.
1110+
return true;
1111+
}
1112+
}
1113+
1114+
public:
1115+
LocalConsumer(const SourceManager &SM, SourceLoc Loc,
1116+
VisibleDeclConsumer &Consumer)
1117+
: SM(SM), Loc(Loc), Consumer(Consumer) {}
1118+
1119+
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) {
1120+
if (isUsableValue(VD, Reason))
1121+
Consumer.foundDecl(VD, Reason);
1122+
}
1123+
} LocalConsumer(DC->getASTContext().SourceMgr, Loc, Consumer);
1124+
1125+
lookupVisibleDeclsImpl(LocalConsumer, DC, TypeResolver, IncludeTopLevel, Loc);
1126+
}
1127+
10701128
void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy,
10711129
const DeclContext *CurrDC,
10721130
LazyResolver *TypeResolver,

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -637,15 +637,6 @@ static bool isPlausibleTypo(DeclRefKind refKind, DeclName typedName,
637637
return true;
638638
}
639639

640-
static bool isLocInVarInit(TypeChecker &TC, VarDecl *var, SourceLoc loc) {
641-
auto binding = var->getParentPatternBinding();
642-
if (!binding || binding->isImplicit())
643-
return false;
644-
645-
auto initRange = binding->getSourceRange();
646-
return TC.Context.SourceMgr.rangeContainsTokenLoc(initRange, loc);
647-
}
648-
649640
void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind,
650641
Type baseTypeOrNull,
651642
NameLookupOptions lookupOptions,
@@ -670,12 +661,6 @@ void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind,
670661
if (!isPlausibleTypo(refKind, corrections.WrittenName, decl))
671662
return;
672663

673-
// Don't suggest a variable within its own initializer.
674-
if (auto var = dyn_cast<VarDecl>(decl)) {
675-
if (isLocInVarInit(*this, var, corrections.Loc.getBaseNameLoc()))
676-
return;
677-
}
678-
679664
auto candidateName = decl->getFullName();
680665

681666
// Don't waste time computing edit distances that are more than

test/IDE/complete_expr_postfix_begin.swift

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@
7575
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_TUPLE_1 | %FileCheck %s -check-prefix=IN_TUPLE_1
7676
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_TUPLE_2 | %FileCheck %s -check-prefix=IN_TUPLE_2
7777

78+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_1 | %FileCheck %s -check-prefix=OWN_INIT_1
79+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_2 | %FileCheck %s -check-prefix=OWN_INIT_2
80+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_3 | %FileCheck %s -check-prefix=OWN_INIT_3
81+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_4 | %FileCheck %s -check-prefix=OWN_INIT_4
82+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_5 | %FileCheck %s -check-prefix=OWN_INIT_5
83+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_6 | %FileCheck %s -check-prefix=OWN_INIT_6
84+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_7 | %FileCheck %s -check-prefix=OWN_INIT_7
85+
7886
//
7987
// Test code completion at the beginning of expr-postfix.
8088
//
@@ -435,8 +443,7 @@ func testInForEach1(arg: Int) {
435443
let after = 4
436444
// IN_FOR_EACH_1-NOT: Decl[LocalVar]
437445
// IN_FOR_EACH_1: Decl[LocalVar]/Local: local[#Int#];
438-
// FIXME: shouldn't show 'after' here.
439-
// IN_FOR_EACH_1: Decl[LocalVar]/Local: after[#Int#];
446+
// IN_FOR_EACH_1-NOT: after
440447
// IN_FOR_EACH_1: Decl[LocalVar]/Local: arg[#Int#];
441448
// IN_FOR_EACH_1-NOT: Decl[LocalVar]
442449
}
@@ -448,8 +455,7 @@ func testInForEach2(arg: Int) {
448455
let after = 4
449456
// IN_FOR_EACH_2-NOT: Decl[LocalVar]
450457
// IN_FOR_EACH_2: Decl[LocalVar]/Local/TypeRelation[Identical]: local[#Int#];
451-
// FIXME: shouldn't show 'after' here.
452-
// IN_FOR_EACH_2: Decl[LocalVar]/Local/TypeRelation[Identical]: after[#Int#];
458+
// IN_FOR_EACH_2-NOT: after
453459
// IN_FOR_EACH_2: Decl[LocalVar]/Local/TypeRelation[Identical]: arg[#Int#];
454460
// IN_FOR_EACH_2-NOT: Decl[LocalVar]
455461
}
@@ -463,8 +469,7 @@ func testInForEach3(arg: Int) {
463469
// IN_FOR_EACH_3: Decl[LocalVar]/Local: index[#Int#];
464470
// IN_FOR_EACH_3-NOT: Decl[LocalVar]
465471
// IN_FOR_EACH_3: Decl[LocalVar]/Local: local[#Int#];
466-
// FIXME: shouldn't show 'after' here.
467-
// IN_FOR_EACH_3: Decl[LocalVar]/Local: after[#Int#];
472+
// IN_FOR_EACH_3-NOT: after
468473
// IN_FOR_EACH_3: Decl[LocalVar]/Local: arg[#Int#];
469474
// IN_FOR_EACH_3-NOT: Decl[LocalVar]
470475
}
@@ -503,8 +508,7 @@ func testInForEach9(arg: Int) {
503508
// NOTE: [Convertible] to AnyHashable.
504509
// IN_FOR_EACH_4-NOT: Decl[LocalVar]
505510
// IN_FOR_EACH_4: Decl[LocalVar]/Local/TypeRelation[Convertible]: local[#Int#];
506-
// FIXME: shouldn't show 'after' here.
507-
// IN_FOR_EACH_4: Decl[LocalVar]/Local/TypeRelation[Convertible]: after[#Int#];
511+
// IN_FOR_EACH_4-NOT: after
508512
// IN_FOR_EACH_4: Decl[LocalVar]/Local/TypeRelation[Convertible]: arg[#Int#];
509513
// IN_FOR_EACH_4-NOT: Decl[LocalVar]
510514
}
@@ -555,3 +559,31 @@ func testTuple(localInt: Int) {
555559
// IN_TUPLE_2: Decl[LocalVar]/Local: localStr[#String#]; name=localStr
556560
// IN_TUPLE_2: Decl[LocalVar]/Local/TypeRelation[Identical]: localInt[#Int#]; name=localInt
557561
// IN_TUPLE_2: End completions
562+
563+
var ownInit1: Int = #^OWN_INIT_1^#
564+
// OWN_INIT_1: Begin completions
565+
// OWN_INIT_1-NOT: ownInit1
566+
var ownInit2: () -> Void = { #^OWN_INIT_2^# }
567+
// OWN_INIT_2: Begin completions
568+
// OWN_INIT_2-NOT: ownInit2
569+
struct OwnInitTester {
570+
var ownInit3: Int = #^OWN_INIT_3^#
571+
// OWN_INIT_3: Begin completions
572+
// OWN_INIT_3-NOT: ownInit3
573+
var ownInit4: () -> Void = { #^OWN_INIT_4^# }
574+
// OWN_INIT_4: Begin completions
575+
// OWN_INIT_4-NOT: ownInit4
576+
}
577+
func ownInitTesting() {
578+
var ownInit5: Int = #^OWN_INIT_5^#
579+
// OWN_INIT_5: Begin completions
580+
// OWN_INIT_5-NOT: ownInit5
581+
var ownInit6: () -> Void = { #^OWN_INIT_6^# }
582+
// OWN_INIT_6: Begin completions
583+
// OWN_INIT_6-NOT: ownInit6
584+
}
585+
func ownInitTestingShadow(ownInit7: Int) {
586+
var ownInit7: Int = #^OWN_INIT_7^#
587+
// OWN_INIT_7: Begin completions
588+
// OWN_INIT_7: Decl[LocalVar]/Local/TypeRelation[Identical]: ownInit7[#Int#];
589+
}

test/Sema/typo_correction.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -typo-correction-limit 22
1+
// RUN: %target-typecheck-verify-swift -typo-correction-limit 23
22
// RUN: not %target-swift-frontend -typecheck -disable-typo-correction %s 2>&1 | %FileCheck %s -check-prefix=DISABLED
33
// RUN: not %target-swift-frontend -typecheck -typo-correction-limit 0 %s 2>&1 | %FileCheck %s -check-prefix=DISABLED
44
// RUN: not %target-swift-frontend -typecheck -DIMPORT_FAIL %s 2>&1 | %FileCheck %s -check-prefix=DISABLED
@@ -191,3 +191,9 @@ func test_underscored_match() {
191191
_ = _fggs + 1
192192
// expected-error@-1 {{use of unresolved identifier '_fggs'; did you mean '_eggs'?}}
193193
}
194+
195+
// Don't show values before declaration.
196+
func testFwdRef() {
197+
let _ = forward_refX + 1 // expected-error {{use of unresolved identifier 'forward_refX'}}
198+
let forward_ref1 = 4
199+
}

0 commit comments

Comments
 (0)