Skip to content

Commit 22e083e

Browse files
authored
Merge pull request #34455 from bnbarham/benb/decl-filter-70704835
Retain invalid decls when filtering using access path and skip including decls in the completion list if the completion is in their initializer.
2 parents e602aa5 + 4da190d commit 22e083e

File tree

6 files changed

+97
-63
lines changed

6 files changed

+97
-63
lines changed

include/swift/AST/NameLookup.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,22 @@ class AccessFilteringDeclConsumer final : public VisibleDeclConsumer {
414414
DynamicLookupInfo dynamicLookupInfo = {}) override;
415415
};
416416

417+
/// Filters out decls that are not usable based on their source location, eg.
418+
/// a decl inside its own initializer or a non-type decl before its definition.
419+
class UsableFilteringDeclConsumer final : public VisibleDeclConsumer {
420+
const SourceManager &SM;
421+
SourceLoc Loc;
422+
VisibleDeclConsumer &ChainedConsumer;
423+
424+
public:
425+
UsableFilteringDeclConsumer(const SourceManager &SM, SourceLoc loc,
426+
VisibleDeclConsumer &consumer)
427+
: SM(SM), Loc(loc), ChainedConsumer(consumer) {}
428+
429+
void foundDecl(ValueDecl *D, DeclVisibilityKind reason,
430+
DynamicLookupInfo dynamicLookupInfo) override;
431+
};
432+
417433
/// Remove any declarations in the given set that were overridden by
418434
/// other declarations in that set.
419435
///

lib/AST/NameLookup.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,40 @@ void DebuggerClient::anchor() {}
138138
void AccessFilteringDeclConsumer::foundDecl(
139139
ValueDecl *D, DeclVisibilityKind reason,
140140
DynamicLookupInfo dynamicLookupInfo) {
141-
if (D->hasInterfaceType() && D->isInvalid())
142-
return;
143141
if (!D->isAccessibleFrom(DC))
144142
return;
145143

146144
ChainedConsumer.foundDecl(D, reason, dynamicLookupInfo);
147145
}
148146

147+
void UsableFilteringDeclConsumer::foundDecl(ValueDecl *D,
148+
DeclVisibilityKind reason, DynamicLookupInfo dynamicLookupInfo) {
149+
// Skip when Loc is within the decl's own initializer
150+
if (auto *VD = dyn_cast<VarDecl>(D)) {
151+
if (auto *init = VD->getParentInitializer()) {
152+
auto initRange = init->getSourceRange();
153+
if (initRange.isValid() && SM.rangeContainsTokenLoc(initRange, Loc))
154+
return;
155+
}
156+
}
157+
158+
switch (reason) {
159+
case DeclVisibilityKind::LocalVariable:
160+
// Skip if Loc is before the found decl, unless its a TypeDecl (whose use
161+
// before its declaration is still allowed)
162+
if (!isa<TypeDecl>(D) && !SM.isBeforeInBuffer(D->getLoc(), Loc))
163+
return;
164+
break;
165+
default:
166+
// The rest of the file is currently skipped, so no need to check
167+
// decl location for VisibleAtTopLevel. Other visibility kinds are always
168+
// usable
169+
break;
170+
}
171+
172+
ChainedConsumer.foundDecl(D, reason, dynamicLookupInfo);
173+
}
174+
149175
void LookupResultEntry::print(llvm::raw_ostream& out) const {
150176
getValueDecl()->print(out);
151177
if (auto dc = getBaseDecl()) {

lib/IDE/CodeCompletion.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2468,9 +2468,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
24682468

24692469
void addVarDeclRef(const VarDecl *VD, DeclVisibilityKind Reason,
24702470
DynamicLookupInfo dynamicLookupInfo) {
2471-
if (!VD->hasName() ||
2472-
!VD->isAccessibleFrom(CurrDeclContext) ||
2473-
VD->shouldHideFromEditor())
2471+
if (!VD->hasName())
24742472
return;
24752473

24762474
const Identifier Name = VD->getName();
@@ -4288,8 +4286,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
42884286
ExprType = Type();
42894287
Kind = LookupKind::ValueInDeclContext;
42904288
NeedLeadingDot = false;
4291-
FilteredDeclConsumer Consumer(*this, Filter);
4292-
lookupVisibleDecls(Consumer, CurrDeclContext,
4289+
4290+
AccessFilteringDeclConsumer AccessFilteringConsumer(
4291+
CurrDeclContext, *this);
4292+
FilteredDeclConsumer FilteringConsumer(AccessFilteringConsumer, Filter);
4293+
4294+
lookupVisibleDecls(FilteringConsumer, CurrDeclContext,
42934295
/*IncludeTopLevel=*/false, Loc);
42944296
RequestedCachedResults.push_back(RequestedResultsTy::toplevelResults()
42954297
.withModuleQualifier(ModuleQualifier));
@@ -4633,7 +4635,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
46334635
void getTypeCompletionsInDeclContext(SourceLoc Loc,
46344636
bool ModuleQualifier = true) {
46354637
Kind = LookupKind::TypeInDeclContext;
4636-
lookupVisibleDecls(*this, CurrDeclContext,
4638+
4639+
AccessFilteringDeclConsumer AccessFilteringConsumer(
4640+
CurrDeclContext, *this);
4641+
lookupVisibleDecls(AccessFilteringConsumer, CurrDeclContext,
46374642
/*IncludeTopLevel=*/false, Loc);
46384643

46394644
RequestedCachedResults.push_back(
@@ -4646,21 +4651,30 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
46464651
Kind = OnlyTypes ? LookupKind::TypeInDeclContext
46474652
: LookupKind::ValueInDeclContext;
46484653
NeedLeadingDot = false;
4649-
AccessFilteringDeclConsumer FilteringConsumer(CurrDeclContext, *this);
4650-
CurrModule->lookupVisibleDecls({}, FilteringConsumer,
4654+
4655+
UsableFilteringDeclConsumer UsableFilteringConsumer(Ctx.SourceMgr,
4656+
Ctx.SourceMgr.getCodeCompletionLoc(), *this);
4657+
AccessFilteringDeclConsumer AccessFilteringConsumer(
4658+
CurrDeclContext, UsableFilteringConsumer);
4659+
4660+
CurrModule->lookupVisibleDecls({}, AccessFilteringConsumer,
46514661
NLKind::UnqualifiedLookup);
46524662
}
46534663

4654-
void getVisibleDeclsOfModule(const ModuleDecl *TheModule,
4655-
ArrayRef<std::string> AccessPath,
4656-
bool ResultsHaveLeadingDot) {
4664+
void lookupExternalModuleDecls(const ModuleDecl *TheModule,
4665+
ArrayRef<std::string> AccessPath,
4666+
bool ResultsHaveLeadingDot) {
4667+
assert(CurrModule != TheModule &&
4668+
"requested module should be external");
4669+
46574670
Kind = LookupKind::ImportFromModule;
46584671
NeedLeadingDot = ResultsHaveLeadingDot;
46594672

46604673
ImportPath::Access::Builder builder;
46614674
for (auto Piece : AccessPath) {
46624675
builder.push_back(Ctx.getIdentifier(Piece));
46634676
}
4677+
46644678
AccessFilteringDeclConsumer FilteringConsumer(CurrDeclContext, *this);
46654679
TheModule->lookupVisibleDecls(builder.get(), FilteringConsumer,
46664680
NLKind::UnqualifiedLookup);
@@ -6758,7 +6772,7 @@ void swift::ide::lookupCodeCompletionResultsFromModule(
67586772
ArrayRef<std::string> accessPath, bool needLeadingDot,
67596773
const DeclContext *currDeclContext) {
67606774
CompletionLookup Lookup(targetSink, module->getASTContext(), currDeclContext);
6761-
Lookup.getVisibleDeclsOfModule(module, accessPath, needLeadingDot);
6775+
Lookup.lookupExternalModuleDecls(module, accessPath, needLeadingDot);
67626776
}
67636777

67646778
void swift::ide::copyCodeCompletionResults(CodeCompletionResultSink &targetSink,

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,55 +1302,9 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer,
13021302
lookupVisibleDeclsImpl(Consumer, DC, IncludeTopLevel, Loc);
13031303
return;
13041304
}
1305-
1306-
// Filtering out unusable values.
1307-
class LocalConsumer : public VisibleDeclConsumer {
1308-
const SourceManager &SM;
1309-
SourceLoc Loc;
1310-
VisibleDeclConsumer &Consumer;
1311-
1312-
bool isUsableValue(ValueDecl *VD, DeclVisibilityKind Reason) {
1313-
1314-
// Check "use within its own initial value" case.
1315-
if (auto *varD = dyn_cast<VarDecl>(VD)) {
1316-
if (auto *initExpr = varD->getParentInitializer())
1317-
if (SM.rangeContainsTokenLoc(initExpr->getSourceRange(), Loc))
1318-
return false;
1319-
}
1320-
1321-
switch (Reason) {
1322-
case DeclVisibilityKind::LocalVariable:
1323-
// Use of 'TypeDecl's before declaration is allowed.
1324-
if (isa<TypeDecl>(VD))
1325-
return true;
1326-
1327-
return SM.isBeforeInBuffer(VD->getLoc(), Loc);
1328-
1329-
case DeclVisibilityKind::VisibleAtTopLevel:
1330-
// TODO: Implement forward reference rule for script mode? Currently,
1331-
// it's not needed because the rest of the file hasn't been parsed.
1332-
// See: https://bugs.swift.org/browse/SR-284 for the rule.
1333-
return true;
1334-
1335-
default:
1336-
// Other visibility kind are always usable.
1337-
return true;
1338-
}
1339-
}
1340-
1341-
public:
1342-
LocalConsumer(const SourceManager &SM, SourceLoc Loc,
1343-
VisibleDeclConsumer &Consumer)
1344-
: SM(SM), Loc(Loc), Consumer(Consumer) {}
1345-
1346-
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
1347-
DynamicLookupInfo dynamicLookupInfo) override {
1348-
if (isUsableValue(VD, Reason))
1349-
Consumer.foundDecl(VD, Reason, dynamicLookupInfo);
1350-
}
1351-
} LocalConsumer(DC->getASTContext().SourceMgr, Loc, Consumer);
1352-
1353-
lookupVisibleDeclsImpl(LocalConsumer, DC, IncludeTopLevel, Loc);
1305+
UsableFilteringDeclConsumer FilteringConsumer(DC->getASTContext().SourceMgr,
1306+
Loc, Consumer);
1307+
lookupVisibleDeclsImpl(FilteringConsumer, DC, IncludeTopLevel, Loc);
13541308
}
13551309

13561310
void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy,

test/IDE/complete_at_top_level.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_VAR_INIT_3 | %FileCheck %s -check-prefix=TOP_LEVEL_VAR_INIT_3_NEGATIVE
2+
13
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_CHECKED_EXPR_1 | %FileCheck %s -check-prefix=TYPE_CHECKED_EXPR_1
24
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_CHECKED_EXPR_2 | %FileCheck %s -check-prefix=TYPE_CHECKED_EXPR_2
35
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_CHECKED_EXPR_3 | %FileCheck %s -check-prefix=TYPE_CHECKED_EXPR_3
@@ -153,6 +155,9 @@
153155
// This test is not meant to test that we can correctly form all kinds of
154156
// completion results in general; that should be tested elsewhere.
155157

158+
var topLevelVar3 = #^TOP_LEVEL_VAR_INIT_3^#
159+
// TOP_LEVEL_VAR_INIT_3_NEGATIVE-NOT: topLevelVar3
160+
156161
struct FooStruct {
157162
var instanceVar = 0
158163

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
3+
4+
// GLOBAL: Decl[GlobalVar]/CurrModule: invalidDecl[#<<error type>>#];
5+
let invalidDecl = INVALID
6+
7+
struct S {
8+
// MEMBER: Decl[InstanceMethod]/CurrNominal: invalidMethod()[#<<error type>>#];
9+
func invalidMethod() -> INVALID
10+
}
11+
12+
func test() {
13+
#^GLOBAL_1?check=GLOBAL^#
14+
#^GLOBAL_2?check=GLOBAL^#
15+
}
16+
17+
func testMember(val: S) {
18+
val.#^MEMBER_1?check=MEMBER^##^MEMBER_2?check=MEMBER^#
19+
}

0 commit comments

Comments
 (0)