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:
@@ -69,7 +69,7 @@ public class Concat : IntrinsicMethod() {
|
|||||||
codegen: ExpressionCodegen
|
codegen: ExpressionCodegen
|
||||||
): StackValue {
|
): StackValue {
|
||||||
return StackValue.operation(returnType) {
|
return StackValue.operation(returnType) {
|
||||||
val arguments = resolvedCall.getCall().getValueArguments().map { it.getArgumentExpression() }
|
val arguments = resolvedCall.getCall().getValueArguments().map { it.getArgumentExpression()!! }
|
||||||
val actualType = generateImpl(
|
val actualType = generateImpl(
|
||||||
codegen, it, returnType,
|
codegen, it, returnType,
|
||||||
resolvedCall.getCall().getCallElement(),
|
resolvedCall.getCall().getCallElement(),
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public interface Call {
|
|||||||
|
|
||||||
@ReadOnly
|
@ReadOnly
|
||||||
@NotNull
|
@NotNull
|
||||||
List<JetFunctionLiteralArgument> getFunctionLiteralArguments();
|
List<? extends FunctionLiteralArgument> getFunctionLiteralArguments();
|
||||||
|
|
||||||
@ReadOnly
|
@ReadOnly
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ package org.jetbrains.kotlin.psi
|
|||||||
import com.intellij.lang.ASTNode
|
import com.intellij.lang.ASTNode
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
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: " +
|
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 =
|
private fun unpackFunctionLiteral(expression: JetExpression?): JetFunctionLiteralExpression =
|
||||||
when (expression) {
|
when (expression) {
|
||||||
|
|||||||
+16
-16
@@ -14,29 +14,29 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.psi;
|
package org.jetbrains.kotlin.psi
|
||||||
|
|
||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public interface ValueArgument {
|
public trait ValueArgument {
|
||||||
@Nullable
|
IfNotParsed
|
||||||
@IfNotParsed
|
public fun getArgumentExpression(): JetExpression?
|
||||||
JetExpression getArgumentExpression();
|
|
||||||
|
|
||||||
@Nullable
|
public fun getArgumentName(): JetValueArgumentName?
|
||||||
JetValueArgumentName getArgumentName();
|
|
||||||
|
|
||||||
boolean isNamed();
|
public fun isNamed(): Boolean
|
||||||
|
|
||||||
@NotNull
|
public fun asElement(): JetElement
|
||||||
JetElement asElement();
|
|
||||||
|
|
||||||
/* The '*' in something like foo(*arr) i.e. pass an array as a number of vararg arguments */
|
/* The '*' in something like foo(*arr) i.e. pass an array as a number of vararg arguments */
|
||||||
@Nullable
|
public fun getSpreadElement(): LeafPsiElement?
|
||||||
LeafPsiElement getSpreadElement();
|
|
||||||
|
|
||||||
/* The argument is placed externally to call element, e.g. in 'when' condition with subject: 'when (a) { in c -> }' */
|
/* 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
|
if (valueArgument.isExternal()) return
|
||||||
|
|
||||||
val expression = valueArgument.getArgumentExpression()
|
val expression = valueArgument.getArgumentExpression() ?: return
|
||||||
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context)
|
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context)
|
||||||
if (deparenthesized == null) return
|
if (deparenthesized == null) return
|
||||||
|
|
||||||
val recordedType = expression?.let { context.trace.getType(it) }
|
val recordedType = expression.let { context.trace.getType(it) }
|
||||||
var updatedType: JetType? = recordedType
|
var updatedType: JetType? = recordedType
|
||||||
|
|
||||||
val results = completeCallForArgument(deparenthesized, context)
|
val results = completeCallForArgument(deparenthesized, context)
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
|
public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -213,9 +213,9 @@ import static org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMappe
|
|||||||
D candidate = candidateCall.getCandidateDescriptor();
|
D candidate = candidateCall.getCandidateDescriptor();
|
||||||
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
|
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
|
||||||
|
|
||||||
List<JetFunctionLiteralArgument> functionLiteralArguments = call.getFunctionLiteralArguments();
|
List<? extends FunctionLiteralArgument> functionLiteralArguments = call.getFunctionLiteralArguments();
|
||||||
if (!functionLiteralArguments.isEmpty()) {
|
if (!functionLiteralArguments.isEmpty()) {
|
||||||
JetFunctionLiteralArgument functionLiteralArgument = functionLiteralArguments.get(0);
|
FunctionLiteralArgument functionLiteralArgument = functionLiteralArguments.get(0);
|
||||||
JetExpression possiblyLabeledFunctionLiteral = functionLiteralArgument.getArgumentExpression();
|
JetExpression possiblyLabeledFunctionLiteral = functionLiteralArgument.getArgumentExpression();
|
||||||
|
|
||||||
if (valueParameters.isEmpty()) {
|
if (valueParameters.isEmpty()) {
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public class CallMaker {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
|
public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -301,7 +301,7 @@ public class CallMaker {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
|
public List<? extends FunctionLiteralArgument> getFunctionLiteralArguments() {
|
||||||
return callElement.getFunctionLiteralArguments();
|
return callElement.getFunctionLiteralArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class DelegatingCall implements Call {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
|
public List<? extends FunctionLiteralArgument> getFunctionLiteralArguments() {
|
||||||
return delegate.getFunctionLiteralArguments();
|
return delegate.getFunctionLiteralArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -214,7 +214,7 @@ public class ControlStructureTypingUtils {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
|
public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-15
@@ -23,6 +23,7 @@ import com.intellij.patterns.ElementPattern
|
|||||||
import com.intellij.patterns.StandardPatterns
|
import com.intellij.patterns.StandardPatterns
|
||||||
import com.intellij.psi.PsiCompiledElement
|
import com.intellij.psi.PsiCompiledElement
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
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.bindingContextUtil.getDataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
|
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.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
@@ -400,21 +402,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
|||||||
if (expression != null) {
|
if (expression != null) {
|
||||||
val mapper = ToFromOriginalFileMapper(parameters.getOriginalFile() as JetFile, position.getContainingFile() as JetFile, parameters.getOffset())
|
val mapper = ToFromOriginalFileMapper(parameters.getOriginalFile() as JetFile, position.getContainingFile() as JetFile, parameters.getOffset())
|
||||||
|
|
||||||
// special completion for outside parenthesis lambda argument
|
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 argumentIndex = call.getValueArguments().size()
|
|
||||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, true)
|
|
||||||
.calculateForArgument(call, argumentIndex, true)
|
|
||||||
if (expectedInfos != null) {
|
|
||||||
collector.addElements(LambdaItems.collect(expectedInfos))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val completion = SmartCompletion(expression, resolutionFacade, moduleDescriptor,
|
val completion = SmartCompletion(expression, resolutionFacade, moduleDescriptor,
|
||||||
bindingContext, { isVisibleDescriptor(it) }, inDescriptor, prefixMatcher, originalSearchScope,
|
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) {
|
private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) {
|
||||||
getTopLevelExtensions().forEach(processor)
|
getTopLevelExtensions().forEach(processor)
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.di.InjectorForMacros
|
import org.jetbrains.kotlin.di.InjectorForMacros
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.completion.smart.toList
|
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.idea.util.makeNotNullable
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.DelegatingBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
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.callUtil.noErrorsInValueArguments
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CompositeChecker
|
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) {
|
: ExpectedInfo(type, name, tail, itemOptions) {
|
||||||
|
|
||||||
override fun equals(other: Any?)
|
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()
|
override fun hashCode()
|
||||||
= function.hashCode()
|
= function.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ExpectedInfos(
|
class ExpectedInfos(
|
||||||
val bindingContext: BindingContext,
|
val bindingContext: BindingContext,
|
||||||
val resolutionFacade: ResolutionFacade,
|
val resolutionFacade: ResolutionFacade,
|
||||||
@@ -97,67 +105,42 @@ class ExpectedInfos(
|
|||||||
|
|
||||||
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
val argument = expressionWithType.getParent() as? JetValueArgument ?: return null
|
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 argumentList = argument.getParent() as? JetValueArgumentList ?: return null
|
||||||
val argumentIndex = argumentList.getArguments().indexOf(argument)
|
|
||||||
val callElement = argumentList.getParent() as? JetCallElement ?: return null
|
val callElement = argumentList.getParent() as? JetCallElement ?: return null
|
||||||
return calculateForArgument(callElement, argumentIndex, false)
|
return calculateForArgument(callElement, argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateForFunctionLiteralArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
private fun calculateForFunctionLiteralArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
val functionLiteralArgument = expressionWithType.getParent() as? JetFunctionLiteralArgument
|
val functionLiteralArgument = expressionWithType.getParent() as? JetFunctionLiteralArgument
|
||||||
val callExpression = functionLiteralArgument?.getParent() as? JetCallExpression
|
val callExpression = functionLiteralArgument?.getParent() as? JetCallExpression ?: return null
|
||||||
if (callExpression != null) {
|
val literalArgument = callExpression.getFunctionLiteralArguments().firstOrNull() ?: return null
|
||||||
if (callExpression.getFunctionLiteralArguments().firstOrNull()?.getArgumentExpression() == expressionWithType) {
|
if (literalArgument.getArgumentExpression() != expressionWithType) return null
|
||||||
return calculateForArgument(callExpression, callExpression.getValueArguments().size() - 1, true)
|
return calculateForArgument(callExpression, literalArgument)
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateForArgument(callElement: JetCallElement, argumentIndex: Int, isFunctionLiteralArgument: Boolean): Collection<ExpectedInfo>? {
|
private fun calculateForArgument(callElement: JetCallElement, argument: ValueArgument): Collection<ExpectedInfo>? {
|
||||||
val parent = callElement.getParent()
|
val call = callElement.getCall(bindingContext) ?: return null
|
||||||
val receiver: ReceiverValue
|
return calculateForArgument(call, argument)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 callElement = call.getCallElement()
|
||||||
val calleeExpression = call.getCalleeExpression()
|
val calleeExpression = call.getCalleeExpression()
|
||||||
|
|
||||||
val truncatedCall = if (!isFunctionLiteralArgument) { // leave only arguments before the current one
|
// leave only arguments before the current one
|
||||||
object : DelegatingCall(call) {
|
val truncatedCall = object : DelegatingCall(call) {
|
||||||
override fun getValueArguments() = super.getValueArguments().subList(0, argumentIndex)
|
val arguments = call.getValueArguments().subList(0, argumentIndex)
|
||||||
override fun getValueArgumentList() = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
call
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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 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
|
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()
|
val parameters = descriptor.getValueParameters()
|
||||||
if (parameters.isEmpty()) continue
|
if (parameters.isEmpty()) continue
|
||||||
|
|
||||||
val parameterIndex = if (isFunctionLiteralArgument) {
|
val argumentToParameter = call.mapArgumentsToParameters(descriptor)
|
||||||
parameters.lastIndex
|
val parameter = argumentToParameter[argument] ?: continue
|
||||||
}
|
|
||||||
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 thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidate.getDispatchReceiver(), bindingContext)
|
val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidate.getDispatchReceiver(), bindingContext)
|
||||||
if (!Visibilities.isVisible(thisReceiver, descriptor, resolutionScope.getContainingDeclaration())) continue
|
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 expectedName = if (descriptor.hasSynthesizedParameterNames()) null else parameter.getName().asString()
|
||||||
|
|
||||||
|
val varargElementType = parameter.getVarargElementType()
|
||||||
if (varargElementType != null) {
|
if (varargElementType != null) {
|
||||||
if (isFunctionLiteralArgument) continue
|
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) {
|
if (argumentIndex == parameters.indexOf(parameter)) {
|
||||||
val tail = if (parameterIndex == parameters.lastIndex) Tail.RPARENTH else null
|
val tail = if (parameter == parameters.last()) Tail.RPARENTH else null
|
||||||
expectedInfos.add(PositionalArgumentExpectedInfo(parameter.getType(), expectedName, tail, descriptor, parameterIndex, ItemOptions.STAR_PREFIX))
|
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 {
|
else {
|
||||||
@@ -228,28 +205,47 @@ class ExpectedInfos(
|
|||||||
return true
|
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)
|
val parameterType = if (useHeuristicSignatures)
|
||||||
HeuristicSignatures.correctedParameterType(descriptor, argumentIndex, moduleDescriptor, callElement.getProject()) ?: parameter.getType()
|
HeuristicSignatures.correctedParameterType(descriptor, parameter, moduleDescriptor, callElement.getProject()) ?: parameter.getType()
|
||||||
else
|
else
|
||||||
parameter.getType()
|
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
|
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>? {
|
private fun calculateForEqAndAssignment(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
val binaryExpression = expressionWithType.getParent() as? JetBinaryExpression
|
val binaryExpression = expressionWithType.getParent() as? JetBinaryExpression
|
||||||
if (binaryExpression != null) {
|
if (binaryExpression != null) {
|
||||||
@@ -271,7 +267,7 @@ class ExpectedInfos(
|
|||||||
return when (expressionWithType) {
|
return when (expressionWithType) {
|
||||||
ifExpression.getCondition() -> listOf(ExpectedInfo(KotlinBuiltIns.getInstance().getBooleanType(), null, Tail.RPARENTH))
|
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() -> {
|
ifExpression.getElse() -> {
|
||||||
val ifExpectedInfo = calculate(ifExpression)
|
val ifExpectedInfo = calculate(ifExpression)
|
||||||
@@ -312,7 +308,7 @@ class ExpectedInfos(
|
|||||||
private fun calculateForBlockExpression(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
private fun calculateForBlockExpression(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
val block = expressionWithType.getParent() as? JetBlockExpression ?: return null
|
val block = expressionWithType.getParent() as? JetBlockExpression ?: return null
|
||||||
if (expressionWithType != block.getStatements().last()) 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>? {
|
private fun calculateForWhenEntryValue(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
|
|||||||
+19
-12
@@ -16,24 +16,25 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
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.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
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.psi.JetPsiFactory
|
||||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
import org.jetbrains.kotlin.resolve.JetModuleUtil
|
||||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
|
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.TypeUtils
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
public object HeuristicSignatures {
|
public object HeuristicSignatures {
|
||||||
private val signatures = HashMap<Pair<FqName, Name>, List<String>>()
|
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()
|
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 ownerType = function.getDispatchReceiverParameter()?.getType() ?: return null
|
||||||
|
|
||||||
val superFunctions = function.getOverriddenDescriptors()
|
val superFunctions = function.getOverriddenDescriptors()
|
||||||
|
|||||||
+12
-8
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.core.FirstChildInParentFilter
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.JetIcons
|
import org.jetbrains.kotlin.idea.JetIcons
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
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.references.JetReference
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
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.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object NamedParametersCompletion {
|
object NamedParametersCompletion {
|
||||||
private val positionFilter = AndFilter(
|
private val positionFilter = AndFilter(
|
||||||
@@ -83,18 +85,20 @@ object NamedParametersCompletion {
|
|||||||
|
|
||||||
for (funDescriptor in functionDescriptors) {
|
for (funDescriptor in functionDescriptors) {
|
||||||
if (!funDescriptor.hasStableParameterNames()) continue
|
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()) {
|
for (parameter in funDescriptor.getValueParameters()) {
|
||||||
val name = parameter.getName()
|
if (parameter !in usedParameters) {
|
||||||
val nameString = name.asString()
|
val name = parameter.getName().asString()
|
||||||
if (nameString !in usedArguments) {
|
val lookupElement = LookupElementBuilder.create(name)
|
||||||
val lookupElement = LookupElementBuilder.create(nameString)
|
.withPresentableText("$name =")
|
||||||
.withPresentableText("$nameString =")
|
|
||||||
.withTailText(" ${DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameter.getType())}")
|
.withTailText(" ${DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameter.getType())}")
|
||||||
.withIcon(JetIcons.PARAMETER)
|
.withIcon(JetIcons.PARAMETER)
|
||||||
.withInsertHandler(NamedParameterInsertHandler(name))
|
.withInsertHandler(NamedParameterInsertHandler(parameter.getName()))
|
||||||
.assignPriority(ItemPriority.NAMED_PARAMETER)
|
.assignPriority(ItemPriority.NAMED_PARAMETER)
|
||||||
collector.addElement(lookupElement)
|
collector.addElement(lookupElement)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-18
@@ -16,26 +16,22 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion.smart
|
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.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.JetType
|
||||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
||||||
val smartCastTypes: (VariableDescriptor) -> Collection<JetType>) {
|
val smartCastTypes: (VariableDescriptor) -> Collection<JetType>) {
|
||||||
@@ -47,7 +43,7 @@ class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
|||||||
|
|
||||||
val added = HashSet<String>()
|
val added = HashSet<String>()
|
||||||
for (expectedInfo in expectedInfos) {
|
for (expectedInfo in expectedInfos) {
|
||||||
if (expectedInfo is PositionalArgumentExpectedInfo && expectedInfo.parameterIndex == 0) {
|
if (expectedInfo is ArgumentExpectedInfo && expectedInfo.position == ArgumentPosition(0)) {
|
||||||
val parameters = expectedInfo.function.getValueParameters()
|
val parameters = expectedInfo.function.getValueParameters()
|
||||||
if (parameters.size() > 1) {
|
if (parameters.size() > 1) {
|
||||||
val variables = ArrayList<VariableDescriptor>()
|
val variables = ArrayList<VariableDescriptor>()
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ object NameSimilarityWeigher : LookupElementWeigher("kotlin.nameSimilarity") {
|
|||||||
|
|
||||||
fun calcNameSimilarity(name: String, expectedInfos: Collection<ExpectedInfo>): Int {
|
fun calcNameSimilarity(name: String, expectedInfos: Collection<ExpectedInfo>): Int {
|
||||||
return expectedInfos
|
return expectedInfos
|
||||||
.map { it.name }
|
.map { it.expectedName }
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
.map { calcNameSimilarity(name, it) }
|
.map { calcNameSimilarity(name, it) }
|
||||||
.max() ?: 0
|
.max() ?: 0
|
||||||
|
|||||||
+1
-1
@@ -130,7 +130,7 @@ class SmartCompletion(
|
|||||||
|
|
||||||
// if we complete argument of == or !=, make types in expected info's nullable to allow nullable items too
|
// 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)
|
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
|
else
|
||||||
filteredExpectedInfos
|
filteredExpectedInfos
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ class TypesWithContainsDetector(
|
|||||||
private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean {
|
private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean {
|
||||||
if (!TypeUtils.equalTypes(function.getReturnType(), booleanType)) return false
|
if (!TypeUtils.equalTypes(function.getReturnType(), booleanType)) return false
|
||||||
val parameter = function.getValueParameters().singleOrNull() ?: 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)
|
val fuzzyParameterType = FuzzyType(parameterType, function.getTypeParameters() + freeTypeParams)
|
||||||
return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null
|
return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ fun LookupElement.withOptions(options: ItemOptions): LookupElement {
|
|||||||
val token = context.getFile().findElementAt(offset)!!
|
val token = context.getFile().findElementAt(offset)!!
|
||||||
val argument = token.getStrictParentOfType<JetValueArgument>()
|
val argument = token.getStrictParentOfType<JetValueArgument>()
|
||||||
if (argument != null) {
|
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" }
|
||||||
+6
@@ -1301,6 +1301,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
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 {
|
public void testAllFilesPresentInNamedParameters() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/namedParameters"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/namedParameters"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -1301,6 +1301,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
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 {
|
public void testAllFilesPresentInNamedParameters() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/namedParameters"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/namedParameters"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -251,6 +251,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("NoExtensionMethodFromClassObject.kt")
|
||||||
public void testNoExtensionMethodFromClassObject() throws Exception {
|
public void testNoExtensionMethodFromClassObject() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/NoExtensionMethodFromClassObject.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/NoExtensionMethodFromClassObject.kt");
|
||||||
@@ -353,6 +359,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("SkipDeclarationsOfType.kt")
|
||||||
public void testSkipDeclarationsOfType() throws Exception {
|
public void testSkipDeclarationsOfType() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SkipDeclarationsOfType.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SkipDeclarationsOfType.kt");
|
||||||
|
|||||||
+48
@@ -55,6 +55,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
|||||||
doTest(fileName);
|
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 {
|
public void testAllFilesPresentInSmart() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/smart"), Pattern.compile("^(.+)\\.kt$"), true);
|
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);
|
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")
|
@TestMetadata("NestedDataClass.kt")
|
||||||
public void testNestedDataClass() throws Exception {
|
public void testNestedDataClass() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NestedDataClass.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/NestedDataClass.kt");
|
||||||
@@ -587,6 +629,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("TabReplaceComma1.kt")
|
||||||
public void testTabReplaceComma1() throws Exception {
|
public void testTabReplaceComma1() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/TabReplaceComma1.kt");
|
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;
|
package org.jetbrains.kotlin.idea.core.quickfix;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.intellij.extapi.psi.ASTDelegatePsiElement;
|
import com.intellij.extapi.psi.ASTDelegatePsiElement;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
@@ -24,10 +23,8 @@ import com.intellij.psi.PsiWhiteSpace;
|
|||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.ReadOnly;
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
||||||
import org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver;
|
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.JetType;
|
||||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class QuickFixUtil {
|
public class QuickFixUtil {
|
||||||
private 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) {
|
public static String renderTypeWithFqNameOnClash(JetType type, String nameToCheckAgainst) {
|
||||||
FqName typeFqName = DescriptorUtils.getFqNameSafe(DescriptorUtils.getClassDescriptorForType(type));
|
FqName typeFqName = DescriptorUtils.getFqNameSafe(DescriptorUtils.getClassDescriptorForType(type));
|
||||||
FqName fqNameToCheckAgainst = new FqName(nameToCheckAgainst);
|
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.openapi.ui.popup.util.BaseListPopupStep;
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import kotlin.KotlinPackage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
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.JetBundle;
|
||||||
import org.jetbrains.kotlin.idea.JetIcons;
|
import org.jetbrains.kotlin.idea.JetIcons;
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
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.idea.core.quickfix.QuickFixUtil;
|
||||||
import org.jetbrains.kotlin.psi.JetCallElement;
|
import org.jetbrains.kotlin.psi.JetCallElement;
|
||||||
import org.jetbrains.kotlin.psi.JetExpression;
|
import org.jetbrains.kotlin.psi.JetExpression;
|
||||||
@@ -76,13 +78,11 @@ public class AddNameToArgumentFix extends JetIntentionAction<JetValueArgument> {
|
|||||||
CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
|
CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
|
||||||
JetExpression argExpression = argument.getArgumentExpression();
|
JetExpression argExpression = argument.getArgumentExpression();
|
||||||
JetType type = argExpression != null ? context.getType(argExpression) : null;
|
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();
|
List<String> names = Lists.newArrayList();
|
||||||
for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) {
|
for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) {
|
||||||
String name = parameter.getName().asString();
|
if (!usedParameters.contains(parameter) && (type == null || JetTypeChecker.DEFAULT.isSubtypeOf(type, parameter.getType()))) {
|
||||||
if (usedParameters.contains(name)) continue;
|
names.add(parameter.getName().asString());
|
||||||
if (type == null || JetTypeChecker.DEFAULT.isSubtypeOf(type, parameter.getType())) {
|
|
||||||
names.add(name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return names;
|
return names;
|
||||||
|
|||||||
Reference in New Issue
Block a user