Skip to content

Commit 0f4e7a5

Browse files
committed
[CodeCompletion] Add code completion for where clauses. rdar://24245022
When completing at "extension A where #^HERE^#", we suggest the generic params of A to users.
1 parent e25cd88 commit 0f4e7a5

File tree

8 files changed

+98
-15
lines changed

8 files changed

+98
-15
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ enum class CompletionKind {
447447
CallArg,
448448
ReturnStmtExpr,
449449
AfterPound,
450+
GenericParams,
450451
};
451452

452453
/// \brief A single code completion result.

include/swift/Parse/CodeCompletionCallbacks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ class CodeCompletionCallbacks {
170170

171171
virtual void completeAfterPound(CodeCompletionExpr *E, StmtKind ParentKind) = 0;
172172

173+
virtual void completeGenericParams(TypeLoc TL) = 0;
174+
173175
/// \brief Signals that the AST for the all the delayed-parsed code was
174176
/// constructed. No \c complete*() callbacks will be done after this.
175177
virtual void doneParsing() = 0;

include/swift/Parse/Parser.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,8 +1194,9 @@ class Parser {
11941194
ParserResult<GenericParamList> parseGenericParameters();
11951195
ParserResult<GenericParamList> parseGenericParameters(SourceLoc LAngleLoc);
11961196
ParserResult<GenericParamList> maybeParseGenericParams();
1197-
bool parseGenericWhereClause(SourceLoc &WhereLoc,
1198-
SmallVectorImpl<RequirementRepr> &Requirements);
1197+
ParserStatus parseGenericWhereClause(SourceLoc &WhereLoc,
1198+
SmallVectorImpl<RequirementRepr> &Requirements,
1199+
bool &FirstTypeInComplete);
11991200

12001201
//===--------------------------------------------------------------------===//
12011202
// Availability Specification Parsing

lib/IDE/CodeCompletion.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
12381238
void completeCallArg(CallExpr *E) override;
12391239
void completeReturnStmt(CodeCompletionExpr *E) override;
12401240
void completeAfterPound(CodeCompletionExpr *E, StmtKind ParentKind) override;
1241+
void completeGenericParams(TypeLoc TL) override;
12411242
void addKeywords(CodeCompletionResultSink &Sink);
12421243

12431244
void doneParsing() override;
@@ -3934,6 +3935,12 @@ void CodeCompletionCallbacksImpl::completeAfterPound(CodeCompletionExpr *E,
39343935
ParentStmtKind = ParentKind;
39353936
}
39363937

3938+
void CodeCompletionCallbacksImpl::completeGenericParams(TypeLoc TL) {
3939+
CurDeclContext = P.CurDeclContext;
3940+
Kind = CompletionKind::GenericParams;
3941+
ParsedTypeLoc = TL;
3942+
}
3943+
39373944
void CodeCompletionCallbacksImpl::completeNominalMemberBeginning(
39383945
SmallVectorImpl<StringRef> &Keywords) {
39393946
assert(!InEnumElementRawValue);
@@ -4056,6 +4063,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink) {
40564063
case CompletionKind::UnresolvedMember:
40574064
case CompletionKind::CallArg:
40584065
case CompletionKind::AfterPound:
4066+
case CompletionKind::GenericParams:
40594067
break;
40604068

40614069
case CompletionKind::StmtOrExpr:
@@ -4571,6 +4579,17 @@ void CodeCompletionCallbacksImpl::doneParsing() {
45714579
Lookup.addPoundAvailable(ParentStmtKind);
45724580
break;
45734581
}
4582+
4583+
case CompletionKind::GenericParams: {
4584+
if (auto NM = ParsedTypeLoc.getType()->getAnyNominal()) {
4585+
if (auto Params = NM->getGenericParams()) {
4586+
for (auto GP : Params->getParams()) {
4587+
Lookup.addGenericTypeParamRef(GP, DeclVisibilityKind::GenericParameter);
4588+
}
4589+
}
4590+
}
4591+
break;
4592+
}
45744593
}
45754594

45764595
if (Lookup.RequestedCachedResults) {

lib/Parse/ParseDecl.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2464,9 +2464,17 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
24642464
if (Tok.is(tok::kw_where)) {
24652465
SourceLoc whereLoc;
24662466
SmallVector<RequirementRepr, 4> requirements;
2467-
if (!parseGenericWhereClause(whereLoc, requirements)) {
2467+
bool firstTypeInComplete;
2468+
auto whereStatus = parseGenericWhereClause(whereLoc, requirements,
2469+
firstTypeInComplete);
2470+
if (whereStatus.isSuccess()) {
24682471
trailingWhereClause = TrailingWhereClause::create(Context, whereLoc,
24692472
requirements);
2473+
} else if (whereStatus.hasCodeCompletion()) {
2474+
if (CodeCompletion && firstTypeInComplete) {
2475+
CodeCompletion->completeGenericParams(extendedType.getPtrOrNull());
2476+
} else
2477+
return makeParserCodeCompletionResult<ExtensionDecl>();
24702478
}
24712479
}
24722480

lib/Parse/ParseGeneric.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ ParserResult<GenericParamList> Parser::parseGenericParameters(SourceLoc LAngleLo
107107
// Parse the optional where-clause.
108108
SourceLoc WhereLoc;
109109
SmallVector<RequirementRepr, 4> Requirements;
110+
bool FirstTypeInComplete;
110111
if (Tok.is(tok::kw_where) &&
111-
parseGenericWhereClause(WhereLoc, Requirements)) {
112+
parseGenericWhereClause(WhereLoc, Requirements, FirstTypeInComplete).isError()) {
112113
Invalid = true;
113114
}
114115

@@ -178,17 +179,23 @@ ParserResult<GenericParamList> Parser::maybeParseGenericParams() {
178179
///
179180
/// same-type-requirement:
180181
/// type-identifier '==' type
181-
bool Parser::parseGenericWhereClause(
182+
ParserStatus Parser::parseGenericWhereClause(
182183
SourceLoc &WhereLoc,
183-
SmallVectorImpl<RequirementRepr> &Requirements) {
184+
SmallVectorImpl<RequirementRepr> &Requirements,
185+
bool &FirstTypeInComplete) {
186+
ParserStatus Status;
184187
// Parse the 'where'.
185188
WhereLoc = consumeToken(tok::kw_where);
186-
bool Invalid = false;
189+
FirstTypeInComplete = false;
187190
do {
188191
// Parse the leading type-identifier.
189192
ParserResult<TypeRepr> FirstType = parseTypeIdentifier();
190-
if (FirstType.isNull() || FirstType.hasCodeCompletion()) {
191-
Invalid = true;
193+
if (FirstType.isNull()) {
194+
Status.setIsParseError();
195+
if (FirstType.hasCodeCompletion()) {
196+
Status.setHasCodeCompletion();
197+
FirstTypeInComplete = true;
198+
}
192199
break;
193200
}
194201

@@ -203,8 +210,10 @@ bool Parser::parseGenericWhereClause(
203210
} else {
204211
Protocol = parseTypeIdentifier();
205212
}
206-
if (Protocol.isNull() || Protocol.hasCodeCompletion()) {
207-
Invalid = true;
213+
if (Protocol.isNull()) {
214+
Status.setIsParseError();
215+
if (Protocol.hasCodeCompletion())
216+
Status.setHasCodeCompletion();
208217
break;
209218
}
210219

@@ -222,8 +231,10 @@ bool Parser::parseGenericWhereClause(
222231

223232
// Parse the second type.
224233
ParserResult<TypeRepr> SecondType = parseType();
225-
if (SecondType.isNull() || SecondType.hasCodeCompletion()) {
226-
Invalid = true;
234+
if (SecondType.isNull()) {
235+
Status.setIsParseError();
236+
if (SecondType.hasCodeCompletion())
237+
Status.setHasCodeCompletion();
227238
break;
228239
}
229240

@@ -233,11 +244,11 @@ bool Parser::parseGenericWhereClause(
233244
SecondType.get()));
234245
} else {
235246
diagnose(Tok, diag::expected_requirement_delim);
236-
Invalid = true;
247+
Status.setIsParseError();
237248
break;
238249
}
239250
// If there's a comma, keep parsing the list.
240251
} while (consumeIf(tok::comma));
241252

242-
return Invalid;
253+
return Status;
243254
}

lib/Sema/TypeChecker.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,9 @@ bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T,
636636
bool isSILType, DeclContext *DC,
637637
bool ProduceDiagnostics) {
638638
TypeResolutionOptions options;
639+
640+
// Fine to have unbound generic types.
641+
options |= TR_AllowUnboundGenerics;
639642
if (isSILType)
640643
options |= TR_SILType;
641644

test/IDE/complete_where_clause.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP1 | FileCheck %s -check-prefix=A1
2+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP2 | FileCheck %s -check-prefix=A1
3+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP3 | FileCheck %s -check-prefix=A1
4+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP4 | FileCheck %s -check-prefix=TYPE1
5+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP5 | FileCheck %s -check-prefix=TYPE1
6+
7+
class A1<T1, T2, T3> {}
8+
9+
class A2<T4, T5> {}
10+
11+
protocol P1 {}
12+
13+
extension A1 where #^GP1^#{}
14+
15+
extension A1 where T1 : P1, #^GP2^# {}
16+
17+
extension A1 where T1 : P1, #^GP3^#
18+
19+
extension A1 where T1 : #^GP4^#
20+
21+
extension A1 where T1 : P1, T2 : #^GP5^#
22+
23+
// A1: Begin completions
24+
// A1-DAG: Decl[GenericTypeParam]/Local: T1[#T1#]; name=T1
25+
// A1-DAG: Decl[GenericTypeParam]/Local: T2[#T2#]; name=T2
26+
// A1-DAG: Decl[GenericTypeParam]/Local: T3[#T3#]; name=T3
27+
// A1-NOT: T4
28+
// A1-NOT: T5
29+
30+
// TYPE1: Begin completions
31+
// TYPE1-DAG: Decl[Protocol]/CurrModule: P1[#P1#]; name=P1
32+
// TYPE1-DAG: Decl[Class]/CurrModule: A1[#A1#]; name=A1
33+
// TYPE1-DAG: Decl[Class]/CurrModule: A2[#A2#]; name=A2
34+
// TYPE1-NOT: T1
35+
// TYPE1-NOT: T2
36+
// TYPE1-NOT: T3
37+
// TYPE1-NOT: T4
38+
// TYPE1-NOT: T5

0 commit comments

Comments
 (0)