Skip to content

Commit 122350d

Browse files
committed
[CodeCompletion] Apply filter rules directly to inner results
... and don't try to filter the extended results. Once the results are extended with the common prefix they will not match identifier filter rules, which will create differences between completions depending on whether they had a filter text or were a postfix expression. Also, allow filtering by name directly on the inner operator name for inner operators. rdar://problem/26312235
1 parent 92f1da4 commit 122350d

File tree

6 files changed

+163
-17
lines changed

6 files changed

+163
-17
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
key.kind: source.codecompletion.identifier,
4+
key.hide: 1,
5+
key.names: [".", "?.", "("]
6+
}
7+
]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[
2+
{
3+
key.kind: source.codecompletion.everything,
4+
key.hide: 1
5+
},
6+
{
7+
key.kind: source.codecompletion.identifier,
8+
key.hide: 0,
9+
key.names: ["local", ".", "="]
10+
},
11+
{
12+
key.kind: source.codecompletion.module,
13+
key.hide: 0,
14+
key.names: ["Swift"]
15+
}
16+
]

test/SourceKit/CodeComplete/complete_filter_rules.swift

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,99 @@ func testShowSpecific01() {
8585
// SHOW_SPECIFIC_1-NEXT: myFunFunction1()
8686
// SHOW_SPECIFIC_1-NEXT: ]
8787
}
88+
89+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showSpecific.json -tok=HIDE_OP_1 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP
90+
func testHideOp1() {
91+
var local = 1
92+
#^HIDE_OP_1,local^#
93+
}
94+
// HIDE_OP-NOT: .
95+
// HIDE_OP-NOT: =
96+
97+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showSpecific.json -tok=HIDE_OP_2 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP -allow-empty
98+
func testHideOp2() {
99+
var local = 1
100+
local#^HIDE_OP_2^#
101+
}
102+
103+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showOp.json -tok=SHOW_OP_1 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=SHOW_OP_1
104+
func testShowOp1() {
105+
var local = 1
106+
#^SHOW_OP_1,local^#
107+
}
108+
// SHOW_OP_1: local.{{$}}
109+
// SHOW_OP_1: local={{$}}
110+
111+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showOp.json -tok=SHOW_OP_2 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=SHOW_OP_2
112+
func testShowOp2() {
113+
var local = 1
114+
local#^SHOW_OP_2^#
115+
}
116+
// SHOW_OP_2: {{^}}.{{$}}
117+
// SHOW_OP_2: {{^}}={{$}}
118+
119+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showOp.json -tok=HIDE_OP_3 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP
120+
func testHideOp3() {
121+
let local = TestHideName()
122+
// Implicitly hidden because we hide all the members.
123+
#^HIDE_OP_3,local^#
124+
}
125+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showOp.json -tok=HIDE_OP_4 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP -allow-empty
126+
func testHideOp4() {
127+
let local = TestHideName()
128+
// Implicitly hidden because we hide all the members.
129+
local#^HIDE_OP_4^#
130+
}
131+
132+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showOp.json -tok=SHOW_OP_3 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=SHOW_OP_1
133+
func testShowOp3() {
134+
var local = 1
135+
#^SHOW_OP_3,local^#
136+
}
137+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showOp.json -tok=SHOW_OP_4 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=SHOW_OP_2
138+
func testShowOp4() {
139+
var local = 1
140+
local#^SHOW_OP_4^#
141+
}
142+
143+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideInnerOp.json -tok=HIDE_OP_5 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP_5 -allow-empty
144+
func testHideOp5() {
145+
var local = 1
146+
#^HIDE_OP_5,local^#
147+
}
148+
// HIDE_OP_5-NOT: local.{{$}}
149+
// HIDE_OP_5-NOT: local?.
150+
// HIDE_OP_5-NOT: local(
151+
152+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideInnerOp.json -tok=HIDE_OP_6 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP_5 -allow-empty
153+
func testHideOp6() {
154+
var local: Int? = 1
155+
#^HIDE_OP_6,local^#
156+
}
157+
158+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideInnerOp.json -tok=HIDE_OP_7 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP_5 -allow-empty
159+
func testHideOp7() {
160+
struct local {}
161+
#^HIDE_OP_7,local^#
162+
}
163+
164+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideInnerOp.json -tok=HIDE_OP_8 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP_8 -allow-empty
165+
func testHideOp8() {
166+
var local = 1
167+
local#^HIDE_OP_8^#
168+
}
169+
// HIDE_OP_8-NOT: {{^}}.{{$}}
170+
// HIDE_OP_8-NOT: {{^}}?.
171+
// HIDE_OP_8-NOT: {{^}}(
172+
173+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideInnerOp.json -tok=HIDE_OP_9 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP_8 -allow-empty
174+
func testHideOp9() {
175+
var local: Int? = 1
176+
local#^HIDE_OP_9^#
177+
}
178+
179+
// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideInnerOp.json -tok=HIDE_OP_10 %s -- -F %S/../Inputs/libIDE-mock-sdk | FileCheck %s -check-prefix=HIDE_OP_8 -allow-empty
180+
func testHideOp10() {
181+
struct local {}
182+
local#^HIDE_OP_10^#
183+
}

tools/SourceKit/lib/SwiftLang/CodeCompletion.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ struct FilterRules {
234234
llvm::StringMap<bool> hideByName;
235235

236236
bool hideCompletion(Completion *completion) const;
237+
bool hideCompletion(SwiftResult *completion,
238+
StringRef name,
239+
void *customKind = nullptr) const;
240+
bool hideName(StringRef name) const;
237241
};
238242

239243
} // end namespace CodeCompletion

tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,21 @@ static bool isHighPriorityKeyword(CodeCompletionKeywordKind kind) {
447447
}
448448
}
449449

450+
bool FilterRules::hideName(StringRef name) const {
451+
auto I = hideByName.find(name);
452+
if (I != hideByName.end())
453+
return I->getValue();
454+
return hideAll;
455+
}
456+
450457
bool FilterRules::hideCompletion(Completion *completion) const {
458+
return hideCompletion(completion, completion->getName(), completion->getCustomKind());
459+
}
460+
461+
bool FilterRules::hideCompletion(SwiftResult *completion, StringRef name, void *customKind) const {
451462

452-
if (!completion->getName().empty()) {
453-
auto I = hideByName.find(completion->getName());
463+
if (!name.empty()) {
464+
auto I = hideByName.find(name);
454465
if (I != hideByName.end())
455466
return I->getValue();
456467
}
@@ -468,7 +479,7 @@ bool FilterRules::hideCompletion(Completion *completion) const {
468479
break;
469480
}
470481
case Completion::Pattern: {
471-
if (completion->hasCustomKind()) {
482+
if (customKind) {
472483
// FIXME: individual custom completions
473484
if (hideCustomCompletions)
474485
return true;

tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -928,14 +928,24 @@ template <typename Result>
928928
static std::vector<Result *>
929929
filterInnerResults(ArrayRef<Result *> results, bool includeInner,
930930
bool includeInnerOperators,
931-
932-
bool &hasDot, bool &hasQDot, bool &hasInit) {
931+
bool &hasDot, bool &hasQDot, bool &hasInit,
932+
const CodeCompletion::FilterRules &rules) {
933933
std::vector<Result *> topResults;
934934
for (auto *result : results) {
935935
if (!includeInnerOperators && result->isOperator())
936936
continue;
937937

938+
llvm::SmallString<64> name;
939+
{
940+
llvm::raw_svector_ostream OSS(name);
941+
CodeCompletion::CompletionBuilder::getFilterName(
942+
result->getCompletionString(), OSS);
943+
}
944+
if (rules.hideCompletion(result, name))
945+
continue;
946+
938947
bool inner = checkInnerResult(result, hasDot, hasQDot, hasInit);
948+
939949
if (!inner ||
940950
(includeInner &&
941951
result->getSemanticContext() <= SemanticContextKind::CurrentNominal))
@@ -989,13 +999,14 @@ static void transformAndForwardResults(
989999
options, session->getCompletionKind(),
9901000
session->getCompletionHasExpectedTypes());
9911001

1002+
auto &rules = session->getFilterRules();
1003+
9921004
bool hasEarlyInnerResults =
9931005
session->getCompletionKind() == CompletionKind::PostfixExpr;
9941006

9951007
if (!hasEarlyInnerResults) {
9961008
organizer.addCompletionsWithFilter(session->getSortedCompletions(),
997-
filterText, session->getFilterRules(),
998-
exactMatch);
1009+
filterText, rules, exactMatch);
9991010
}
10001011

10011012
if (hasEarlyInnerResults &&
@@ -1006,18 +1017,19 @@ static void transformAndForwardResults(
10061017
auto completions = session->getSortedCompletions();
10071018
auto innerResults =
10081019
filterInnerResults(completions, options.addInnerResults,
1009-
options.addInnerOperators, hasDot, hasQDot, hasInit);
1020+
options.addInnerOperators, hasDot, hasQDot, hasInit,
1021+
rules);
10101022
if (options.addInnerOperators) {
1011-
if (hasInit)
1023+
if (hasInit && !rules.hideName("("))
10121024
innerResults.insert(innerResults.begin(), buildParen());
1013-
if (hasDot)
1025+
if (hasDot && !rules.hideName("."))
10141026
innerResults.insert(innerResults.begin(), buildDot());
1015-
if (hasQDot)
1027+
if (hasQDot && !rules.hideName("?."))
10161028
innerResults.insert(innerResults.begin(), buildQDot());
10171029
}
10181030

10191031
organizer.addCompletionsWithFilter(innerResults, filterText,
1020-
session->getFilterRules(), exactMatch);
1032+
CodeCompletion::FilterRules(), exactMatch);
10211033
}
10221034

10231035
organizer.groupAndSort(options);
@@ -1033,7 +1045,7 @@ static void transformAndForwardResults(
10331045
SwiftCompletionInfo &info) {
10341046
auto topResults = filterInnerResults(results, options.addInnerResults,
10351047
options.addInnerOperators, hasDot,
1036-
hasQDot, hasInit);
1048+
hasQDot, hasInit, rules);
10371049
// FIXME: Overriding the default to context "None" is a hack so that they
10381050
// won't overwhelm other results that also match the filter text.
10391051
innerResults = extendCompletions(
@@ -1063,18 +1075,18 @@ static void transformAndForwardResults(
10631075
}
10641076

10651077
if (options.addInnerOperators) {
1066-
if (hasInit)
1078+
if (hasInit && !rules.hideName("("))
10671079
innerResults.insert(innerResults.begin(), buildParen());
1068-
if (hasDot)
1080+
if (hasDot && !rules.hideName("."))
10691081
innerResults.insert(innerResults.begin(), buildDot());
1070-
if (hasQDot)
1082+
if (hasQDot && !rules.hideName("?."))
10711083
innerResults.insert(innerResults.begin(), buildQDot());
10721084
}
10731085

10741086
// Add the inner results (and don't filter them).
10751087
exactMatch = nullptr; // No longer needed.
10761088
organizer.addCompletionsWithFilter(innerResults, filterText,
1077-
session->getFilterRules(), exactMatch);
1089+
CodeCompletion::FilterRules(), exactMatch);
10781090

10791091
CodeCompletion::Options noGroupOpts = options;
10801092
noGroupOpts.groupStems = false;

0 commit comments

Comments
 (0)