Skip to content

Commit b640033

Browse files
committed
[CodeCompletion] Suggest #selector and #keyPath after # only if applicable
Also, add type annotation, and make it `TypeRelation[Identical]`. 'ExprSpecific' is too strong. (cherry picked from commit e2a4621)
1 parent a534050 commit b640033

File tree

4 files changed

+80
-56
lines changed

4 files changed

+80
-56
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,37 +2248,29 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
22482248
// #selector is only available when the Objective-C runtime is.
22492249
if (!Ctx.LangOpts.EnableObjCInterop) return;
22502250

2251-
// After #, this is a very likely result. When just in a String context,
2252-
// it's not.
2253-
auto semanticContext = needPound ? SemanticContextKind::None
2254-
: SemanticContextKind::ExpressionSpecific;
2255-
22562251
CodeCompletionResultBuilder Builder(
2257-
Sink,
2258-
CodeCompletionResult::ResultKind::Keyword,
2259-
semanticContext, expectedTypeContext);
2252+
Sink, CodeCompletionResult::ResultKind::Keyword,
2253+
SemanticContextKind::None, {});
22602254
if (needPound)
22612255
Builder.addTextChunk("#selector");
22622256
else
22632257
Builder.addTextChunk("selector");
22642258
Builder.addLeftParen();
22652259
Builder.addSimpleTypedParameter("@objc method", /*IsVarArg=*/false);
22662260
Builder.addRightParen();
2261+
Builder.addTypeAnnotation("Selector");
2262+
// This function is called only if the context type is 'Selector'.
2263+
Builder.setExpectedTypeRelation(
2264+
CodeCompletionResult::ExpectedTypeRelation::Identical);
22672265
}
22682266

22692267
void addPoundKeyPath(bool needPound) {
22702268
// #keyPath is only available when the Objective-C runtime is.
22712269
if (!Ctx.LangOpts.EnableObjCInterop) return;
22722270

2273-
// After #, this is a very likely result. When just in a String context,
2274-
// it's not.
2275-
auto semanticContext = needPound ? SemanticContextKind::None
2276-
: SemanticContextKind::ExpressionSpecific;
2277-
22782271
CodeCompletionResultBuilder Builder(
2279-
Sink,
2280-
CodeCompletionResult::ResultKind::Keyword,
2281-
semanticContext, expectedTypeContext);
2272+
Sink, CodeCompletionResult::ResultKind::Keyword,
2273+
SemanticContextKind::None, {});
22822274
if (needPound)
22832275
Builder.addTextChunk("#keyPath");
22842276
else
@@ -2287,6 +2279,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
22872279
Builder.addSimpleTypedParameter("@objc property sequence",
22882280
/*IsVarArg=*/false);
22892281
Builder.addRightParen();
2282+
Builder.addTypeAnnotation("String");
2283+
// This function is called only if the context type is 'String'.
2284+
Builder.setExpectedTypeRelation(
2285+
CodeCompletionResult::ExpectedTypeRelation::Identical);
22902286
}
22912287

22922288
SemanticContextKind getSemanticContextKind(const ValueDecl *VD) {
@@ -3682,6 +3678,38 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36823678
}
36833679
}
36843680

3681+
void addObjCPoundKeywordCompletions(bool needPound) {
3682+
if (!Ctx.LangOpts.EnableObjCInterop)
3683+
return;
3684+
3685+
// If the expected type is ObjectiveC.Selector, add #selector. If
3686+
// it's String, add #keyPath.
3687+
bool addedSelector = false;
3688+
bool addedKeyPath = false;
3689+
3690+
for (auto T : expectedTypeContext.possibleTypes) {
3691+
T = T->lookThroughAllOptionalTypes();
3692+
if (auto structDecl = T->getStructOrBoundGenericStruct()) {
3693+
if (!addedSelector && structDecl->getName() == Ctx.Id_Selector &&
3694+
structDecl->getParentModule()->getName() == Ctx.Id_ObjectiveC) {
3695+
addPoundSelector(needPound);
3696+
if (addedKeyPath)
3697+
break;
3698+
addedSelector = true;
3699+
continue;
3700+
}
3701+
}
3702+
3703+
if (!addedKeyPath && T->getAnyNominal() == Ctx.getStringDecl()) {
3704+
addPoundKeyPath(needPound);
3705+
if (addedSelector)
3706+
break;
3707+
addedKeyPath = true;
3708+
continue;
3709+
}
3710+
}
3711+
}
3712+
36853713
struct FilteredDeclConsumer : public swift::VisibleDeclConsumer {
36863714
swift::VisibleDeclConsumer &Consumer;
36873715
DeclFilter Filter;
@@ -3745,33 +3773,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
37453773
addPoundLiteralCompletions(/*needPound=*/true);
37463774
}
37473775

3748-
3749-
// If the expected type is ObjectiveC.Selector, add #selector. If
3750-
// it's String, add #keyPath.
3751-
if (Ctx.LangOpts.EnableObjCInterop) {
3752-
bool addedSelector = false;
3753-
bool addedKeyPath = false;
3754-
for (auto T : expectedTypeContext.possibleTypes) {
3755-
T = T->lookThroughAllOptionalTypes();
3756-
if (auto structDecl = T->getStructOrBoundGenericStruct()) {
3757-
if (!addedSelector &&
3758-
structDecl->getName() == Ctx.Id_Selector &&
3759-
structDecl->getParentModule()->getName() == Ctx.Id_ObjectiveC) {
3760-
addPoundSelector(/*needPound=*/true);
3761-
if (addedKeyPath) break;
3762-
addedSelector = true;
3763-
continue;
3764-
}
3765-
}
3766-
3767-
if (!addedKeyPath && T->getAnyNominal() == Ctx.getStringDecl()) {
3768-
addPoundKeyPath(/*needPound=*/true);
3769-
if (addedSelector) break;
3770-
addedKeyPath = true;
3771-
continue;
3772-
}
3773-
}
3774-
}
3776+
addObjCPoundKeywordCompletions(/*needPound=*/true);
37753777
}
37763778

37773779
void getUnresolvedMemberCompletions(Type T) {
@@ -5478,8 +5480,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
54785480

54795481
Lookup.addPoundAvailable(ParentStmtKind);
54805482
Lookup.addPoundLiteralCompletions(/*needPound=*/false);
5481-
Lookup.addPoundSelector(/*needPound=*/false);
5482-
Lookup.addPoundKeyPath(/*needPound=*/false);
5483+
Lookup.addObjCPoundKeywordCompletions(/*needPound=*/false);
54835484
break;
54845485
}
54855486

test/IDE/complete_pound_expr.swift

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,42 @@
1-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POUND_EXPR_1 | %FileCheck %s -check-prefix=POUND_EXPR_STRINGCONTEXT
1+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POUND_EXPR_1 | %FileCheck %s -check-prefix=POUND_EXPR_INTCONTEXT
2+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POUND_EXPR_2 | %FileCheck %s -check-prefix=POUND_EXPR_STRINGCONTEXT
3+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POUND_EXPR_3 | %FileCheck %s -check-prefix=POUND_EXPR_SELECTORCONTEXT
24
// REQUIRES: objc_interop
35

4-
func use(_ str: String) -> Bool {}
6+
import ObjectiveC
7+
8+
func useInt(_ str: Int) -> Bool {}
9+
func useString(_ str: String) -> Bool {}
10+
func useSelector(_ sel: Selector) -> Bool {}
511

612
func test1() {
7-
_ = use(##^POUND_EXPR_1^#)
13+
let _ = useInt(##^POUND_EXPR_1^#)
14+
let _ = useString(##^POUND_EXPR_2^#)
15+
let _ = useSelector(##^POUND_EXPR_3^#)
816
}
917

10-
// POUND_EXPR_STRINGCONTEXT: Begin completions, 7 items
11-
// POUND_EXPR_STRINGCONTEXT-NOT: available
18+
// POUND_EXPR_INTCONTEXT: Begin completions, 5 items
19+
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#function]/None: function[#String#]; name=function
20+
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#file]/None: file[#String#]; name=file
21+
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#line]/None/TypeRelation[Identical]: line[#Int#]; name=line
22+
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#column]/None/TypeRelation[Identical]: column[#Int#]; name=column
23+
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#dsohandle]/None: dsohandle[#UnsafeRawPointer#]; name=dsohandle
24+
// POUND_EXPR_INTCONTEXT: End completions
25+
26+
// POUND_EXPR_STRINGCONTEXT: Begin completions, 6 items
1227
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#function]/None/TypeRelation[Identical]: function[#String#];
1328
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#file]/None/TypeRelation[Identical]: file[#String#];
1429
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#line]/None: line[#Int#];
1530
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#column]/None: column[#Int#];
1631
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#dsohandle]/None: dsohandle[#UnsafeRawPointer#];
17-
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword/ExprSpecific: selector({#@objc method#});
18-
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword/ExprSpecific: keyPath({#@objc property sequence#});
32+
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword/None/TypeRelation[Identical]: keyPath({#@objc property sequence#})[#String#];
1933
// POUND_EXPR_STRINGCONTEXT: End completions
34+
35+
// POUND_EXPR_SELECTORCONTEXT: Begin completions, 6 items
36+
// POUND_EXPR_SELECTORCONTEXT-DAG: Keyword[#function]/None/TypeRelation[Identical]: function[#Selector#];
37+
// POUND_EXPR_SELECTORCONTEXT-DAG: Keyword[#file]/None/TypeRelation[Identical]: file[#Selector#];
38+
// POUND_EXPR_SELECTORCONTEXT-DAG: Keyword[#line]/None: line[#Int#];
39+
// POUND_EXPR_SELECTORCONTEXT-DAG: Keyword[#column]/None: column[#Int#];
40+
// POUND_EXPR_SELECTORCONTEXT-DAG: Keyword[#dsohandle]/None: dsohandle[#UnsafeRawPointer#];
41+
// POUND_EXPR_SELECTORCONTEXT-DAG: Keyword/None/TypeRelation[Identical]: selector({#@objc method#})[#Selector#];
42+
// POUND_EXPR_SELECTORCONTEXT: End completions

test/IDE/complete_pound_keypath.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ func completeInKeyPath2() {
3434
_ = #keyPath(ObjCClass.#^IN_KEYPATH_2^#
3535
}
3636

37-
// CHECK-AFTER_POUND: Keyword/ExprSpecific: keyPath({#@objc property sequence#}); name=keyPath(@objc property sequence)
37+
// CHECK-AFTER_POUND-NOT: keyPath
3838

39-
// CHECK-KEYPATH_ARG: Keyword/None: #keyPath({#@objc property sequence#}); name=#keyPath(@objc property sequence)
39+
// CHECK-KEYPATH_ARG: Keyword/None/TypeRelation[Identical]: #keyPath({#@objc property sequence#})[#String#]; name=#keyPath(@objc property sequence)
4040

4141
// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop1[#String#]; name=prop1
4242
// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop2[#ObjCClass?#]; name=prop2

test/IDE/complete_pound_selector.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ class Subclass : NSObject {
7171
}
7272

7373

74+
// CHECK-AFTER_POUND-NOT: selector
7475
// CHECK-AFTER_POUND: Keyword/ExprSpecific: available({#Platform...#}, *); name=available(Platform..., *)
75-
// CHECK-AFTER_POUND: Keyword/ExprSpecific: selector({#@objc method#}); name=selector(@objc method)
7676

77-
// CHECK-CONTEXT_SELECTOR: Keyword/None: #selector({#@objc method#}); name=#selector(@objc method)
77+
// CHECK-CONTEXT_SELECTOR: Keyword/None/TypeRelation[Identical]: #selector({#@objc method#})[#Selector#]; name=#selector(@objc method)
7878

7979
// CHECK-SELECTOR_BASIC: Keyword/None: getter: {#@objc property#}; name=getter: @objc property
8080
// CHECK-SELECTOR_BASIC: Keyword/None: setter: {#@objc property#}; name=setter: @objc property

0 commit comments

Comments
 (0)