KT-4909 Smart completion does not work for named arguments

KT-7668 Named argument completion does not work after vararg

 #KT-4909 Fixed
 #KT-7668 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-05-07 19:48:52 +03:00
parent 58ac497bd7
commit 67cfd9d516
45 changed files with 474 additions and 215 deletions
@@ -69,7 +69,7 @@ public class Concat : IntrinsicMethod() {
codegen: ExpressionCodegen
): StackValue {
return StackValue.operation(returnType) {
val arguments = resolvedCall.getCall().getValueArguments().map { it.getArgumentExpression() }
val arguments = resolvedCall.getCall().getValueArguments().map { it.getArgumentExpression()!! }
val actualType = generateImpl(
codegen, it, returnType,
resolvedCall.getCall().getCallElement(),
@@ -48,7 +48,7 @@ public interface Call {
@ReadOnly
@NotNull
List<JetFunctionLiteralArgument> getFunctionLiteralArguments();
List<? extends FunctionLiteralArgument> getFunctionLiteralArguments();
@ReadOnly
@NotNull
@@ -19,14 +19,14 @@ package org.jetbrains.kotlin.psi
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiWhiteSpace
public class JetFunctionLiteralArgument(node: ASTNode) : JetValueArgument(node) {
public class JetFunctionLiteralArgument(node: ASTNode) : JetValueArgument(node), FunctionLiteralArgument {
private fun assertFL() = throw AssertionError("Function literal argument doesn't contain function literal expression: " +
"${super.getArgumentExpression()?.getText()} (it should be guaranteed by parser)")
"${super<JetValueArgument>.getArgumentExpression()?.getText()} (it should be guaranteed by parser)")
override fun getArgumentExpression() = super.getArgumentExpression() ?: assertFL()
override fun getArgumentExpression() = super<JetValueArgument>.getArgumentExpression() ?: assertFL()
public fun getFunctionLiteral(): JetFunctionLiteralExpression = unpackFunctionLiteral(getArgumentExpression())
override fun getFunctionLiteral(): JetFunctionLiteralExpression = unpackFunctionLiteral(getArgumentExpression())
private fun unpackFunctionLiteral(expression: JetExpression?): JetFunctionLiteralExpression =
when (expression) {
@@ -14,29 +14,29 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.psi;
package org.jetbrains.kotlin.psi
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.psi.impl.source.tree.LeafPsiElement
public interface ValueArgument {
@Nullable
@IfNotParsed
JetExpression getArgumentExpression();
public trait ValueArgument {
IfNotParsed
public fun getArgumentExpression(): JetExpression?
@Nullable
JetValueArgumentName getArgumentName();
public fun getArgumentName(): JetValueArgumentName?
boolean isNamed();
public fun isNamed(): Boolean
@NotNull
JetElement asElement();
public fun asElement(): JetElement
/* The '*' in something like foo(*arr) i.e. pass an array as a number of vararg arguments */
@Nullable
LeafPsiElement getSpreadElement();
public fun getSpreadElement(): LeafPsiElement?
/* The argument is placed externally to call element, e.g. in 'when' condition with subject: 'when (a) { in c -> }' */
boolean isExternal();
public fun isExternal(): Boolean
}
public trait FunctionLiteralArgument : ValueArgument {
public fun getFunctionLiteral(): JetFunctionLiteralExpression
override fun getArgumentExpression(): JetExpression
}
@@ -229,11 +229,11 @@ public class CallCompleter(
) {
if (valueArgument.isExternal()) return
val expression = valueArgument.getArgumentExpression()
val expression = valueArgument.getArgumentExpression() ?: return
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context)
if (deparenthesized == null) return
val recordedType = expression?.let { context.trace.getType(it) }
val recordedType = expression.let { context.trace.getType(it) }
var updatedType: JetType? = recordedType
val results = completeCallForArgument(deparenthesized, context)
@@ -164,7 +164,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
@NotNull
@Override
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
return Collections.emptyList();
}
@@ -213,9 +213,9 @@ import static org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMappe
D candidate = candidateCall.getCandidateDescriptor();
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
List<JetFunctionLiteralArgument> functionLiteralArguments = call.getFunctionLiteralArguments();
List<? extends FunctionLiteralArgument> functionLiteralArguments = call.getFunctionLiteralArguments();
if (!functionLiteralArguments.isEmpty()) {
JetFunctionLiteralArgument functionLiteralArgument = functionLiteralArguments.get(0);
FunctionLiteralArgument functionLiteralArgument = functionLiteralArguments.get(0);
JetExpression possiblyLabeledFunctionLiteral = functionLiteralArgument.getArgumentExpression();
if (valueParameters.isEmpty()) {
@@ -162,7 +162,7 @@ public class CallMaker {
@NotNull
@Override
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
return Collections.emptyList();
}
@NotNull
@@ -301,7 +301,7 @@ public class CallMaker {
@Override
@NotNull
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
public List<? extends FunctionLiteralArgument> getFunctionLiteralArguments() {
return callElement.getFunctionLiteralArguments();
}
@@ -72,7 +72,7 @@ public class DelegatingCall implements Call {
@Override
@NotNull
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
public List<? extends FunctionLiteralArgument> getFunctionLiteralArguments() {
return delegate.getFunctionLiteralArguments();
}
@@ -214,7 +214,7 @@ public class ControlStructureTypingUtils {
@NotNull
@Override
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
return Collections.emptyList();
}
@@ -23,6 +23,7 @@ import com.intellij.patterns.ElementPattern
import com.intellij.patterns.StandardPatterns
import com.intellij.psi.PsiCompiledElement
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.search.DelegatingGlobalSearchScope
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil
@@ -50,6 +51,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -400,21 +402,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
if (expression != null) {
val mapper = ToFromOriginalFileMapper(parameters.getOriginalFile() as JetFile, position.getContainingFile() as JetFile, parameters.getOffset())
// special completion for outside parenthesis lambda argument
if (reference != null) {
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(reference.expression)
if (receiverData != null && receiverData.second == CallType.INFIX) {
val call = receiverData.first.getCall(bindingContext)
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
val argumentIndex = call.getValueArguments().size()
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, true)
.calculateForArgument(call, argumentIndex, true)
if (expectedInfos != null) {
collector.addElements(LambdaItems.collect(expectedInfos))
}
}
}
}
addFunctionLiteralArgumentCompletions()
val completion = SmartCompletion(expression, resolutionFacade, moduleDescriptor,
bindingContext, { isVisibleDescriptor(it) }, inDescriptor, prefixMatcher, originalSearchScope,
@@ -448,6 +436,39 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
}
}
// special completion for outside parenthesis lambda argument
private fun addFunctionLiteralArgumentCompletions() {
if (reference != null) {
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(reference.expression)
if (receiverData != null && receiverData.second == CallType.INFIX) {
val call = receiverData.first.getCall(bindingContext)
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
val dummyArgument = object : FunctionLiteralArgument {
override fun getFunctionLiteral() = throw UnsupportedOperationException()
override fun getArgumentExpression() = throw UnsupportedOperationException()
override fun getArgumentName(): JetValueArgumentName? = null
override fun isNamed() = false
override fun asElement() = throw UnsupportedOperationException()
override fun getSpreadElement(): LeafPsiElement? = null
override fun isExternal() = false
}
val dummyArguments = call!!.getValueArguments() + listOf(dummyArgument)
val dummyCall = object : DelegatingCall(call) {
override fun getValueArguments() = dummyArguments
override fun getFunctionLiteralArguments() = listOf(dummyArgument)
override fun getValueArgumentList() = throw UnsupportedOperationException()
}
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, true)
.calculateForArgument(dummyCall, dummyArgument)
if (expectedInfos != null) {
collector.addElements(LambdaItems.collect(expectedInfos))
}
}
}
}
}
private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) {
getTopLevelExtensions().forEach(processor)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.di.InjectorForMacros
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.completion.smart.toList
import org.jetbrains.kotlin.idea.core.mapArgumentsToParameters
import org.jetbrains.kotlin.idea.util.makeNotNullable
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.*
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.noErrorsInValueArguments
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CompositeChecker
@@ -62,18 +64,24 @@ data class ItemOptions(val starPrefix: Boolean) {
}
}
open data class ExpectedInfo(val type: JetType, val name: String?, val tail: Tail?, val itemOptions: ItemOptions = ItemOptions.DEFAULT)
open data class ExpectedInfo(val type: JetType, val expectedName: String?, val tail: Tail?, val itemOptions: ItemOptions = ItemOptions.DEFAULT)
class PositionalArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val function: FunctionDescriptor, val parameterIndex: Int, itemOptions: ItemOptions = ItemOptions.DEFAULT)
data class ArgumentPosition(val argumentIndex: Int, val argumentName: String?, val isFunctionLiteralArgument: Boolean) {
constructor(argumentIndex: Int, isFunctionLiteralArgument: Boolean = false) : this(argumentIndex, null, isFunctionLiteralArgument)
constructor(argumentIndex: Int, argumentName: String?) : this(argumentIndex, argumentName, false)
}
class ArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val function: FunctionDescriptor, val position: ArgumentPosition, itemOptions: ItemOptions = ItemOptions.DEFAULT)
: ExpectedInfo(type, name, tail, itemOptions) {
override fun equals(other: Any?)
= other is PositionalArgumentExpectedInfo && super.equals(other) && function == other.function && parameterIndex == other.parameterIndex
= other is ArgumentExpectedInfo && super.equals(other) && function == other.function && position == other.position
override fun hashCode()
= function.hashCode()
}
class ExpectedInfos(
val bindingContext: BindingContext,
val resolutionFacade: ResolutionFacade,
@@ -97,67 +105,42 @@ class ExpectedInfos(
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val argument = expressionWithType.getParent() as? JetValueArgument ?: return null
if (argument.isNamed()) return null //TODO - support named arguments (also do not forget to check for presence of named arguments before)
val argumentList = argument.getParent() as? JetValueArgumentList ?: return null
val argumentIndex = argumentList.getArguments().indexOf(argument)
val callElement = argumentList.getParent() as? JetCallElement ?: return null
return calculateForArgument(callElement, argumentIndex, false)
return calculateForArgument(callElement, argument)
}
private fun calculateForFunctionLiteralArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val functionLiteralArgument = expressionWithType.getParent() as? JetFunctionLiteralArgument
val callExpression = functionLiteralArgument?.getParent() as? JetCallExpression
if (callExpression != null) {
if (callExpression.getFunctionLiteralArguments().firstOrNull()?.getArgumentExpression() == expressionWithType) {
return calculateForArgument(callExpression, callExpression.getValueArguments().size() - 1, true)
}
}
return null
val callExpression = functionLiteralArgument?.getParent() as? JetCallExpression ?: return null
val literalArgument = callExpression.getFunctionLiteralArguments().firstOrNull() ?: return null
if (literalArgument.getArgumentExpression() != expressionWithType) return null
return calculateForArgument(callExpression, literalArgument)
}
private fun calculateForArgument(callElement: JetCallElement, argumentIndex: Int, isFunctionLiteralArgument: Boolean): Collection<ExpectedInfo>? {
val parent = callElement.getParent()
val receiver: ReceiverValue
val callOperationNode: ASTNode?
if (parent is JetQualifiedExpression && callElement == parent.getSelectorExpression()) {
val receiverExpression = parent.getReceiverExpression()
val expressionType = bindingContext.getType(receiverExpression)
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression]
if (expressionType != null) {
receiver = ExpressionReceiver(receiverExpression, expressionType)
callOperationNode = parent.getOperationTokenNode()
}
else if (qualifier != null) {
receiver = qualifier
callOperationNode = null
}
else {
return null
}
}
else {
receiver = ReceiverValue.NO_RECEIVER
callOperationNode = null
}
val call = CallMaker.makeCall(receiver, callOperationNode, callElement)
return calculateForArgument(call, argumentIndex, isFunctionLiteralArgument)
private fun calculateForArgument(callElement: JetCallElement, argument: ValueArgument): Collection<ExpectedInfo>? {
val call = callElement.getCall(bindingContext) ?: return null
return calculateForArgument(call, argument)
}
public fun calculateForArgument(call: Call, argumentIndex: Int, isFunctionLiteralArgument: Boolean): Collection<ExpectedInfo>? {
public fun calculateForArgument(call: Call, argument: ValueArgument): Collection<ExpectedInfo>? {
val argumentIndex = call.getValueArguments().indexOf(argument)
assert(argumentIndex >= 0)
val argumentName = argument.getArgumentName()?.getReferenceExpression()?.getReferencedName()
val isFunctionLiteralArgument = argument is FunctionLiteralArgument
val argumentPosition = ArgumentPosition(argumentIndex, argumentName, isFunctionLiteralArgument)
val callElement = call.getCallElement()
val calleeExpression = call.getCalleeExpression()
val truncatedCall = if (!isFunctionLiteralArgument) { // leave only arguments before the current one
object : DelegatingCall(call) {
override fun getValueArguments() = super.getValueArguments().subList(0, argumentIndex)
override fun getValueArgumentList() = null
}
}
else {
call
}
// leave only arguments before the current one
val truncatedCall = object : DelegatingCall(call) {
val arguments = call.getValueArguments().subList(0, argumentIndex)
override fun getValueArguments() = arguments
override fun getFunctionLiteralArguments() = emptyList<FunctionLiteralArgument>()
override fun getValueArgumentList() = null
}
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return null //TODO: discuss it
val expectedType = (callElement as? JetExpression)?.let { bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, it] } ?: TypeUtils.NO_EXPECTED_TYPE
@@ -185,36 +168,30 @@ class ExpectedInfos(
val parameters = descriptor.getValueParameters()
if (parameters.isEmpty()) continue
val parameterIndex = if (isFunctionLiteralArgument) {
parameters.lastIndex
}
else {
val varArgIndex = parameters.indexOfFirst { it.getVarargElementType() != null }
if (varArgIndex < 0) {
if (parameters.size() <= argumentIndex) continue
argumentIndex
}
else {
if (argumentIndex < varArgIndex) argumentIndex else varArgIndex
}
}
val argumentToParameter = call.mapArgumentsToParameters(descriptor)
val parameter = argumentToParameter[argument] ?: continue
val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidate.getDispatchReceiver(), bindingContext)
if (!Visibilities.isVisible(thisReceiver, descriptor, resolutionScope.getContainingDeclaration())) continue
val parameter = parameters[parameterIndex]
val varargElementType = parameter.getVarargElementType()
val expectedName = if (descriptor.hasSynthesizedParameterNames()) null else parameter.getName().asString()
val varargElementType = parameter.getVarargElementType()
if (varargElementType != null) {
if (isFunctionLiteralArgument) continue
expectedInfos.add(PositionalArgumentExpectedInfo(varargElementType, expectedName?.fromPlural(), null, descriptor, parameterIndex))
if (argumentName == null) {
expectedInfos.add(ArgumentExpectedInfo(varargElementType, expectedName?.fromPlural(), null, descriptor, argumentPosition))
if (argumentIndex == parameterIndex) {
val tail = if (parameterIndex == parameters.lastIndex) Tail.RPARENTH else null
expectedInfos.add(PositionalArgumentExpectedInfo(parameter.getType(), expectedName, tail, descriptor, parameterIndex, ItemOptions.STAR_PREFIX))
if (argumentIndex == parameters.indexOf(parameter)) {
val tail = if (parameter == parameters.last()) Tail.RPARENTH else null
expectedInfos.add(ArgumentExpectedInfo(parameter.getType(), expectedName, tail, descriptor, argumentPosition, ItemOptions.STAR_PREFIX))
}
}
else {
val tail = namedArgumentTail(argumentToParameter, argumentName, descriptor)
expectedInfos.add(ArgumentExpectedInfo(varargElementType, expectedName?.fromPlural(), tail, descriptor, argumentPosition))
expectedInfos.add(ArgumentExpectedInfo(parameter.getType(), expectedName, tail, descriptor, argumentPosition, ItemOptions.STAR_PREFIX))
}
}
else {
@@ -228,28 +205,47 @@ class ExpectedInfos(
return true
}
val tail = if (isFunctionLiteralArgument)
null
else if (parameterIndex == parameters.lastIndex)
Tail.RPARENTH //TODO: support square brackets
else if (parameters.drop(parameterIndex + 1).none(::needCommaForParameter))
null
else
Tail.COMMA
val parameterType = if (useHeuristicSignatures)
HeuristicSignatures.correctedParameterType(descriptor, argumentIndex, moduleDescriptor, callElement.getProject()) ?: parameter.getType()
HeuristicSignatures.correctedParameterType(descriptor, parameter, moduleDescriptor, callElement.getProject()) ?: parameter.getType()
else
parameter.getType()
if (isFunctionLiteralArgument && !KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) continue
if (isFunctionLiteralArgument) {
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
expectedInfos.add(ArgumentExpectedInfo(parameterType, expectedName, null, descriptor, argumentPosition))
}
}
else {
val tail = if (argumentName == null) {
if (parameter == parameters.last())
Tail.RPARENTH //TODO: support square brackets
else if (parameters.dropWhile { it != parameter }.drop(1).none(::needCommaForParameter))
null
else
Tail.COMMA
}
else {
namedArgumentTail(argumentToParameter, argumentName, descriptor)
}
expectedInfos.add(PositionalArgumentExpectedInfo(parameterType, expectedName, tail, descriptor, parameterIndex))
expectedInfos.add(ArgumentExpectedInfo(parameterType, expectedName, tail, descriptor, argumentPosition))
}
}
}
return expectedInfos
}
private fun namedArgumentTail(argumentToParameter: Map<ValueArgument, ValueParameterDescriptor>, argumentName: String, descriptor: FunctionDescriptor): Tail? {
val usedParameterNames = (argumentToParameter.values().map { it.getName().asString() } + listOf(argumentName)).toSet()
val notUsedParameters = descriptor.getValueParameters().filter { it.getName().asString() !in usedParameterNames }
return if (notUsedParameters.isEmpty())
Tail.RPARENTH
else if (notUsedParameters.all { it.hasDefaultValue() })
null
else
Tail.COMMA
}
private fun calculateForEqAndAssignment(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val binaryExpression = expressionWithType.getParent() as? JetBinaryExpression
if (binaryExpression != null) {
@@ -271,7 +267,7 @@ class ExpectedInfos(
return when (expressionWithType) {
ifExpression.getCondition() -> listOf(ExpectedInfo(KotlinBuiltIns.getInstance().getBooleanType(), null, Tail.RPARENTH))
ifExpression.getThen() -> calculate(ifExpression)?.map { ExpectedInfo(it.type, it.name, Tail.ELSE) }
ifExpression.getThen() -> calculate(ifExpression)?.map { ExpectedInfo(it.type, it.expectedName, Tail.ELSE) }
ifExpression.getElse() -> {
val ifExpectedInfo = calculate(ifExpression)
@@ -312,7 +308,7 @@ class ExpectedInfos(
private fun calculateForBlockExpression(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val block = expressionWithType.getParent() as? JetBlockExpression ?: return null
if (expressionWithType != block.getStatements().last()) return null
return calculate(block)?.map { ExpectedInfo(it.type, it.name, null) }
return calculate(block)?.map { ExpectedInfo(it.type, it.expectedName, null) }
}
private fun calculateForWhenEntryValue(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
@@ -16,24 +16,25 @@
package org.jetbrains.kotlin.idea.completion
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import java.util.HashMap
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.di.InjectorForMacros
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.SubstitutionUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.di.InjectorForMacros
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.resolve.JetModuleUtil
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.JetModuleUtil
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.SubstitutionUtils
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import java.util.HashMap
public object HeuristicSignatures {
private val signatures = HashMap<Pair<FqName, Name>, List<String>>()
@@ -59,7 +60,13 @@ public object HeuristicSignatures {
signatures[FqName(classFqName) to Name.identifier(name)] = parameterTypes.toList()
}
public fun correctedParameterType(function: FunctionDescriptor, parameterIndex: Int, moduleDescriptor: ModuleDescriptor, project: Project): JetType? {
public fun correctedParameterType(function: FunctionDescriptor, parameter: ValueParameterDescriptor, moduleDescriptor: ModuleDescriptor, project: Project): JetType? {
val parameterIndex = function.getValueParameters().indexOf(parameter)
assert(parameterIndex >= 0)
return correctedParameterType(function, parameterIndex, moduleDescriptor, project)
}
private fun correctedParameterType(function: FunctionDescriptor, parameterIndex: Int, moduleDescriptor: ModuleDescriptor, project: Project): JetType? {
val ownerType = function.getDispatchReceiverParameter()?.getType() ?: return null
val superFunctions = function.getOverriddenDescriptors()
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.core.FirstChildInParentFilter
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.JetIcons
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.core.mapArgumentsToParameters
import org.jetbrains.kotlin.idea.references.JetReference
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.lexer.JetTokens
@@ -41,6 +41,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import java.util.*
object NamedParametersCompletion {
private val positionFilter = AndFilter(
@@ -83,18 +85,20 @@ object NamedParametersCompletion {
for (funDescriptor in functionDescriptors) {
if (!funDescriptor.hasStableParameterNames()) continue
val call = callElement.getCall(bindingContext) ?: continue
val usedArguments = QuickFixUtil.getUsedParameters(callElement, valueArgument, funDescriptor)
var argumentToParameter = HashMap(call.mapArgumentsToParameters(funDescriptor))
argumentToParameter.remove(valueArgument)
val usedParameters = argumentToParameter.values().toSet()
for (parameter in funDescriptor.getValueParameters()) {
val name = parameter.getName()
val nameString = name.asString()
if (nameString !in usedArguments) {
val lookupElement = LookupElementBuilder.create(nameString)
.withPresentableText("$nameString =")
if (parameter !in usedParameters) {
val name = parameter.getName().asString()
val lookupElement = LookupElementBuilder.create(name)
.withPresentableText("$name =")
.withTailText(" ${DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameter.getType())}")
.withIcon(JetIcons.PARAMETER)
.withInsertHandler(NamedParameterInsertHandler(name))
.withInsertHandler(NamedParameterInsertHandler(parameter.getName()))
.assignPriority(ItemPriority.NAMED_PARAMETER)
collector.addElement(lookupElement)
}
@@ -16,26 +16,22 @@
package org.jetbrains.kotlin.idea.completion.smart
import org.jetbrains.kotlin.idea.completion.ExpectedInfo
import org.jetbrains.kotlin.psi.JetExpression
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.ui.LayeredIcon
import com.intellij.codeInsight.lookup.LookupElementBuilder
import org.jetbrains.kotlin.idea.completion.Tail
import org.jetbrains.kotlin.idea.completion.ItemPriority
import org.jetbrains.kotlin.resolve.BindingContext
import java.util.HashSet
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.completion.PositionalArgumentExpectedInfo
import java.util.ArrayList
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.completion.assignPriority
import com.intellij.codeInsight.lookup.Lookup
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.ui.LayeredIcon
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
import org.jetbrains.kotlin.idea.completion.*
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import java.util.ArrayList
import java.util.HashSet
class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
val smartCastTypes: (VariableDescriptor) -> Collection<JetType>) {
@@ -47,7 +43,7 @@ class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
val added = HashSet<String>()
for (expectedInfo in expectedInfos) {
if (expectedInfo is PositionalArgumentExpectedInfo && expectedInfo.parameterIndex == 0) {
if (expectedInfo is ArgumentExpectedInfo && expectedInfo.position == ArgumentPosition(0)) {
val parameters = expectedInfo.function.getValueParameters()
if (parameters.size() > 1) {
val variables = ArrayList<VariableDescriptor>()
@@ -32,7 +32,7 @@ object NameSimilarityWeigher : LookupElementWeigher("kotlin.nameSimilarity") {
fun calcNameSimilarity(name: String, expectedInfos: Collection<ExpectedInfo>): Int {
return expectedInfos
.map { it.name }
.map { it.expectedName }
.filterNotNull()
.map { calcNameSimilarity(name, it) }
.max() ?: 0
@@ -130,7 +130,7 @@ class SmartCompletion(
// if we complete argument of == or !=, make types in expected info's nullable to allow nullable items too
val expectedInfos = if ((expressionWithType.getParent() as? JetBinaryExpression)?.getOperationToken() in COMPARISON_TOKENS)
filteredExpectedInfos.map { ExpectedInfo(it.type.makeNullable(), it.name, it.tail) }
filteredExpectedInfos.map { ExpectedInfo(it.type.makeNullable(), it.expectedName, it.tail) }
else
filteredExpectedInfos
@@ -58,7 +58,7 @@ class TypesWithContainsDetector(
private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean {
if (!TypeUtils.equalTypes(function.getReturnType(), booleanType)) return false
val parameter = function.getValueParameters().singleOrNull() ?: return false
val parameterType = HeuristicSignatures.correctedParameterType(function, 0, moduleDescriptor, project) ?: parameter.getType()
val parameterType = HeuristicSignatures.correctedParameterType(function, parameter, moduleDescriptor, project) ?: parameter.getType()
val fuzzyParameterType = FuzzyType(parameterType, function.getTypeParameters() + freeTypeParams)
return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null
}
@@ -107,7 +107,7 @@ fun LookupElement.withOptions(options: ItemOptions): LookupElement {
val token = context.getFile().findElementAt(offset)!!
val argument = token.getStrictParentOfType<JetValueArgument>()
if (argument != null) {
context.getDocument().insertString(argument.getTextRange().getStartOffset(), "*")
context.getDocument().insertString(argument.getArgumentExpression()!!.getTextRange().getStartOffset(), "*")
}
}
}
@@ -0,0 +1,7 @@
fun foo(vararg strings: String, option: String = ""){ }
fun bar(s: String){
foo("", "", <caret>)
}
// EXIST: { lookupString:"option", itemText:"option =" }
@@ -0,0 +1,7 @@
fun foo(vararg v: Int, s: String) { }
fun bar(s: String) {
foo(*intArrayOf(), <caret>)
}
// ELEMENT: s
@@ -0,0 +1,7 @@
fun foo(vararg v: Int, s: String) { }
fun bar(s: String) {
foo(*intArrayOf(), s)<caret>
}
// ELEMENT: s
@@ -0,0 +1,7 @@
fun foo(param1: String, param2: Int) { }
fun bar(pInt: Int) {
foo(param2 = <caret>)
}
// ELEMENT: pInt
@@ -0,0 +1,7 @@
fun foo(param1: String, param2: Int) { }
fun bar(pInt: Int) {
foo(param2 = pInt, <caret>)
}
// ELEMENT: pInt
@@ -0,0 +1,7 @@
fun foo(param1: String = "", param2: Int, param3: Int = 0) { }
fun bar(pInt: Int) {
foo(param2 = <caret>)
}
// ELEMENT: pInt
@@ -0,0 +1,7 @@
fun foo(param1: String = "", param2: Int, param3: Int = 0) { }
fun bar(pInt: Int) {
foo(param2 = pInt<caret>)
}
// ELEMENT: pInt
@@ -0,0 +1,7 @@
fun foo(param1: String, param2: Int, param3: Int) { }
fun bar(pInt: Int) {
foo("", param2 = 1, param3 = <caret>)
}
// ELEMENT: pInt
@@ -0,0 +1,7 @@
fun foo(param1: String, param2: Int, param3: Int) { }
fun bar(pInt: Int) {
foo("", param2 = 1, param3 = pInt)<caret>
}
// ELEMENT: pInt
@@ -0,0 +1,7 @@
fun foo(param1: String, vararg param2: Int) { }
fun bar(arr: IntArray) {
foo("", param2 = <caret>)
}
// ELEMENT: arr
@@ -0,0 +1,7 @@
fun foo(param1: String, vararg param2: Int) { }
fun bar(arr: IntArray) {
foo("", param2 = *arr)<caret>
}
// ELEMENT: arr
@@ -0,0 +1,7 @@
fun foo(param1: String, vararg param2: Int) { }
fun bar(p: Int) {
foo("", param2 = <caret>)
}
// ELEMENT: p
@@ -0,0 +1,7 @@
fun foo(param1: String, vararg param2: Int) { }
fun bar(p: Int) {
foo("", param2 = p)<caret>
}
// ELEMENT: p
@@ -0,0 +1,7 @@
fun foo(param1: String, vararg param2: Int) { }
fun bar(arr: IntArray) {
foo(param2 = <caret>)
}
// ELEMENT: arr
@@ -0,0 +1,7 @@
fun foo(param1: String, vararg param2: Int) { }
fun bar(arr: IntArray) {
foo(param2 = *arr, <caret>)
}
// ELEMENT: arr
@@ -0,0 +1,7 @@
fun foo(vararg v1: Int, vararg v2: Char, s: String) { }
fun bar(c: Char) {
foo(*intArrayOf(), <caret>)
}
// ELEMENT: c
@@ -0,0 +1,7 @@
fun foo(vararg v1: Int, vararg v2: Char, s: String) { }
fun bar(c: Char) {
foo(*intArrayOf(), c<caret>)
}
// ELEMENT: c
@@ -0,0 +1,8 @@
fun foo(param1: String, param2: Int) { }
fun bar(pInt: Int, pString: String) {
foo(param2 = <caret>)
}
// EXIST: pInt
// ABSENT: pString
@@ -0,0 +1,9 @@
fun foo(vararg v1: Int, vararg v2: Char, s: String) { }
fun bar(c: Char, pInt: Int) {
foo(*intArrayOf(), <caret>)
}
// EXIST: c
// ABSENT: pInt
// EXIST: { lookupString: "charArrayOf", itemText: "*charArrayOf" }
@@ -1301,6 +1301,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest(fileName);
}
@TestMetadata("AfterVararg.kt")
public void testAfterVararg() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/namedParameters/AfterVararg.kt");
doTest(fileName);
}
public void testAllFilesPresentInNamedParameters() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/namedParameters"), Pattern.compile("^(.+)\\.kt$"), true);
}
@@ -1301,6 +1301,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName);
}
@TestMetadata("AfterVararg.kt")
public void testAfterVararg() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/namedParameters/AfterVararg.kt");
doTest(fileName);
}
public void testAllFilesPresentInNamedParameters() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/namedParameters"), Pattern.compile("^(.+)\\.kt$"), true);
}
@@ -251,6 +251,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName);
}
@TestMetadata("NamedArgument.kt")
public void testNamedArgument() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/NamedArgument.kt");
doTest(fileName);
}
@TestMetadata("NoExtensionMethodFromClassObject.kt")
public void testNoExtensionMethodFromClassObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/NoExtensionMethodFromClassObject.kt");
@@ -353,6 +359,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName);
}
@TestMetadata("SecondVararg.kt")
public void testSecondVararg() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SecondVararg.kt");
doTest(fileName);
}
@TestMetadata("SkipDeclarationsOfType.kt")
public void testSkipDeclarationsOfType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SkipDeclarationsOfType.kt");
@@ -55,6 +55,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest(fileName);
}
@TestMetadata("AfterVararg.kt")
public void testAfterVararg() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/AfterVararg.kt");
doTest(fileName);
}
public void testAllFilesPresentInSmart() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/smart"), Pattern.compile("^(.+)\\.kt$"), true);
}
@@ -509,6 +515,42 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest(fileName);
}
@TestMetadata("NamedArgument1.kt")
public void testNamedArgument1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NamedArgument1.kt");
doTest(fileName);
}
@TestMetadata("NamedArgument2.kt")
public void testNamedArgument2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NamedArgument2.kt");
doTest(fileName);
}
@TestMetadata("NamedArgument3.kt")
public void testNamedArgument3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NamedArgument3.kt");
doTest(fileName);
}
@TestMetadata("NamedArgumentVararg1.kt")
public void testNamedArgumentVararg1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NamedArgumentVararg1.kt");
doTest(fileName);
}
@TestMetadata("NamedArgumentVararg2.kt")
public void testNamedArgumentVararg2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NamedArgumentVararg2.kt");
doTest(fileName);
}
@TestMetadata("NamedArgumentVararg3.kt")
public void testNamedArgumentVararg3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NamedArgumentVararg3.kt");
doTest(fileName);
}
@TestMetadata("NestedDataClass.kt")
public void testNestedDataClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NestedDataClass.kt");
@@ -587,6 +629,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest(fileName);
}
@TestMetadata("SecondVararg.kt")
public void testSecondVararg() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/SecondVararg.kt");
doTest(fileName);
}
@TestMetadata("TabReplaceComma1.kt")
public void testTabReplaceComma1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/TabReplaceComma1.kt");
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.core
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.FunctionLiteralArgument
import org.jetbrains.kotlin.psi.ValueArgument
import java.util.HashMap
public fun Call.mapArgumentsToParameters(targetDescriptor: CallableDescriptor): Map<ValueArgument, ValueParameterDescriptor> {
val parameters = targetDescriptor.getValueParameters()
if (parameters.isEmpty()) return emptyMap()
val map = HashMap<ValueArgument, ValueParameterDescriptor>()
val parametersByName = parameters.toMap { it.getName().asString() }
var positionalArgumentIndex: Int? = 0
for (argument in getValueArguments()) {
if (argument is FunctionLiteralArgument) {
map[argument] = parameters.last()
}
else {
val argumentName = argument.getArgumentName()?.getReferenceExpression()?.getReferencedName()
if (argumentName != null) {
if (targetDescriptor.hasStableParameterNames()) {
val parameter = parametersByName[argumentName]
if (parameter != null) {
map[argument] = parameter
}
}
positionalArgumentIndex = null
}
else {
if (positionalArgumentIndex != null && positionalArgumentIndex < parameters.size()) {
val parameter = parameters[positionalArgumentIndex]
map[argument] = parameter
if (parameter.getVarargElementType() == null || argument.getSpreadElement() != null) {
positionalArgumentIndex++
}
}
}
}
}
return map
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.idea.core.quickfix;
import com.google.common.collect.Sets;
import com.intellij.extapi.psi.ASTDelegatePsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -24,10 +23,8 @@ import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver;
@@ -44,8 +41,6 @@ import org.jetbrains.kotlin.types.DeferredType;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import java.util.Set;
public class QuickFixUtil {
private QuickFixUtil() {
}
@@ -167,39 +162,6 @@ public class QuickFixUtil {
}
}
@ReadOnly
@NotNull
public static Set<String> getUsedParameters(
@NotNull JetCallElement callElement,
@Nullable JetValueArgument ignoreArgument,
@NotNull CallableDescriptor callableDescriptor
) {
Set<String> usedParameters = Sets.newHashSet();
boolean isPositionalArgument = true;
int idx = 0;
for (ValueArgument argument : callElement.getValueArguments()) {
if (argument.isNamed()) {
JetValueArgumentName name = argument.getArgumentName();
assert name != null : "Named argument's name cannot be null";
if (argument != ignoreArgument) {
usedParameters.add(name.getText());
}
isPositionalArgument = false;
}
else if (isPositionalArgument) {
if (callableDescriptor.getValueParameters().size() > idx) {
ValueParameterDescriptor parameter = callableDescriptor.getValueParameters().get(idx);
if (argument != ignoreArgument) {
usedParameters.add(parameter.getName().asString());
}
idx++;
}
}
}
return usedParameters;
}
public static String renderTypeWithFqNameOnClash(JetType type, String nameToCheckAgainst) {
FqName typeFqName = DescriptorUtils.getFqNameSafe(DescriptorUtils.getClassDescriptorForType(type));
FqName fqNameToCheckAgainst = new FqName(nameToCheckAgainst);
@@ -28,6 +28,7 @@ import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
@@ -36,6 +37,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.JetIcons;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.core.CorePackage;
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
import org.jetbrains.kotlin.psi.JetCallElement;
import org.jetbrains.kotlin.psi.JetExpression;
@@ -76,13 +78,11 @@ public class AddNameToArgumentFix extends JetIntentionAction<JetValueArgument> {
CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
JetExpression argExpression = argument.getArgumentExpression();
JetType type = argExpression != null ? context.getType(argExpression) : null;
Set<String> usedParameters = QuickFixUtil.getUsedParameters(callElement, null, callableDescriptor);
Set<ValueParameterDescriptor> usedParameters = KotlinPackage.toSet( CorePackage.mapArgumentsToParameters(resolvedCall.getCall(), callableDescriptor).values());
List<String> names = Lists.newArrayList();
for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) {
String name = parameter.getName().asString();
if (usedParameters.contains(name)) continue;
if (type == null || JetTypeChecker.DEFAULT.isSubtypeOf(type, parameter.getType())) {
names.add(name);
if (!usedParameters.contains(parameter) && (type == null || JetTypeChecker.DEFAULT.isSubtypeOf(type, parameter.getType()))) {
names.add(parameter.getName().asString());
}
}
return names;