Skip to content

Commit f8147f7

Browse files
committed
[CodeCompletion] Call argument label with value placeholder
When a completion happens at a call argument position, insert 'label: <#T##TypeName#>' instead of just 'label: '. rdar://problem/60379654
1 parent afa2440 commit f8147f7

7 files changed

+81
-56
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3936,14 +3936,23 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
39363936
}
39373937
}
39383938

3939-
void addArgNameCompletionResults(ArrayRef<StringRef> Names) {
3940-
for (auto Name : Names) {
3941-
CodeCompletionResultBuilder Builder(Sink,
3942-
CodeCompletionResult::ResultKind::Keyword,
3943-
SemanticContextKind::ExpressionSpecific, {});
3944-
Builder.addTextChunk(Name);
3945-
Builder.addCallParameterColon();
3946-
Builder.addTypeAnnotation("Argument name");
3939+
void addCallArgumentCompletionResults(
3940+
ArrayRef<const AnyFunctionType::Param *> Args) {
3941+
Type ContextType;
3942+
if (auto typeContext = CurrDeclContext->getInnermostTypeContext())
3943+
ContextType = typeContext->getDeclaredTypeInContext();
3944+
3945+
for (auto *Arg : Args) {
3946+
CodeCompletionResultBuilder Builder(
3947+
Sink, CodeCompletionResult::ResultKind::Pattern,
3948+
SemanticContextKind::ExpressionSpecific, {});
3949+
Builder.addCallParameter(Arg->getLabel(), Identifier(),
3950+
Arg->getPlainType(), ContextType,
3951+
Arg->isVariadic(), Arg->isInOut(),
3952+
/*isIUO=*/false, Arg->isAutoClosure());
3953+
Builder.addTypeAnnotation("Argument");
3954+
Builder.setExpectedTypeRelation(
3955+
CodeCompletionResult::ExpectedTypeRelation::NotApplicable);
39473956
}
39483957
}
39493958

@@ -5432,7 +5441,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
54325441
}
54335442
} else {
54345443
// Add argument labels, then fallthrough to get values.
5435-
Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames());
5444+
Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams());
54365445
}
54375446

54385447
if (!Lookup.FoundFunctionCalls ||
@@ -5570,8 +5579,8 @@ void CodeCompletionCallbacksImpl::doneParsing() {
55705579
!Lookup.FoundFunctionCalls ||
55715580
(Lookup.FoundFunctionCalls &&
55725581
Lookup.FoundFunctionsWithoutFirstKeyword);
5573-
} else if (!ContextInfo.getPossibleNames().empty()) {
5574-
Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames());
5582+
} else if (!ContextInfo.getPossibleParams().empty()) {
5583+
Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams());
55755584

55765585
shouldPerformGlobalCompletion = !ContextInfo.getPossibleTypes().empty();
55775586
}

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ class ExprContextAnalyzer {
537537

538538
// Results populated by Analyze()
539539
SmallVectorImpl<Type> &PossibleTypes;
540-
SmallVectorImpl<StringRef> &PossibleNames;
540+
SmallVectorImpl<const AnyFunctionType::Param *> &PossibleParams;
541541
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees;
542542
bool &singleExpressionBody;
543543

@@ -548,7 +548,9 @@ class ExprContextAnalyzer {
548548
PossibleTypes.push_back(ty->getRValueType());
549549
}
550550

551-
void recordPossibleName(StringRef name) { PossibleNames.push_back(name); }
551+
void recordPossibleParam(const AnyFunctionType::Param &arg) {
552+
PossibleParams.push_back(&arg);
553+
}
552554

553555
/// Collect context information at call argument position.
554556
bool analyzeApplyExpr(Expr *E) {
@@ -585,7 +587,7 @@ class ExprContextAnalyzer {
585587
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
586588
isa<UnresolvedMemberExpr>(E));
587589
SmallPtrSet<TypeBase *, 4> seenTypes;
588-
SmallPtrSet<Identifier, 4> seenNames;
590+
llvm::SmallSet<std::pair<Identifier, TypeBase *>, 4> seenArgs;
589591
for (auto &typeAndDecl : Candidates) {
590592
DeclContext *memberDC = nullptr;
591593
if (typeAndDecl.Decl)
@@ -603,23 +605,27 @@ class ExprContextAnalyzer {
603605
}
604606
for (auto Pos = Position; Pos < Params.size(); ++Pos) {
605607
const auto &Param = Params[Pos];
608+
Type ty = Param.getPlainType();
609+
if (memberDC && ty->hasTypeParameter())
610+
ty = memberDC->mapTypeIntoContext(ty);
611+
606612
if (Param.hasLabel() && MayNeedName) {
607-
if (seenNames.insert(Param.getLabel()).second)
608-
recordPossibleName(Param.getLabel().str());
613+
if (seenArgs.insert({Param.getLabel(), ty.getPointer()}).second)
614+
recordPossibleParam(Param);
609615
if (paramList && paramList->get(Position)->isDefaultArgument())
610616
continue;
611617
} else {
612-
Type ty = Param.getOldType();
613-
if (memberDC && ty->hasTypeParameter())
614-
ty = memberDC->mapTypeIntoContext(ty);
615-
if (seenTypes.insert(ty.getPointer()).second)
616-
recordPossibleType(ty);
618+
auto argTy = ty;
619+
if (Param.isInOut())
620+
argTy = InOutType::get(argTy);
621+
if (seenTypes.insert(argTy.getPointer()).second)
622+
recordPossibleType(argTy);
617623
}
618624
break;
619625
}
620626
}
621627
}
622-
return !PossibleTypes.empty() || !PossibleNames.empty();
628+
return !PossibleTypes.empty() || !PossibleParams.empty();
623629
}
624630

625631
void analyzeExpr(Expr *Parent) {
@@ -879,14 +885,14 @@ class ExprContextAnalyzer {
879885
}
880886

881887
public:
882-
ExprContextAnalyzer(DeclContext *DC, Expr *ParsedExpr,
883-
SmallVectorImpl<Type> &PossibleTypes,
884-
SmallVectorImpl<StringRef> &PossibleNames,
885-
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees,
886-
bool &singleExpressionBody)
888+
ExprContextAnalyzer(
889+
DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl<Type> &PossibleTypes,
890+
SmallVectorImpl<const AnyFunctionType::Param *> &PossibleArgs,
891+
SmallVectorImpl<FunctionTypeAndDecl> &PossibleCallees,
892+
bool &singleExpressionBody)
887893
: DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr),
888894
Context(DC->getASTContext()), PossibleTypes(PossibleTypes),
889-
PossibleNames(PossibleNames), PossibleCallees(PossibleCallees),
895+
PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees),
890896
singleExpressionBody(singleExpressionBody) {}
891897

892898
void Analyze() {
@@ -990,7 +996,7 @@ class ExprContextAnalyzer {
990996
} // end anonymous namespace
991997

992998
ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) {
993-
ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleNames,
999+
ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams,
9941000
PossibleCallees, singleExpressionBody);
9951001
Analyzer.Analyze();
9961002
}

lib/IDE/ExprContextAnalysis.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
#define SWIFT_IDE_EXPRCONTEXTANALYSIS_H
1515

1616
#include "swift/AST/Type.h"
17+
#include "swift/AST/Types.h"
1718
#include "swift/Basic/LLVM.h"
1819
#include "swift/Basic/SourceLoc.h"
1920

2021
namespace swift {
2122
class DeclContext;
2223
class Expr;
2324
class ValueDecl;
24-
class AnyFunctionType;
2525

2626
namespace ide {
2727
enum class SemanticContextKind;
@@ -54,7 +54,7 @@ struct FunctionTypeAndDecl {
5454
/// the expected type of the expression by analyzing its context.
5555
class ExprContextInfo {
5656
SmallVector<Type, 2> PossibleTypes;
57-
SmallVector<StringRef, 2> PossibleNames;
57+
SmallVector<const AnyFunctionType::Param *, 2> PossibleParams;
5858
SmallVector<FunctionTypeAndDecl, 2> PossibleCallees;
5959
bool singleExpressionBody = false;
6060

@@ -73,7 +73,9 @@ class ExprContextInfo {
7373

7474
// Returns a list of possible argument label names.
7575
// Valid only if \c getKind() is \c CallArgument.
76-
ArrayRef<StringRef> getPossibleNames() const { return PossibleNames; }
76+
ArrayRef<const AnyFunctionType::Param *> getPossibleParams() const {
77+
return PossibleParams;
78+
}
7779

7880
// Returns a list of possible callee
7981
// Valid only if \c getKind() is \c CallArgument.

test/IDE/complete_call_arg.swift

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG3 | %FileCheck %s -check-prefix=ARG-NAME2
44
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG4 | %FileCheck %s -check-prefix=EXPECT_INT
55
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG5 | %FileCheck %s -check-prefix=EXPECT_OSTRING
6-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG6 | %FileCheck %s -check-prefix=ARG-NAME2
7-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG7 | %FileCheck %s -check-prefix=ARG-NAME1
6+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG6 | %FileCheck %s -check-prefix=ARG-NAME3
7+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG7 | %FileCheck %s -check-prefix=ARG-NAME4
88
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG8 | %FileCheck %s -check-prefix=EXPECT_STRING
99

1010
// RUN-FIXME: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOAD1 | %FileCheck %s -check-prefix=OVERLOAD1
@@ -171,11 +171,19 @@ class C1 {
171171
}
172172

173173
// ARG-NAME1: Begin completions, 2 items
174-
// ARG-NAME1-DAG: Keyword/ExprSpecific: b1: [#Argument name#]; name=b1:
175-
// ARG-NAME1-DAG: Keyword/ExprSpecific: b2: [#Argument name#]; name=b2:
174+
// ARG-NAME1-DAG: Pattern/ExprSpecific: {#b1: Int?#}[#Argument#];
175+
// ARG-NAME1-DAG: Pattern/ExprSpecific: {#b2: Int?#}[#Argument#];
176176

177177
// ARG-NAME2: Begin completions, 1 items
178-
// ARG-NAME2-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b:
178+
// ARG-NAME2-DAG: Pattern/ExprSpecific: {#b: Int#}[#Argument#];
179+
180+
// ARG-NAME3: Begin completions, 1 items
181+
// ARG-NAME3-DAG: Pattern/ExprSpecific: {#b: String?#}[#Argument#];
182+
183+
// ARG-NAME4: Begin completions, 2 items
184+
// ARG-NAME4-DAG: Pattern/ExprSpecific: {#b1: String#}[#Argument#];
185+
// ARG-NAME4-DAG: Pattern/ExprSpecific: {#b2: String#}[#Argument#];
186+
// ARG-NAME4: End completions
179187

180188
// EXPECT_OINT: Begin completions
181189
// EXPECT_OINT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended/TypeRelation[Invalid]: f1()[#Void#]; name=f1()
@@ -336,7 +344,7 @@ extension C3 {
336344
// HASERROR2: End completions
337345

338346
// HASERROR3: Begin completions
339-
// HASERROR3-DAG: Keyword/ExprSpecific: b1: [#Argument name#];
347+
// HASERROR3-DAG: Pattern/ExprSpecific: {#b1: <<error type>>#}[#Argument#];
340348
// HASERROR3: End completions
341349

342350
// HASERROR4: Begin completions
@@ -464,7 +472,7 @@ func testArg2Name1() {
464472
func testArg2Name3() {
465473
firstArg(#^FIRST_ARG_NAME_3^#,
466474
}
467-
// FIRST_ARG_NAME_3: Keyword/ExprSpecific: arg1: [#Argument name#]
475+
// FIRST_ARG_NAME_3: Pattern/ExprSpecific: {#arg1: Int#}[#Argument#];
468476
// FIRST_ARG_NAME_4: Decl[FreeFunction]/CurrModule: ['(']{#arg1: Int#}, {#arg2: Int#}[')'][#Void#];
469477

470478
func takeArray<T>(_ x: [T]) {}
@@ -582,7 +590,7 @@ func testSubscript(obj: HasSubscript, intValue: Int, strValue: String) {
582590

583591
let _ = obj[42, #^SUBSCRIPT_2^#
584592
// SUBSCRIPT_2: Begin completions, 1 items
585-
// SUBSCRIPT_2-NEXT: Keyword/ExprSpecific: default: [#Argument name#]; name=default:
593+
// SUBSCRIPT_2-NEXT: Pattern/ExprSpecific: {#default: String#}[#Argument#];
586594

587595
let _ = obj[42, .#^SUBSCRIPT_2_DOT^#
588596
// SUBSCRIPT_2_DOT-NOT: Begin completions
@@ -659,16 +667,16 @@ func testStaticMemberCall() {
659667

660668
let _ = TestStaticMemberCall.create2(1, #^STATIC_METHOD_SECOND^#)
661669
// STATIC_METHOD_SECOND: Begin completions, 3 items
662-
// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg2: [#Argument name#];
663-
// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg3: [#Argument name#];
664-
// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg4: [#Argument name#];
670+
// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg2: Int#}[#Argument#];
671+
// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg3: Int#}[#Argument#];
672+
// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg4: Int#}[#Argument#];
665673
// STATIC_METHOD_SECOND: End completions
666674

667675
let _ = TestStaticMemberCall.create2(1, arg3: 2, #^STATIC_METHOD_SKIPPED^#)
668676
// STATIC_METHOD_SKIPPED: Begin completions, 2 items
669677
// FIXME: 'arg3' shouldn't be suggested.
670-
// STATIC_METHOD_SKIPPED: Keyword/ExprSpecific: arg3: [#Argument name#];
671-
// STATIC_METHOD_SKIPPED: Keyword/ExprSpecific: arg4: [#Argument name#];
678+
// STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Argument#];
679+
// STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Argument#];
672680
// STATIC_METHOD_SKIPPED: End completions
673681
}
674682
func testImplicitMember() {
@@ -687,16 +695,16 @@ func testImplicitMember() {
687695

688696
let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#)
689697
// IMPLICIT_MEMBER_SECOND: Begin completions, 3 items
690-
// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg2: [#Argument name#];
691-
// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg3: [#Argument name#];
692-
// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg4: [#Argument name#];
698+
// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg2: Int#}[#Argument#];
699+
// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg3: Int#}[#Argument#];
700+
// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg4: Int#}[#Argument#];
693701
// IMPLICIT_MEMBER_SECOND: End completions
694702

695703
let _: TestStaticMemberCall = .create2(1, arg3: 2, #^IMPLICIT_MEMBER_SKIPPED^#)
696704
// IMPLICIT_MEMBER_SKIPPED: Begin completions, 2 items
697705
// FIXME: 'arg3' shouldn't be suggested.
698-
// IMPLICIT_MEMBER_SKIPPED: Keyword/ExprSpecific: arg3: [#Argument name#];
699-
// IMPLICIT_MEMBER_SKIPPED: Keyword/ExprSpecific: arg4: [#Argument name#];
706+
// IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Argument#];
707+
// IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Argument#];
700708
// IMPLICIT_MEMBER_SKIPPED: End completions
701709
}
702710
func testImplicitMemberInArrayLiteral() {

test/IDE/complete_call_as_function.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func testCallAsFunction(add: Adder, addTy: Adder.Type) {
3939

4040
let _ = add(x: 12, #^INSTANCE_ARG2^#)
4141
// INSTANCE_ARG2: Begin completions, 1 items
42-
// INSTANCE_ARG2: Keyword/ExprSpecific: y: [#Argument name#];
42+
// INSTANCE_ARG2: Pattern/ExprSpecific: {#y: Int#}[#Argument#];
4343
// INSTANCE_ARG2: End completions
4444

4545
let _ = addTy#^METATYPE_NO_DOT^#;
@@ -105,8 +105,8 @@ func testCallAsFunctionOverloaded(fn: Functor) {
105105
fn(h: .left, #^OVERLOADED_ARG2_LABEL^#)
106106
// FIXME: Should only suggest 'v:' (rdar://problem/60346573).
107107
//OVERLOADED_ARG2_LABEL: Begin completions, 2 items
108-
//OVERLOADED_ARG2_LABEL-DAG: Keyword/ExprSpecific: v: [#Argument name#];
109-
//OVERLOADED_ARG2_LABEL-DAG: Keyword/ExprSpecific: h: [#Argument name#];
108+
//OVERLOADED_ARG2_LABEL-DAG: Pattern/ExprSpecific: {#v: Functor.Vertical#}[#Argument#];
109+
//OVERLOADED_ARG2_LABEL-DAG: Pattern/ExprSpecific: {#h: Functor.Horizontal#}[#Argument#];
110110
//OVERLOADED_ARG2_LABEL: End completions
111111

112112
fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#)

test/IDE/complete_subscript.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ func test2<U>(value: MyStruct<U>) {
9191

9292
let _ = MyStruct<U>[42, #^METATYPE_LABEL^#
9393
// METATYPE_LABEL: Begin completions, 1 items
94-
// METATYPE_LABEL-DAG: Keyword/ExprSpecific: static: [#Argument name#];
94+
// METATYPE_LABEL-DAG: Pattern/ExprSpecific: {#static: U#}[#Argument#];
9595
// METATYPE_LABEL: End completions
9696

9797
let _ = value[42, #^INSTANCE_LABEL^#
9898
// INSTANCE_LABEL: Begin completions, 1 items
99-
// INSTANCE_LABEL-DAG: Keyword/ExprSpecific: instance: [#Argument name#];
99+
// INSTANCE_LABEL-DAG: Pattern/ExprSpecific: {#instance: U#}[#Argument#];
100100
// INSTANCE_LABEL: End completions
101101
}
102102

test/IDE/complete_value_expr.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ func testInsideFunctionCall4() {
768768
func testInsideFunctionCall5() {
769769
FooStruct().instanceFunc2(42, #^INSIDE_FUNCTION_CALL_5^#
770770
// INSIDE_FUNCTION_CALL_5: Begin completions
771-
// INSIDE_FUNCTION_CALL_5-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b:
771+
// INSIDE_FUNCTION_CALL_5-DAG: Pattern/ExprSpecific: {#b: &Double#}[#Argument#];
772772
// INSIDE_FUNCTION_CALL_5: End completions
773773
}
774774

0 commit comments

Comments
 (0)