Skip to content

Commit 7407a80

Browse files
rintarorjmccall
authored andcommitted
[CodeCompletion] Postfix expr completion after trailing closures
1 parent 7cb5066 commit 7407a80

File tree

5 files changed

+69
-12
lines changed

5 files changed

+69
-12
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5948,8 +5948,37 @@ void CodeCompletionCallbacksImpl::doneParsing() {
59485948
DoPostfixExprBeginning();
59495949
} else {
59505950
// foo() {} <HERE>
5951-
// Member completion
5952-
// TODO: Member completion.
5951+
// Member completion.
5952+
Expr *analyzedExpr = ContextInfo.getAnalyzedExpr();
5953+
if (!analyzedExpr)
5954+
break;
5955+
5956+
// Only if the completion token is the last token in the call.
5957+
if (analyzedExpr->getEndLoc() != CodeCompleteTokenExpr->getLoc())
5958+
break;
5959+
5960+
// If the call expression doesn't have a type, infer it from the
5961+
// possible callee info.
5962+
Type resultTy = analyzedExpr->getType();
5963+
if (!resultTy) {
5964+
if (ContextInfo.getPossibleCallees().empty())
5965+
break;
5966+
auto calleeInfo = ContextInfo.getPossibleCallees()[0];
5967+
resultTy = calleeInfo.Type->getResult();
5968+
analyzedExpr->setType(resultTy);
5969+
}
5970+
5971+
auto &SM = CurDeclContext->getASTContext().SourceMgr;
5972+
auto leadingChar =
5973+
SM.extractText({SM.getCodeCompletionLoc().getAdvancedLoc(-1), 1});
5974+
Lookup.setHaveLeadingSpace(leadingChar.find_first_of(" \t\f\v") !=
5975+
StringRef::npos);
5976+
5977+
if (isDynamicLookup(resultTy))
5978+
Lookup.setIsDynamicLookup();
5979+
Lookup.getValueExprCompletions(resultTy, /*VD=*/nullptr);
5980+
Lookup.getOperatorCompletions(analyzedExpr, leadingSequenceExprs);
5981+
Lookup.getPostfixKeywordCompletions(resultTy, analyzedExpr);
59535982
}
59545983
}
59555984
break;

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ class ExprContextAnalyzer {
573573
SmallVectorImpl<Type> &PossibleTypes;
574574
SmallVectorImpl<PossibleParamInfo> &PossibleParams;
575575
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees;
576+
Expr *&AnalyzedExpr;
576577
bool &singleExpressionBody;
577578

578579
void recordPossibleType(Type ty) {
@@ -674,6 +675,7 @@ class ExprContextAnalyzer {
674675
}
675676

676677
void analyzeExpr(Expr *Parent) {
678+
AnalyzedExpr = Parent;
677679
switch (Parent->getKind()) {
678680
case ExprKind::Call:
679681
case ExprKind::Subscript:
@@ -936,10 +938,11 @@ class ExprContextAnalyzer {
936938
DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl<Type> &PossibleTypes,
937939
SmallVectorImpl<PossibleParamInfo> &PossibleArgs,
938940
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees,
939-
bool &singleExpressionBody)
941+
Expr *&AnalyzedExpr, bool &singleExpressionBody)
940942
: DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr),
941943
Context(DC->getASTContext()), PossibleTypes(PossibleTypes),
942944
PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees),
945+
AnalyzedExpr(AnalyzedExpr),
943946
singleExpressionBody(singleExpressionBody) {}
944947

945948
void Analyze() {
@@ -1048,7 +1051,8 @@ class ExprContextAnalyzer {
10481051

10491052
ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
10501053
ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams,
1051-
PossibleCallees, singleExpressionBody);
1054+
PossibleCallees, AnalyzedExpr,
1055+
singleExpressionBody);
10521056
Analyzer.Analyze();
10531057
}
10541058

lib/IDE/ExprContextAnalysis.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class ExprContextInfo {
7373
SmallVector<Type, 2> PossibleTypes;
7474
SmallVector<PossibleParamInfo, 2> PossibleParams;
7575
SmallVector<FunctionTypeAndDecl, 2> PossibleCallees;
76+
Expr *AnalyzedExpr = nullptr;
7677
bool singleExpressionBody = false;
7778

7879
public:
@@ -99,6 +100,10 @@ class ExprContextInfo {
99100
ArrayRef<FunctionTypeAndDecl> getPossibleCallees() const {
100101
return PossibleCallees;
101102
}
103+
104+
Expr *getAnalyzedExpr() const {
105+
return AnalyzedExpr;
106+
}
102107
};
103108

104109
/// Returns whether \p VD is referenceable with implicit member expression.

test/IDE/complete_multiple_trailingclosure.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,26 @@ func testGlobalFunc() {
3333
// GLOBALFUNC_AFTERLABEL-NOT: Begin completions
3434
}
3535

36+
struct SimpleEnum {
37+
case foo, bar
38+
39+
func enumFunc() {}
40+
static func + (lhs: SimpleEnum, rhs: SimpleEnum) -> SimpleEnum {}
41+
}
42+
3643
struct MyStruct {
37-
func method1(fn1: () -> Int, fn2: (() -> String)? = nil) {}
38-
func method1(fn1: () -> Int, fn2: Int = nil) {}
44+
func method1(fn1: () -> Int, fn2: (() -> String)? = nil) -> SimpleEnum {}
45+
func method1(fn1: () -> Int, fn2: Int = nil) -> SimpleEnum {}
3946
}
4047
func testMethod(value: MyStruct) {
4148
value.method1 {
4249
} #^METHOD_SAMELINE^#
4350
#^METHOD_NEWLINE^#
44-
// METHOD_SAMELINE: Begin completions, 1 items
51+
// METHOD_SAMELINE: Begin completions, 4 items
4552
// METHOD_SAMELINE-DAG: Pattern/ExprSpecific: {#fn2: (() -> String)?##() -> String#}[#(() -> String)?#];
53+
// METHOD_SAMELINE-DAG: Decl[InstanceMethod]/CurrNominal: .enumFunc()[#Void#];
54+
// METHOD_SAMELINE-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: [' ']+ {#SimpleEnum#}[#SimpleEnum#];
55+
// METHOD_SAMELINE-DAG: Keyword[self]/CurrNominal: .self[#SimpleEnum#];
4656
// METHOD_SAMELINE: End completions
4757

4858
// METHOD_NEWLINE: Begin completions
@@ -59,6 +69,8 @@ struct TestStruct {
5969
init(fn1: () -> Int) {}
6070
init(fn1: () -> Int, fn2: () -> String) {}
6171
init(fn1: () -> Int, fn3: () -> String) {}
72+
73+
func testStructMethod() {}
6274
}
6375

6476
func testOverloadedInit() {
@@ -67,9 +79,11 @@ func testOverloadedInit() {
6779
} #^INIT_OVERLOADED_SAMELINE^#
6880
#^INIT_OVERLOADED_NEWLINE^#
6981

70-
// INIT_OVERLOADED_SAMELINE: Begin completions, 2 items
82+
// INIT_OVERLOADED_SAMELINE: Begin completions, 4 items
7183
// INIT_OVERLOADED_SAMELINE-DAG: Pattern/ExprSpecific: {#fn2: () -> String##() -> String#}[#() -> String#];
7284
// INIT_OVERLOADED_SAMELINE-DAG: Pattern/ExprSpecific: {#fn3: () -> String##() -> String#}[#() -> String#];
85+
// INIT_OVERLOADED_SAMELINE-DAG: Decl[InstanceMethod]/CurrNominal: .testStructMethod()[#Void#];
86+
// INIT_OVERLOADED_SAMELINE-DAG: Keyword[self]/CurrNominal: .self[#TestStruct#];
7387
// INIT_OVERLOADED_SAMELINE: End completions
7488

7589
// INIT_OVERLOADED_NEWLINE: Begin completions
@@ -84,16 +98,19 @@ func testOverloadedInit() {
8498

8599
struct TestStruct2 {
86100
init(fn1: () -> Int, fn2: () -> String = {}, fn3: () -> String = {}) {}
101+
func testStructMethod() {}
87102
}
88103
func testOptionalInit() {
89104
TestStruct2 {
90105
2
91106
} #^INIT_OPTIONAL_SAMELINE^#
92107
#^INIT_OPTIONAL_NEWLINE^#
93108

94-
// INIT_OPTIONAL_SAMELINE: Begin completions, 2 items
109+
// INIT_OPTIONAL_SAMELINE: Begin completions, 4 items
95110
// INIT_OPTIONAL_SAMELINE-DAG: Pattern/ExprSpecific: {#fn2: () -> String##() -> String#}[#() -> String#];
96111
// INIT_OPTIONAL_SAMELINE-DAG: Pattern/ExprSpecific: {#fn3: () -> String##() -> String#}[#() -> String#];
112+
// INIT_OPTIONAL_SAMELINE-DAG: Decl[InstanceMethod]/CurrNominal: .testStructMethod()[#Void#];
113+
// INIT_OPTIONAL_SAMELINE-DAG: Keyword[self]/CurrNominal: .self[#TestStruct2#];
97114
// INIT_OPTIONAL_SAMELINE: End completions
98115

99116
// INIT_OPTIONAL_NEWLINE: Begin completions
@@ -108,6 +125,7 @@ func testOptionalInit() {
108125

109126
struct TestStruct3 {
110127
init(fn1: () -> Int, fn2: () -> String, fn3: () -> String) {}
128+
func testStructMethod() {}
111129
}
112130
func testOptionalInit() {
113131
// missing 'fn2' and 'fn3'.
@@ -150,7 +168,10 @@ func testOptionalInit() {
150168
} #^INIT_REQUIRED_SAMELINE_3^#
151169
#^INIT_REQUIRED_NEWLINE_3^#
152170

153-
// INIT_REQUIRED_SAMELINE_3-NOT: Begin completions
171+
// INIT_REQUIRED_SAMELINE_3: Begin completions, 2 items
172+
// INIT_REQUIRED_SAMELINE_3-DAG: Decl[InstanceMethod]/CurrNominal: .testStructMethod()[#Void#];
173+
// INIT_REQUIRED_SAMELINE_3-DAG: Keyword[self]/CurrNominal: .self[#TestStruct3#];
174+
// INIT_REQIORED_SAMELINE_3: End completions
154175

155176
// INIT_REQUIRED_NEWLINE_3: Begin completions
156177
// INIT_REQUIRED_NEWLINE_3-NOT: name=fn2

validation-test/IDE/slow/rdar45511835.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
// RUN: %target-swift-ide-test -code-completion -code-completion-token=COMPLETE -source-filename=%s | %FileCheck %s
2-
// TODO: Postfix completion after trailing closure.
3-
// XFAIL: *
42

53
// REQUIRES: long_test
64

0 commit comments

Comments
 (0)