diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 04eb87eb96f75..d078a1c25a5b1 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3936,14 +3936,31 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } } - void addArgNameCompletionResults(ArrayRef Names) { - for (auto Name : Names) { - CodeCompletionResultBuilder Builder(Sink, - CodeCompletionResult::ResultKind::Keyword, - SemanticContextKind::ExpressionSpecific, {}); - Builder.addTextChunk(Name); - Builder.addCallParameterColon(); - Builder.addTypeAnnotation("Argument name"); + void addCallArgumentCompletionResults( + ArrayRef Args) { + Type ContextType; + if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) + ContextType = typeContext->getDeclaredTypeInContext(); + + for (auto *Arg : Args) { + CodeCompletionResultBuilder Builder( + Sink, CodeCompletionResult::ResultKind::Pattern, + SemanticContextKind::ExpressionSpecific, {}); + Builder.addCallParameter(Arg->getLabel(), Identifier(), + Arg->getPlainType(), ContextType, + Arg->isVariadic(), Arg->isInOut(), + /*isIUO=*/false, Arg->isAutoClosure()); + auto Ty = Arg->getPlainType(); + if (Arg->isInOut()) { + Ty = InOutType::get(Ty); + } else if (Arg->isAutoClosure()) { + // 'Ty' may be ErrorType. + if (auto funcTy = Ty->getAs()) + Ty = funcTy->getResult(); + } + addTypeAnnotation(Builder, Ty); + Builder.setExpectedTypeRelation( + CodeCompletionResult::ExpectedTypeRelation::NotApplicable); } } @@ -5432,7 +5449,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { } } else { // Add argument labels, then fallthrough to get values. - Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames()); + Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams()); } if (!Lookup.FoundFunctionCalls || @@ -5570,8 +5587,8 @@ void CodeCompletionCallbacksImpl::doneParsing() { !Lookup.FoundFunctionCalls || (Lookup.FoundFunctionCalls && Lookup.FoundFunctionsWithoutFirstKeyword); - } else if (!ContextInfo.getPossibleNames().empty()) { - Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames()); + } else if (!ContextInfo.getPossibleParams().empty()) { + Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams()); shouldPerformGlobalCompletion = !ContextInfo.getPossibleTypes().empty(); } diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index e6605e0e70d69..f523705b97862 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -537,7 +537,7 @@ class ExprContextAnalyzer { // Results populated by Analyze() SmallVectorImpl &PossibleTypes; - SmallVectorImpl &PossibleNames; + SmallVectorImpl &PossibleParams; SmallVectorImpl &PossibleCallees; bool &singleExpressionBody; @@ -548,7 +548,9 @@ class ExprContextAnalyzer { PossibleTypes.push_back(ty->getRValueType()); } - void recordPossibleName(StringRef name) { PossibleNames.push_back(name); } + void recordPossibleParam(const AnyFunctionType::Param &arg) { + PossibleParams.push_back(&arg); + } /// Collect context information at call argument position. bool analyzeApplyExpr(Expr *E) { @@ -585,7 +587,7 @@ class ExprContextAnalyzer { (isa(E) | isa(E) || isa(E)); SmallPtrSet seenTypes; - SmallPtrSet seenNames; + llvm::SmallSet, 4> seenArgs; for (auto &typeAndDecl : Candidates) { DeclContext *memberDC = nullptr; if (typeAndDecl.Decl) @@ -603,23 +605,27 @@ class ExprContextAnalyzer { } for (auto Pos = Position; Pos < Params.size(); ++Pos) { const auto &Param = Params[Pos]; + Type ty = Param.getPlainType(); + if (memberDC && ty->hasTypeParameter()) + ty = memberDC->mapTypeIntoContext(ty); + if (Param.hasLabel() && MayNeedName) { - if (seenNames.insert(Param.getLabel()).second) - recordPossibleName(Param.getLabel().str()); + if (seenArgs.insert({Param.getLabel(), ty.getPointer()}).second) + recordPossibleParam(Param); if (paramList && paramList->get(Position)->isDefaultArgument()) continue; } else { - Type ty = Param.getOldType(); - if (memberDC && ty->hasTypeParameter()) - ty = memberDC->mapTypeIntoContext(ty); - if (seenTypes.insert(ty.getPointer()).second) - recordPossibleType(ty); + auto argTy = ty; + if (Param.isInOut()) + argTy = InOutType::get(argTy); + if (seenTypes.insert(argTy.getPointer()).second) + recordPossibleType(argTy); } break; } } } - return !PossibleTypes.empty() || !PossibleNames.empty(); + return !PossibleTypes.empty() || !PossibleParams.empty(); } void analyzeExpr(Expr *Parent) { @@ -879,14 +885,14 @@ class ExprContextAnalyzer { } public: - ExprContextAnalyzer(DeclContext *DC, Expr *ParsedExpr, - SmallVectorImpl &PossibleTypes, - SmallVectorImpl &PossibleNames, - SmallVectorImpl &PossibleCallees, - bool &singleExpressionBody) + ExprContextAnalyzer( + DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl &PossibleTypes, + SmallVectorImpl &PossibleArgs, + SmallVectorImpl &PossibleCallees, + bool &singleExpressionBody) : DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr), Context(DC->getASTContext()), PossibleTypes(PossibleTypes), - PossibleNames(PossibleNames), PossibleCallees(PossibleCallees), + PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees), singleExpressionBody(singleExpressionBody) {} void Analyze() { @@ -990,7 +996,7 @@ class ExprContextAnalyzer { } // end anonymous namespace ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) { - ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleNames, + ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams, PossibleCallees, singleExpressionBody); Analyzer.Analyze(); } diff --git a/lib/IDE/ExprContextAnalysis.h b/lib/IDE/ExprContextAnalysis.h index 5844603ec5517..bab0306057b9a 100644 --- a/lib/IDE/ExprContextAnalysis.h +++ b/lib/IDE/ExprContextAnalysis.h @@ -14,6 +14,7 @@ #define SWIFT_IDE_EXPRCONTEXTANALYSIS_H #include "swift/AST/Type.h" +#include "swift/AST/Types.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceLoc.h" @@ -21,7 +22,6 @@ namespace swift { class DeclContext; class Expr; class ValueDecl; -class AnyFunctionType; namespace ide { enum class SemanticContextKind; @@ -54,7 +54,7 @@ struct FunctionTypeAndDecl { /// the expected type of the expression by analyzing its context. class ExprContextInfo { SmallVector PossibleTypes; - SmallVector PossibleNames; + SmallVector PossibleParams; SmallVector PossibleCallees; bool singleExpressionBody = false; @@ -73,7 +73,9 @@ class ExprContextInfo { // Returns a list of possible argument label names. // Valid only if \c getKind() is \c CallArgument. - ArrayRef getPossibleNames() const { return PossibleNames; } + ArrayRef getPossibleParams() const { + return PossibleParams; + } // Returns a list of possible callee // Valid only if \c getKind() is \c CallArgument. diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index cc38667f218fc..7c8a76087efb1 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -3,8 +3,8 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG3 | %FileCheck %s -check-prefix=ARG-NAME2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG4 | %FileCheck %s -check-prefix=EXPECT_INT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG5 | %FileCheck %s -check-prefix=EXPECT_OSTRING -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG6 | %FileCheck %s -check-prefix=ARG-NAME2 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG7 | %FileCheck %s -check-prefix=ARG-NAME1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG6 | %FileCheck %s -check-prefix=ARG-NAME3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG7 | %FileCheck %s -check-prefix=ARG-NAME4 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG8 | %FileCheck %s -check-prefix=EXPECT_STRING // RUN-FIXME: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOAD1 | %FileCheck %s -check-prefix=OVERLOAD1 @@ -96,6 +96,12 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPECHECKED_OVERLOADED | %FileCheck %s -check-prefix=TYPECHECKED_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPECHECKED_TYPEEXPR | %FileCheck %s -check-prefix=TYPECHECKED_TYPEEXPR +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_INOUT | %FileCheck %s -check-prefix=ARG_PARAMFLAG_INOUT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_AUTOCLOSURE| %FileCheck %s -check-prefix=ARG_PARAMFLAG_AUTOCLOSURE +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_IUO | %FileCheck %s -check-prefix=ARG_PARAMFLAG_IUO +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARG_PARAMFLAG_VARIADIC | %FileCheck %s -check-prefix=ARG_PARAMFLAG_VARIADIC + + var i1 = 1 var i2 = 2 var oi1 : Int? @@ -171,11 +177,19 @@ class C1 { } // ARG-NAME1: Begin completions, 2 items -// ARG-NAME1-DAG: Keyword/ExprSpecific: b1: [#Argument name#]; name=b1: -// ARG-NAME1-DAG: Keyword/ExprSpecific: b2: [#Argument name#]; name=b2: +// ARG-NAME1-DAG: Pattern/ExprSpecific: {#b1: Int?#}[#Int?#]; +// ARG-NAME1-DAG: Pattern/ExprSpecific: {#b2: Int?#}[#Int?#]; // ARG-NAME2: Begin completions, 1 items -// ARG-NAME2-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b: +// ARG-NAME2-DAG: Pattern/ExprSpecific: {#b: Int#}[#Int#]; + +// ARG-NAME3: Begin completions, 1 items +// ARG-NAME3-DAG: Pattern/ExprSpecific: {#b: String?#}[#String?#]; + +// ARG-NAME4: Begin completions, 2 items +// ARG-NAME4-DAG: Pattern/ExprSpecific: {#b1: String#}[#String#]; +// ARG-NAME4-DAG: Pattern/ExprSpecific: {#b2: String#}[#String#]; +// ARG-NAME4: End completions // EXPECT_OINT: Begin completions // EXPECT_OINT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended/TypeRelation[Invalid]: f1()[#Void#]; name=f1() @@ -336,7 +350,7 @@ extension C3 { // HASERROR2: End completions // HASERROR3: Begin completions -// HASERROR3-DAG: Keyword/ExprSpecific: b1: [#Argument name#]; +// HASERROR3-DAG: Pattern/ExprSpecific: {#b1: <>#}[#<>#]; // HASERROR3: End completions // HASERROR4: Begin completions @@ -464,7 +478,7 @@ func testArg2Name1() { func testArg2Name3() { firstArg(#^FIRST_ARG_NAME_3^#, } -// FIRST_ARG_NAME_3: Keyword/ExprSpecific: arg1: [#Argument name#] +// FIRST_ARG_NAME_3: Pattern/ExprSpecific: {#arg1: Int#}[#Int#]; // FIRST_ARG_NAME_4: Decl[FreeFunction]/CurrModule: ['(']{#arg1: Int#}, {#arg2: Int#}[')'][#Void#]; func takeArray(_ x: [T]) {} @@ -582,7 +596,7 @@ func testSubscript(obj: HasSubscript, intValue: Int, strValue: String) { let _ = obj[42, #^SUBSCRIPT_2^# // SUBSCRIPT_2: Begin completions, 1 items -// SUBSCRIPT_2-NEXT: Keyword/ExprSpecific: default: [#Argument name#]; name=default: +// SUBSCRIPT_2-NEXT: Pattern/ExprSpecific: {#default: String#}[#String#]; let _ = obj[42, .#^SUBSCRIPT_2_DOT^# // SUBSCRIPT_2_DOT-NOT: Begin completions @@ -659,16 +673,16 @@ func testStaticMemberCall() { let _ = TestStaticMemberCall.create2(1, #^STATIC_METHOD_SECOND^#) // STATIC_METHOD_SECOND: Begin completions, 3 items -// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg2: [#Argument name#]; -// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg3: [#Argument name#]; -// STATIC_METHOD_SECOND: Keyword/ExprSpecific: arg4: [#Argument name#]; +// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg2: Int#}[#Int#]; +// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// STATIC_METHOD_SECOND: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SECOND: End completions let _ = TestStaticMemberCall.create2(1, arg3: 2, #^STATIC_METHOD_SKIPPED^#) // STATIC_METHOD_SKIPPED: Begin completions, 2 items // FIXME: 'arg3' shouldn't be suggested. -// STATIC_METHOD_SKIPPED: Keyword/ExprSpecific: arg3: [#Argument name#]; -// STATIC_METHOD_SKIPPED: Keyword/ExprSpecific: arg4: [#Argument name#]; +// STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: End completions } func testImplicitMember() { @@ -687,16 +701,16 @@ func testImplicitMember() { let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#) // IMPLICIT_MEMBER_SECOND: Begin completions, 3 items -// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg2: [#Argument name#]; -// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg3: [#Argument name#]; -// IMPLICIT_MEMBER_SECOND: Keyword/ExprSpecific: arg4: [#Argument name#]; +// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg2: Int#}[#Int#]; +// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// IMPLICIT_MEMBER_SECOND: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SECOND: End completions let _: TestStaticMemberCall = .create2(1, arg3: 2, #^IMPLICIT_MEMBER_SKIPPED^#) // IMPLICIT_MEMBER_SKIPPED: Begin completions, 2 items // FIXME: 'arg3' shouldn't be suggested. -// IMPLICIT_MEMBER_SKIPPED: Keyword/ExprSpecific: arg3: [#Argument name#]; -// IMPLICIT_MEMBER_SKIPPED: Keyword/ExprSpecific: arg4: [#Argument name#]; +// IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; +// IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: End completions } func testImplicitMemberInArrayLiteral() { @@ -779,3 +793,26 @@ func testTypecheckedTypeExpr() { // TYPECHECKED_TYPEEXPR: Decl[Constructor]/CurrNominal: ['(']{#arg1: String#}, {#arg2: _#}[')'][#MyType<_>#]; name=arg1: String, arg2: _ // TYPECHECKED_TYPEEXPR: Decl[Constructor]/CurrNominal: ['(']{#(intVal): Int#}[')'][#MyType#]; name=intVal: Int // TYPECHECKED_TYPEEXPR: End completions + +func testPamrameterFlags(_: Int, inoutArg: inout Int, autoclosureArg: @autoclosure () -> Int, iuoArg: Int!, variadicArg: Int...) { + var intVal = 1 + testPamrameterFlags(intVal, #^ARG_PARAMFLAG_INOUT^#) +// ARG_PARAMFLAG_INOUT: Begin completions, 1 items +// ARG_PARAMFLAG_INOUT-DAG: Pattern/ExprSpecific: {#inoutArg: &Int#}[#inout Int#]; name=inoutArg: +// ARG_PARAMFLAG_INOUT: End completions + + testPamrameterFlags(intVal, inoutArg: &intVal, #^ARG_PARAMFLAG_AUTOCLOSURE^#) +// ARG_PARAMFLAG_AUTOCLOSURE: Begin completions, 1 items +// ARG_PARAMFLAG_AUTOCLOSURE-DAG: Pattern/ExprSpecific: {#autoclosureArg: Int#}[#Int#]; +// ARG_PARAMFLAG_AUTOCLOSURE: End completions + + testPamrameterFlags(intVal, inoutArg: &intVal, autoclosureArg: intVal, #^ARG_PARAMFLAG_IUO^#) +// ARG_PARAMFLAG_IUO: Begin completions, 1 items +// ARG_PARAMFLAG_IUO-DAG: Pattern/ExprSpecific: {#iuoArg: Int?#}[#Int?#]; +// ARG_PARAMFLAG_IUO: End completions + + testPamrameterFlags(intVal, inoutArg: &intVal, autoclosureArg: intVal, iuoArg: intVal, #^ARG_PARAMFLAG_VARIADIC^#) +// ARG_PARAMFLAG_VARIADIC: Begin completions, 1 items +// ARG_PARAMFLAG_VARIADIC-DAG: Pattern/ExprSpecific: {#variadicArg: Int...#}[#Int#]; +// ARG_PARAMFLAG_VARIADIC: End completions +} diff --git a/test/IDE/complete_call_as_function.swift b/test/IDE/complete_call_as_function.swift index 862bb1f26d6c4..c50070ab4ed90 100644 --- a/test/IDE/complete_call_as_function.swift +++ b/test/IDE/complete_call_as_function.swift @@ -39,7 +39,7 @@ func testCallAsFunction(add: Adder, addTy: Adder.Type) { let _ = add(x: 12, #^INSTANCE_ARG2^#) // INSTANCE_ARG2: Begin completions, 1 items -// INSTANCE_ARG2: Keyword/ExprSpecific: y: [#Argument name#]; +// INSTANCE_ARG2: Pattern/ExprSpecific: {#y: Int#}[#Int#]; // INSTANCE_ARG2: End completions let _ = addTy#^METATYPE_NO_DOT^#; @@ -105,8 +105,8 @@ func testCallAsFunctionOverloaded(fn: Functor) { fn(h: .left, #^OVERLOADED_ARG2_LABEL^#) // FIXME: Should only suggest 'v:' (rdar://problem/60346573). //OVERLOADED_ARG2_LABEL: Begin completions, 2 items -//OVERLOADED_ARG2_LABEL-DAG: Keyword/ExprSpecific: v: [#Argument name#]; -//OVERLOADED_ARG2_LABEL-DAG: Keyword/ExprSpecific: h: [#Argument name#]; +//OVERLOADED_ARG2_LABEL-DAG: Pattern/ExprSpecific: {#v: Functor.Vertical#}[#Functor.Vertical#]; +//OVERLOADED_ARG2_LABEL-DAG: Pattern/ExprSpecific: {#h: Functor.Horizontal#}[#Functor.Horizontal#]; //OVERLOADED_ARG2_LABEL: End completions fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#) diff --git a/test/IDE/complete_subscript.swift b/test/IDE/complete_subscript.swift index 499337c69c507..afd47cb1fb798 100644 --- a/test/IDE/complete_subscript.swift +++ b/test/IDE/complete_subscript.swift @@ -91,12 +91,12 @@ func test2(value: MyStruct) { let _ = MyStruct[42, #^METATYPE_LABEL^# // METATYPE_LABEL: Begin completions, 1 items -// METATYPE_LABEL-DAG: Keyword/ExprSpecific: static: [#Argument name#]; +// METATYPE_LABEL-DAG: Pattern/ExprSpecific: {#static: U#}[#U#]; // METATYPE_LABEL: End completions let _ = value[42, #^INSTANCE_LABEL^# // INSTANCE_LABEL: Begin completions, 1 items -// INSTANCE_LABEL-DAG: Keyword/ExprSpecific: instance: [#Argument name#]; +// INSTANCE_LABEL-DAG: Pattern/ExprSpecific: {#instance: U#}[#U#]; // INSTANCE_LABEL: End completions } diff --git a/test/IDE/complete_value_expr.swift b/test/IDE/complete_value_expr.swift index 906fb09bbd477..f16a8ae567156 100644 --- a/test/IDE/complete_value_expr.swift +++ b/test/IDE/complete_value_expr.swift @@ -768,7 +768,7 @@ func testInsideFunctionCall4() { func testInsideFunctionCall5() { FooStruct().instanceFunc2(42, #^INSIDE_FUNCTION_CALL_5^# // INSIDE_FUNCTION_CALL_5: Begin completions -// INSIDE_FUNCTION_CALL_5-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b: +// INSIDE_FUNCTION_CALL_5-DAG: Pattern/ExprSpecific: {#b: &Double#}[#inout Double#]; // INSIDE_FUNCTION_CALL_5: End completions }