From b3ad725e8d90e9aa301935fa3e5d1b2ad5786a31 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 16 Jul 2014 12:03:16 +0400 Subject: [PATCH] Added 'getParameterForArgument' util function (using resolved call) Removed similar util methods (using psi): getParameterCorrespondingToValueArgumentPassedInCall getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList --- .../lang/resolve/InlineDescriptorUtils.java | 20 +--- .../jet/lang/resolve/calls/util/callUtil.kt | 21 ++++- .../ChangeFunctionLiteralReturnTypeFix.java | 41 ++++---- .../QuickFixFactoryForTypeMismatchError.java | 30 +++--- .../jet/plugin/quickfix/QuickFixUtil.java | 94 ++++--------------- 5 files changed, 77 insertions(+), 129 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/InlineDescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/InlineDescriptorUtils.java index a364129da6a..b1a3968e56b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/InlineDescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/InlineDescriptorUtils.java @@ -26,7 +26,6 @@ import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMapping; import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatch; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; -import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.types.lang.InlineUtil; public class InlineDescriptorUtils { @@ -54,7 +53,8 @@ public class InlineDescriptorUtils { CallableDescriptor resultingDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); if (resultingDescriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) resultingDescriptor).getInlineStrategy().isInline()) { - ValueArgument argument = getContainingArgument(containingFunction, call); + ValueArgument argument = CallUtilPackage.getValueArgumentForExpression( + resolvedCall.getCall(), (JetFunctionLiteralExpression) containingFunction); if (argument != null) { ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument); if (mapping instanceof ArgumentMatch) { @@ -77,22 +77,6 @@ public class InlineDescriptorUtils { return fromFunction == containingFunctionDescriptor; } - @Nullable - public static ValueArgument getContainingArgument(PsiElement expression, @NotNull JetExpression stopAtCall) { - if (expression instanceof JetValueArgument) { - return (JetValueArgument) expression; - } - - while (expression != null && expression.getParent() != stopAtCall) { - PsiElement parent = expression.getParent(); - if (parent instanceof JetValueArgument) { - return (JetValueArgument) parent; - } - expression = parent; - } - return expression != null ? CallMaker.makeValueArgument((JetExpression) expression) : null; - } - @Nullable public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) { DeclarationDescriptor currentDescriptor = strict ? descriptor.getContainingDeclaration() : descriptor; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt index f3de919919b..edbcccf7efa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt @@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatch import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatchStatus import org.jetbrains.jet.lang.psi.Call import org.jetbrains.jet.lang.psi.ValueArgument -import org.jetbrains.jet.lang.resolve.calls.util.CallMaker import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver import org.jetbrains.jet.lang.psi.JetElement @@ -48,6 +47,8 @@ import org.jetbrains.jet.lang.psi.psiUtil.getTextWithLocation import org.jetbrains.jet.lang.descriptors.FunctionDescriptor import org.jetbrains.jet.lang.psi.JetCallExpression import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument +import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression +import org.jetbrains.jet.lang.psi.JetFunctionLiteral // resolved call @@ -74,6 +75,10 @@ public fun ResolvedCall.hasTypeMismatchErrorOnParame } } +public fun ResolvedCall.getParameterForArgument(valueArgument: ValueArgument?): ValueParameterDescriptor? { + return (valueArgument?.let { getArgumentMapping(it) } as? ArgumentMatch)?.valueParameter +} + // call public fun Call.hasUnresolvedArguments(context: BindingContext): Boolean { @@ -93,6 +98,20 @@ public fun JetCallExpression.getValueArgumentsInParentheses(): List.filterArgsInParentheses() = filter { it !is JetFunctionLiteralArgument } as List +public fun Call.getValueArgumentForExpression(expression: JetExpression): ValueArgument? { + fun JetElement.deparenthesizeStructurally(): JetElement? { + val deparenthesized = if (this is JetExpression) JetPsiUtil.deparenthesizeOnce(this, false) else this + return when { + deparenthesized != this -> deparenthesized + this is JetFunctionLiteralExpression -> this.getFunctionLiteral() + this is JetFunctionLiteral -> this.getBodyExpression() + else -> null + } + } + fun JetElement.isParenthesizedExpression() = stream(this) { it.deparenthesizeStructurally() }.any { it == expression } + return getValueArguments().firstOrNull { it?.getArgumentExpression()?.isParenthesizedExpression() ?: false } +} + // Get call / resolved call from binding context public fun JetElement.getCalleeExpressionIfAny(): JetExpression? { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java index d9e81498534..cc0fa1e1c9a 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java @@ -24,10 +24,13 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.TypeUtils; @@ -47,13 +50,13 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction resolvedCall = CallUtilPackage.getParentResolvedCall( + functionLiteralExpression, context, true); + if (resolvedCall != null) { + ValueArgument valueArgument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), functionLiteralExpression); + JetParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument); + if (correspondingParameter != null) { + JetTypeReference correspondingParameterTypeRef = correspondingParameter.getTypeReference(); + JetType parameterType = context.get(BindingContext.TYPE, correspondingParameterTypeRef); + if (parameterType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parameterType)) { + appropriateQuickFix = new ChangeParameterTypeFix(correspondingParameter, eventualFunctionLiteralType); + } + return; } - return; } - JetFunction parentFunction = PsiTreeUtil.getParentOfType(element, JetFunction.class, true); - if (parentFunction != null && QuickFixUtil.canFunctionOrGetterReturnExpression(parentFunction, element)) { + + JetFunction parentFunction = PsiTreeUtil.getParentOfType(functionLiteralExpression, JetFunction.class, true); + if (parentFunction != null && QuickFixUtil.canFunctionOrGetterReturnExpression(parentFunction, functionLiteralExpression)) { JetTypeReference parentFunctionReturnTypeRef = parentFunction.getReturnTypeRef(); JetType parentFunctionReturnType = context.get(BindingContext.TYPE, parentFunctionReturnTypeRef); if (parentFunctionReturnType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parentFunctionReturnType)) { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java index 47d487683e6..b1c3c79873f 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2; import org.jetbrains.jet.lang.diagnostics.Errors; @@ -103,24 +104,15 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF } } - // Change type of a function parameter in case TYPE_MISMATCH is reported on expression passed as value argument of call. - // 1) When an argument is a dangling function literal: - JetFunctionLiteralArgument functionLiteralArgument = - QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralArgument.class); - JetFunctionLiteralExpression functionLiteralExpression = functionLiteralArgument != null ? functionLiteralArgument.getFunctionLiteral() : null; - if (functionLiteralExpression != null && functionLiteralExpression.getBodyExpression() == expression) { - JetParameter correspondingParameter = - QuickFixUtil.getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(functionLiteralExpression); - JetType functionLiteralExpressionType = context.get(BindingContext.EXPRESSION_TYPE, functionLiteralExpression); - if (correspondingParameter != null && functionLiteralExpressionType != null) { - actions.add(new ChangeParameterTypeFix(correspondingParameter, functionLiteralExpressionType)); - } - } - // 2) When an argument is passed inside value argument list: - else { - JetValueArgument valueArgument = QuickFixUtil.getParentElementOfType(diagnostic, JetValueArgument.class); - if (valueArgument != null && QuickFixUtil.canEvaluateTo(valueArgument.getArgumentExpression(), expression)) { - JetParameter correspondingParameter = QuickFixUtil.getParameterCorrespondingToValueArgumentPassedInCall(valueArgument); + ResolvedCall resolvedCall = CallUtilPackage.getParentResolvedCall(expression, context, true); + if (resolvedCall != null) { + // to fix 'type mismatch' on 'if' branches + // todo: the same with 'when' + JetExpression parentIf = QuickFixUtil.getParentIfForBranch(expression); + JetExpression argumentExpression = (parentIf != null) ? parentIf : expression; + ValueArgument valueArgument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), argumentExpression); + if (valueArgument != null) { + JetParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument); JetType valueArgumentType = context.get(BindingContext.EXPRESSION_TYPE, valueArgument.getArgumentExpression()); if (correspondingParameter != null && valueArgumentType != null) { actions.add(new ChangeParameterTypeFix(correspondingParameter, valueArgumentType)); @@ -132,7 +124,7 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF @Nullable private static JetFunction getFunctionDeclaration(@NotNull ResolvedCall resolvedCall) { - PsiElement result = QuickFixUtil.safeGetDeclaration(resolvedCall); + PsiElement result = QuickFixUtil.safeGetDeclaration(resolvedCall.getResultingDescriptor()); if (result instanceof JetFunction) { return (JetFunction) result; } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java index 1dd20b48ff4..098e29aa712 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java @@ -23,7 +23,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; -import com.sun.codemodel.internal.JVar; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.ReadOnly; @@ -45,7 +44,6 @@ import org.jetbrains.jet.plugin.references.BuiltInsReferenceResolver; import javax.swing.*; import java.awt.*; -import java.util.List; import java.util.Set; public class QuickFixUtil { @@ -107,77 +105,16 @@ public class QuickFixUtil { } @Nullable - public static JetParameterList getParameterListOfCallee(@NotNull JetCallExpression callExpression) { - BindingContext context = ResolvePackage.getBindingContext(callExpression.getContainingJetFile()); - ResolvedCall resolvedCall = CallUtilPackage.getResolvedCall(callExpression, context); - if (resolvedCall == null) return null; - PsiElement declaration = safeGetDeclaration(resolvedCall); - if (declaration instanceof JetFunction) { - return ((JetFunction) declaration).getValueParameterList(); - } - if (declaration instanceof JetClass) { - return ((JetClass) declaration).getPrimaryConstructorParameterList(); - } - return null; - } - - @Nullable - public static PsiElement safeGetDeclaration(@NotNull ResolvedCall resolvedCall) { - List declarations = DescriptorToSourceUtils.descriptorToDeclarations(resolvedCall.getResultingDescriptor()); + public static PsiElement safeGetDeclaration(@Nullable CallableDescriptor descriptor) { //do not create fix if descriptor has more than one overridden declaration - if (declarations.size() == 1) { - return declarations.iterator().next(); - } - return null; - } - - //todo remove, use value argument to parameter map - @Nullable - public static JetParameter getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(@NotNull JetFunctionLiteralExpression functionLiteralExpression) { - JetFunctionLiteralArgument functionLiteralArgument = PsiTreeUtil.getParentOfType(functionLiteralExpression, JetFunctionLiteralArgument.class); - if (functionLiteralArgument == null || functionLiteralArgument.getFunctionLiteral() != functionLiteralExpression) return null; - if (!(functionLiteralArgument.getParent() instanceof JetCallExpression)) { - return null; - } - JetCallExpression callExpression = (JetCallExpression) functionLiteralArgument.getParent(); - JetParameterList parameterList = getParameterListOfCallee(callExpression); - if (parameterList == null) return null; - return parameterList.getParameters().get(parameterList.getParameters().size() - 1); + if (descriptor == null || descriptor.getOverriddenDescriptors().size() > 1) return null; + return DescriptorToSourceUtils.descriptorToDeclaration(descriptor); } @Nullable - public static JetParameter getParameterCorrespondingToValueArgumentPassedInCall(@NotNull JetValueArgument valueArgument) { - if (!(valueArgument.getParent() instanceof JetValueArgumentList)) { - return null; - } - JetValueArgumentList valueArgumentList = (JetValueArgumentList) valueArgument.getParent(); - if (!(valueArgumentList.getParent() instanceof JetCallExpression)) { - return null; - } - JetCallExpression callExpression = (JetCallExpression) valueArgumentList.getParent(); - JetParameterList parameterList = getParameterListOfCallee(callExpression); - if (parameterList == null) return null; - List parameters = parameterList.getParameters(); - int position = valueArgumentList.getArguments().indexOf(valueArgument); - if (position == -1) return null; - - if (valueArgument.isNamed()) { - JetValueArgumentName valueArgumentName = valueArgument.getArgumentName(); - JetSimpleNameExpression referenceExpression = valueArgumentName == null ? null : valueArgumentName.getReferenceExpression(); - String valueArgumentNameAsString = referenceExpression == null ? null : referenceExpression.getReferencedName(); - if (valueArgumentNameAsString == null) return null; - - for (JetParameter parameter: parameters) { - if (valueArgumentNameAsString.equals(parameter.getName())) { - return parameter; - } - } - return null; - } - else { - if (position >= parameters.size()) return null; - return parameters.get(position); - } + public static JetParameter getParameterDeclarationForValueArgument(@NotNull ResolvedCall resolvedCall, @Nullable ValueArgument valueArgument) { + ValueParameterDescriptor parameterDescriptor = CallUtilPackage.getParameterForArgument(resolvedCall, valueArgument); + return (JetParameter) safeGetDeclaration(parameterDescriptor); } private static boolean equalOrLastInThenOrElse(JetExpression thenOrElse, JetExpression expression) { @@ -186,6 +123,17 @@ public class QuickFixUtil { PsiTreeUtil.getNextSiblingOfType(expression, JetExpression.class) == null; } + @Nullable + public static JetIfExpression getParentIfForBranch(@Nullable JetExpression expression) { + JetIfExpression ifExpression = PsiTreeUtil.getParentOfType(expression, JetIfExpression.class, true); + if (ifExpression == null) return null; + if (equalOrLastInThenOrElse(ifExpression.getThen(), expression) + || equalOrLastInThenOrElse(ifExpression.getElse(), expression)) { + return ifExpression; + } + return null; + } + public static boolean canEvaluateTo(JetExpression parent, JetExpression child) { if (parent == null || child == null) { return false; @@ -195,12 +143,8 @@ public class QuickFixUtil { child = (JetExpression) child.getParent(); continue; } - JetIfExpression jetIfExpression = PsiTreeUtil.getParentOfType(child, JetIfExpression.class, true); - if (jetIfExpression == null) return false; - if (!equalOrLastInThenOrElse(jetIfExpression.getThen(), child) && !equalOrLastInThenOrElse(jetIfExpression.getElse(), child)) { - return false; - } - child = jetIfExpression; + child = getParentIfForBranch(child); + if (child == null) return false; } return true; }