Skip to content

Commit 9d90e14

Browse files
committed
[CodeCompletion] Postfix expr completion after trailing closures
1 parent bdc4d46 commit 9d90e14

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
@@ -5866,8 +5866,37 @@ void CodeCompletionCallbacksImpl::doneParsing() {
58665866
DoPostfixExprBeginning();
58675867
} else {
58685868
// foo() {} <HERE>
5869-
// Member completion
5870-
// TODO: Member completion.
5869+
// Member completion.
5870+
Expr *analyzedExpr = ContextInfo.getAnalyzedExpr();
5871+
if (!analyzedExpr)
5872+
break;
5873+
5874+
// Only if the completion token is the last token in the call.
5875+
if (analyzedExpr->getEndLoc() != CodeCompleteTokenExpr->getLoc())
5876+
break;
5877+
5878+
// If the call expression doesn't have a type, infer it from the
5879+
// possible callee info.
5880+
Type resultTy = analyzedExpr->getType();
5881+
if (!resultTy) {
5882+
if (ContextInfo.getPossibleCallees().empty())
5883+
break;
5884+
auto calleeInfo = ContextInfo.getPossibleCallees()[0];
5885+
resultTy = calleeInfo.Type->getResult();
5886+
analyzedExpr->setType(resultTy);
5887+
}
5888+
5889+
auto &SM = CurDeclContext->getASTContext().SourceMgr;
5890+
auto leadingChar =
5891+
SM.extractText({SM.getCodeCompletionLoc().getAdvancedLoc(-1), 1});
5892+
Lookup.setHaveLeadingSpace(leadingChar.find_first_of(" \t\f\v") !=
5893+
StringRef::npos);
5894+
5895+
if (isDynamicLookup(resultTy))
5896+
Lookup.setIsDynamicLookup();
5897+
Lookup.getValueExprCompletions(resultTy, /*VD=*/nullptr);
5898+
Lookup.getOperatorCompletions(analyzedExpr, leadingSequenceExprs);
5899+
Lookup.getPostfixKeywordCompletions(resultTy, analyzedExpr);
58715900
}
58725901
}
58735902
break;

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ class ExprContextAnalyzer {
559559
SmallVectorImpl<Type> &PossibleTypes;
560560
SmallVectorImpl<PossibleParamInfo> &PossibleParams;
561561
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees;
562+
Expr *&AnalyzedExpr;
562563
bool &singleExpressionBody;
563564

564565
void recordPossibleType(Type ty) {
@@ -660,6 +661,7 @@ class ExprContextAnalyzer {
660661
}
661662

662663
void analyzeExpr(Expr *Parent) {
664+
AnalyzedExpr = Parent;
663665
switch (Parent->getKind()) {
664666
case ExprKind::Call:
665667
case ExprKind::Subscript:
@@ -920,10 +922,11 @@ class ExprContextAnalyzer {
920922
DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl<Type> &PossibleTypes,
921923
SmallVectorImpl<PossibleParamInfo> &PossibleArgs,
922924
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees,
923-
bool &singleExpressionBody)
925+
Expr *&AnalyzedExpr, bool &singleExpressionBody)
924926
: DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr),
925927
Context(DC->getASTContext()), PossibleTypes(PossibleTypes),
926928
PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees),
929+
AnalyzedExpr(AnalyzedExpr),
927930
singleExpressionBody(singleExpressionBody) {}
928931

929932
void Analyze() {
@@ -1032,7 +1035,8 @@ class ExprContextAnalyzer {
10321035

10331036
ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
10341037
ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams,
1035-
PossibleCallees, singleExpressionBody);
1038+
PossibleCallees, AnalyzedExpr,
1039+
singleExpressionBody);
10361040
Analyzer.Analyze();
10371041
}
10381042

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)