Skip to content

Commit 6c2ec9a

Browse files
committed
[CodeCompletion] Do our best to set NotRecommended on other-module results
These results are cached, so we can't use the type-relation. Instead we use a small hack of checking the textual return type for "Void". This is obviously not ideal, but it lets us detect the most important cases. rdar://problem/22810741
1 parent 379f2b9 commit 6c2ec9a

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

test/SourceKit/CodeComplete/complete_cache.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,36 @@ import Foo
1313
// RUN: FileCheck %s < %t.completions1
1414
// RUN: FileCheck %s < %t.completions2
1515
// CHECK: key.name: "FooStruct
16+
17+
// RUN: %complete-test -raw -tok=VOID_1 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=VOID_1
18+
// RUN: %complete-test -raw -tok=VOID_2 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=VOID_1
19+
// RUN: %complete-test -raw -tok=VOID_3 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=VOID_3
20+
func test1() {
21+
_ = #^VOID_1,fooFunc^#
22+
}
23+
func test2() {
24+
for i in 1...#^VOID_2,fooFunc^# {}
25+
}
26+
// VOID_1: key.name: "fooHelperSubFunc1(:)",
27+
// VOID_1-NEXT: key.sourcetext:
28+
// VOID_1-NEXT: key.description:
29+
// VOID_1-NEXT: key.typename: "Int32",
30+
// VOID_1-NEXT: key.context: source.codecompletion.context.othermodule,
31+
// VOID_1-NEXT: key.moduleimportdepth: 2,
32+
// VOID_1-NEXT: key.num_bytes_to_erase: 0,
33+
// VOID_1-NEXT: key.substructure:
34+
35+
// VOID_1: key.name: "fooFuncNoreturn1()",
36+
// VOID_1-NEXT: key.sourcetext:
37+
// VOID_1-NEXT: key.description:
38+
// VOID_1-NEXT: key.typename: "Void",
39+
// VOID_1-NEXT: key.context: source.codecompletion.context.othermodule,
40+
// VOID_1-NEXT: key.moduleimportdepth: 1,
41+
// VOID_1-NEXT: key.num_bytes_to_erase: 0,
42+
// VOID_1-NEXT: key.not_recommended: 1,
43+
// VOID_1-NEXT: key.substructure:
44+
45+
func test3() {
46+
#^VOID_3,fooFunc^# {}
47+
}
48+
// VOID_3-NOT: key.not_recommended

tools/SourceKit/lib/SwiftLang/CodeCompletion.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class CompletionBuilder {
123123
CompletionSink &sink;
124124
SwiftResult &current;
125125
bool modified = false;
126+
bool isNotRecommended;
127+
Completion::NotRecommendedReason notRecommendedReason;
126128
SemanticContextKind semanticContext;
127129
CodeCompletionString *completionString;
128130
llvm::SmallVector<char, 64> originalName;
@@ -145,6 +147,13 @@ class CompletionBuilder {
145147
moduleImportDepth = value;
146148
}
147149

150+
void setNotRecommended(Completion::NotRecommendedReason Reason) {
151+
modified = true;
152+
notRecommendedReason = Reason;
153+
if (Reason != Completion::NoReason)
154+
isNotRecommended = true;
155+
}
156+
148157
void setSemanticContext(SemanticContextKind kind) {
149158
modified = true;
150159
semanticContext = kind;

tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,24 @@ std::vector<Completion *> SourceKit::CodeCompletion::extendCompletions(
100100
std::vector<Completion *> results;
101101
for (auto *result : swiftResults) {
102102
CompletionBuilder builder(sink, *result);
103-
if (result->getSemanticContext() == SemanticContextKind::OtherModule)
103+
if (result->getSemanticContext() == SemanticContextKind::OtherModule) {
104104
builder.setModuleImportDepth(depth.lookup(result->getModuleName()));
105105

106+
if (info.completionContext->HasExpectedTypeRelation &&
107+
result->getKind() == Completion::Declaration) {
108+
// FIXME: because other-module results are cached, they will not be
109+
// given a type-relation of invalid. As a hack, we look at the text of
110+
// the result type and look for 'Void'.
111+
for (auto &chunk : result->getCompletionString()->getChunks()) {
112+
using ChunkKind = ide::CodeCompletionString::Chunk::ChunkKind;
113+
if (chunk.is(ChunkKind::TypeAnnotation) && chunk.hasText() &&
114+
chunk.getText() == "Void") {
115+
builder.setNotRecommended(Completion::TypeMismatch);
116+
}
117+
}
118+
}
119+
}
120+
106121
if (prefix) {
107122
builder.setPrefix(prefix->getCompletionString());
108123
builder.setSemanticContext(prefix->getSemanticContext());
@@ -1116,6 +1131,8 @@ void CompletionBuilder::getDescription(SwiftResult *result, raw_ostream &OS,
11161131

11171132
CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base)
11181133
: sink(sink), current(base) {
1134+
isNotRecommended = current.isNotRecommended();
1135+
notRecommendedReason = current.getNotRecommendedReason();
11191136
semanticContext = current.getSemanticContext();
11201137
completionString =
11211138
const_cast<CodeCompletionString *>(current.getCompletionString());
@@ -1158,8 +1175,8 @@ Completion *CompletionBuilder::finish() {
11581175
if (current.getKind() == SwiftResult::Declaration) {
11591176
base = SwiftResult(semanticContext, current.getNumBytesToErase(),
11601177
completionString, current.getAssociatedDeclKind(),
1161-
current.getModuleName(), current.isNotRecommended(),
1162-
current.getNotRecommendedReason(),
1178+
current.getModuleName(), isNotRecommended,
1179+
notRecommendedReason,
11631180
current.getBriefDocComment(),
11641181
current.getAssociatedUSRs(),
11651182
current.getDeclKeywords());

0 commit comments

Comments
 (0)