Skip to content

Commit a296e61

Browse files
committed
[CodeComplete] Show global completions from modules that are imported as @_spi
If a module is imported as `@_spi`, we didn’t receive any global completions from it. rdar://99027179
1 parent 0aacdfc commit a296e61

File tree

4 files changed

+118
-8
lines changed

4 files changed

+118
-8
lines changed

include/swift/IDE/CodeCompletionCache.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class CodeCompletionCache {
4545
bool ResultsHaveLeadingDot;
4646
bool ForTestableLookup;
4747
bool ForPrivateImportLookup;
48+
/// Must be sorted alphabetically for stable identity.
49+
llvm::SmallVector<std::string, 2> SpiGroups;
4850
bool AddInitsInToplevel;
4951
bool AddCallWithNoDefaultArgs;
5052
bool Annotated;
@@ -56,6 +58,7 @@ class CodeCompletionCache {
5658
LHS.ResultsHaveLeadingDot == RHS.ResultsHaveLeadingDot &&
5759
LHS.ForTestableLookup == RHS.ForTestableLookup &&
5860
LHS.ForPrivateImportLookup == RHS.ForPrivateImportLookup &&
61+
LHS.SpiGroups == RHS.SpiGroups &&
5962
LHS.AddInitsInToplevel == RHS.AddInitsInToplevel &&
6063
LHS.AddCallWithNoDefaultArgs == RHS.AddCallWithNoDefaultArgs &&
6164
LHS.Annotated == RHS.Annotated;
@@ -125,16 +128,35 @@ template<>
125128
struct DenseMapInfo<swift::ide::CodeCompletionCache::Key> {
126129
using KeyTy = swift::ide::CodeCompletionCache::Key;
127130
static inline KeyTy getEmptyKey() {
128-
return KeyTy{"", "", {}, false, false, false, false, false, false};
131+
return KeyTy{/*ModuleFilename=*/"",
132+
/*ModuleName=*/"",
133+
/*AccessPath=*/{},
134+
/*ResultsHaveLeadingDot=*/false,
135+
/*ForTestableLookup=*/false,
136+
/*ForPrivateImportLookup=*/false,
137+
/*SpiGroups=*/{},
138+
/*AddInitsInToplevel=*/false,
139+
/*AddCallWithNoDefaultArgs=*/false,
140+
/*Annotated=*/false};
129141
}
130142
static inline KeyTy getTombstoneKey() {
131-
return KeyTy{"", "", {}, true, false, false, false, false, false};
143+
return KeyTy{/*ModuleFilename=*/"",
144+
/*ModuleName=*/"",
145+
/*AccessPath=*/{},
146+
/*ResultsHaveLeadingDot=*/true,
147+
/*ForTestableLookup=*/false,
148+
/*ForPrivateImportLookup=*/false,
149+
/*SpiGroups=*/{},
150+
/*AddInitsInToplevel=*/false,
151+
/*AddCallWithNoDefaultArgs=*/false,
152+
/*Annotated=*/false};
132153
}
133154
static unsigned getHashValue(const KeyTy &Val) {
134155
return llvm::hash_combine(
135156
Val.ModuleFilename, Val.ModuleName,
136157
llvm::hash_combine_range(Val.AccessPath.begin(), Val.AccessPath.end()),
137158
Val.ResultsHaveLeadingDot, Val.ForTestableLookup,
159+
llvm::hash_combine_range(Val.SpiGroups.begin(), Val.SpiGroups.end()),
138160
Val.ForPrivateImportLookup, Val.AddInitsInToplevel,
139161
Val.AddCallWithNoDefaultArgs, Val.Annotated);
140162
}

lib/IDE/CodeCompletion.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,16 @@ void swift::ide::deliverCompletionResults(
12911291
// ModuleFilename can be empty if something strange happened during
12921292
// module loading, for example, the module file is corrupted.
12931293
if (!ModuleFilename.empty()) {
1294+
llvm::SmallVector<std::string, 2> spiGroups;
1295+
for (auto Import : SF.getImports()) {
1296+
if (Import.module.importedModule == TheModule) {
1297+
for (auto SpiGroup : Import.spiGroups) {
1298+
spiGroups.push_back(SpiGroup.str().str());
1299+
}
1300+
break;
1301+
}
1302+
}
1303+
llvm::sort(spiGroups);
12941304
CodeCompletionCache::Key K{
12951305
ModuleFilename.str(),
12961306
std::string(TheModule->getName()),
@@ -1302,6 +1312,7 @@ void swift::ide::deliverCompletionResults(
13021312
SF.hasTestableOrPrivateImport(
13031313
AccessLevel::Internal, TheModule,
13041314
SourceFile::ImportQueryKind::PrivateOnly),
1315+
spiGroups,
13051316
CompletionContext.getAddInitsToTopLevel(),
13061317
CompletionContext.addCallWithNoDefaultArgs(),
13071318
CompletionContext.getAnnotateResult()};
@@ -1341,9 +1352,12 @@ void swift::ide::deliverCompletionResults(
13411352
// Add results for all imported modules.
13421353
SmallVector<ImportedModule, 4> Imports;
13431354
SF.getImportedModules(
1344-
Imports, {ModuleDecl::ImportFilterKind::Exported,
1345-
ModuleDecl::ImportFilterKind::Default,
1346-
ModuleDecl::ImportFilterKind::ImplementationOnly});
1355+
Imports, {
1356+
ModuleDecl::ImportFilterKind::Exported,
1357+
ModuleDecl::ImportFilterKind::Default,
1358+
ModuleDecl::ImportFilterKind::ImplementationOnly,
1359+
ModuleDecl::ImportFilterKind::SPIAccessControl,
1360+
});
13471361

13481362
for (auto Imported : Imports) {
13491363
for (auto Import : namelookup::getAllImports(Imported.importedModule))

lib/IDE/CodeCompletionCache.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,12 @@ static std::string getName(StringRef cacheDirectory,
475475
<< (K.AddInitsInToplevel ? "-inits" : "")
476476
<< (K.AddCallWithNoDefaultArgs ? "-nodefaults" : "")
477477
<< (K.Annotated ? "-annotated" : "");
478+
if (K.SpiGroups.size() > 0) {
479+
OSS << "-spi";
480+
for (auto SpiGroup : K.SpiGroups) {
481+
OSS << "-" << SpiGroup;
482+
}
483+
}
478484

479485
// name[-access-path-components]
480486
for (StringRef component : K.AccessPath)
@@ -539,9 +545,16 @@ OnDiskCodeCompletionCache::getFromFile(StringRef filename) {
539545
return None;
540546

541547
// Make up a key for readCachedModule.
542-
CodeCompletionCache::Key K{filename.str(), "<module-name>", {},
543-
false, false, false,
544-
false, false, false};
548+
CodeCompletionCache::Key K{/*ModuleFilename=*/filename.str(),
549+
/*ModuleName=*/"<module-name>",
550+
/*AccessPath=*/{},
551+
/*ResultsHaveLeadingDot=*/false,
552+
/*ForTestableLookup=*/false,
553+
/*ForPrivateImportLookup=*/false,
554+
/*SpiGroups=*/{},
555+
/*AddInitsInToplevel=*/false,
556+
/*AddCallWithNoDefaultArgs=*/false,
557+
/*Annotated=*/false};
545558

546559
// Read the cached results.
547560
auto V = CodeCompletionCache::createValue();
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: %empty-directory(%t/split)
2+
// RUN: %empty-directory(%t/build)
3+
// RUN: %{python} %utils/split_file.py -o %t/split %s
4+
5+
// RUN: %target-swift-frontend -emit-module -o %t/build %t/split/pck.swift
6+
7+
// First SPI completion then completion in file without SPI import
8+
// RUN: %empty-directory(%t/cc-cache)
9+
// RUN: %target-swift-ide-test -code-completion -completion-cache-path %t/cc-cache -source-filename %t/split/with-spi-import.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s --check-prefix=WITH_SPI
10+
// RUN: %target-swift-ide-test -code-completion -completion-cache-path %t/cc-cache -source-filename %t/split/with-different-spi-import.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s --check-prefix=WITHOUT_SPI
11+
// RUN: %target-swift-ide-test -code-completion -completion-cache-path %t/cc-cache -source-filename %t/split/with-normal-import.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s --check-prefix=WITHOUT_SPI
12+
13+
// First completion in file without SPI import, then with SPI import
14+
// RUN: %empty-directory(%t/cc-cache)
15+
// RUN: %target-swift-ide-test -code-completion -completion-cache-path %t/cc-cache -source-filename %t/split/with-normal-import.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s --check-prefix=WITHOUT_SPI
16+
// RUN: %target-swift-ide-test -code-completion -completion-cache-path %t/cc-cache -source-filename %t/split/with-different-spi-import.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s --check-prefix=WITHOUT_SPI
17+
// RUN: %target-swift-ide-test -code-completion -completion-cache-path %t/cc-cache -source-filename %t/split/with-spi-import.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s --check-prefix=WITH_SPI
18+
19+
// WITH_SPI: Begin completions
20+
// WITH_SPI-DAG: Decl[FreeFunction]/OtherModule[pck]: apiFunc()[#Void#]; name=apiFunc()
21+
// WITH_SPI-DAG: Decl[FreeFunction]/OtherModule[pck]: spiFunc()[#Void#]; name=spiFunc()
22+
// WITH_SPI: End completions
23+
24+
// WITHOUT_SPI: Begin completions
25+
// WITHOUT_SPI-NOT: spiFunc
26+
// WITHOUT_SPI-DAG: Decl[FreeFunction]/OtherModule[pck]: apiFunc()[#Void#]; name=apiFunc()
27+
// WITHOUT_SPI-NOT: spiFunc
28+
// WITHOUT_SPI: End completions
29+
30+
31+
// BEGIN pck.swift
32+
33+
public func apiFunc() {}
34+
35+
@_spi(MySPI)
36+
public func spiFunc() {}
37+
38+
// BEGIN with-spi-import.swift
39+
40+
@_spi(MySPI) import pck
41+
42+
func test() {
43+
#^COMPLETE^#
44+
}
45+
46+
// BEGIN with-different-spi-import.swift
47+
48+
@_spi(OtherSPI) import pck
49+
50+
func test() {
51+
#^COMPLETE^#
52+
}
53+
54+
55+
// BEGIN with-normal-import.swift
56+
57+
import pck
58+
59+
func test() {
60+
#^COMPLETE^#
61+
}

0 commit comments

Comments
 (0)