From 1f0679e103b672fc6d3af5b9be5ff48dd36f6c3c Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 28 Mar 2016 15:29:21 +0300 Subject: [PATCH] Converting to Kotlin (step 2) --- .../QuickFixFactoryForTypeMismatchError.kt | 230 ++++++++---------- 1 file changed, 108 insertions(+), 122 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt index 92cbd0d1d56..5229d1fee0c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt @@ -14,191 +14,177 @@ * limitations under the License. */ -package org.jetbrains.kotlin.idea.quickfix; +package org.jetbrains.kotlin.idea.quickfix -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.descriptors.CallableDescriptor; -import org.jetbrains.kotlin.diagnostics.Diagnostic; -import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters1; -import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2; -import org.jetbrains.kotlin.diagnostics.Errors; -import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages; -import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; -import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil; -import org.jetbrains.kotlin.idea.util.ScopeUtils; -import org.jetbrains.kotlin.idea.util.TypeUtils; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; -import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.scopes.LexicalScope; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.diagnostic.Logger +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil +import org.jetbrains.kotlin.idea.util.approximateWithResolvableType +import org.jetbrains.kotlin.idea.util.getResolutionScope +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction +import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf +import org.jetbrains.kotlin.types.typeUtil.makeNullable +import java.util.* //TODO: should use change signature to deal with cases of multiple overridden descriptors -public class QuickFixFactoryForTypeMismatchError extends KotlinIntentionActionsFactory { - private final static Logger LOG = Logger.getInstance(QuickFixFactoryForTypeMismatchError.class); +class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() { - @NotNull - @Override - protected List doCreateActions(@NotNull Diagnostic diagnostic) { - List actions = new LinkedList(); + override fun doCreateActions(diagnostic: Diagnostic): List { + val actions = LinkedList() - BindingContext context = ResolutionUtils.analyzeFully((KtFile) diagnostic.getPsiFile()); + val context = (diagnostic.psiFile as KtFile).analyzeFully() - PsiElement diagnosticElement = diagnostic.getPsiElement(); - if (!(diagnosticElement instanceof KtExpression)) { - LOG.error("Unexpected element: " + diagnosticElement.getText()); - return Collections.emptyList(); + val diagnosticElement = diagnostic.psiElement + if (diagnosticElement !is KtExpression) { + LOG.error("Unexpected element: " + diagnosticElement.text) + return emptyList() } - KtExpression expression = (KtExpression) diagnosticElement; - - KotlinType expectedType; - KotlinType expressionType; - if (diagnostic.getFactory() == Errors.TYPE_MISMATCH) { - DiagnosticWithParameters2 diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic); - expectedType = diagnosticWithParameters.getA(); - expressionType = diagnosticWithParameters.getB(); + val expectedType: KotlinType + val expressionType: KotlinType? + if (diagnostic.factory === Errors.TYPE_MISMATCH) { + val diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic) + expectedType = diagnosticWithParameters.a + expressionType = diagnosticWithParameters.b } - else if (diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE) { - DiagnosticWithParameters1 diagnosticWithParameters = - Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic); - expectedType = diagnosticWithParameters.getA(); - expressionType = TypeUtilsKt.makeNullable(expectedType); + else if (diagnostic.factory === Errors.NULL_FOR_NONNULL_TYPE) { + val diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic) + expectedType = diagnosticWithParameters.a + expressionType = expectedType.makeNullable() } - else if (diagnostic.getFactory() == Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) { - DiagnosticWithParameters2 diagnosticWithParameters = - Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic); - expectedType = diagnosticWithParameters.getB(); - expressionType = context.getType(expression); + else if (diagnostic.factory === Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) { + val diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic) + expectedType = diagnosticWithParameters.b + expressionType = context.getType(diagnosticElement) if (expressionType == null) { - LOG.error("No type inferred: " + expression.getText()); - return Collections.emptyList(); + LOG.error("No type inferred: " + diagnosticElement.text) + return emptyList() } } else { - LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic)); - return Collections.emptyList(); + LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic)) + return emptyList() } - if (TypeUtilsKt.isPrimitiveNumberType(expressionType) && TypeUtilsKt.isPrimitiveNumberType(expectedType)) { - actions.add(new NumberConversionFix(expression, expectedType)); + if (expressionType.isPrimitiveNumberType() && expectedType.isPrimitiveNumberType()) { + actions.add(NumberConversionFix(diagnosticElement, expectedType)) } // We don't want to cast a cast or type-asserted expression: - if (!(expression instanceof KtBinaryExpressionWithTypeRHS) && !(expression.getParent() instanceof KtBinaryExpressionWithTypeRHS)) { - actions.add(new CastExpressionFix(expression, expectedType)); + if (diagnosticElement !is KtBinaryExpressionWithTypeRHS && diagnosticElement.parent !is KtBinaryExpressionWithTypeRHS) { + actions.add(CastExpressionFix(diagnosticElement, expectedType)) } - if (!expectedType.isMarkedNullable() && org.jetbrains.kotlin.types.TypeUtils.isNullableType(expressionType)) { - KotlinType nullableExpected = TypeUtilsKt.makeNullable(expectedType); - if (TypeUtilsKt.isSubtypeOf(expressionType, nullableExpected)) { - actions.add(new AddExclExclCallFix(expression)); + if (!expectedType.isMarkedNullable && org.jetbrains.kotlin.types.TypeUtils.isNullableType(expressionType)) { + val nullableExpected = expectedType.makeNullable() + if (expressionType.isSubtypeOf(nullableExpected)) { + actions.add(AddExclExclCallFix(diagnosticElement)) } } // Property initializer type mismatch property type: - KtProperty property = PsiTreeUtil.getParentOfType(expression, KtProperty.class); + val property = PsiTreeUtil.getParentOfType(diagnosticElement, KtProperty::class.java) if (property != null) { - KtPropertyAccessor getter = property.getGetter(); - KtExpression initializer = property.getInitializer(); - if (QuickFixUtil.canEvaluateTo(initializer, expression) || - (getter != null && QuickFixUtil.canFunctionOrGetterReturnExpression(getter, expression))) { - LexicalScope scope = ScopeUtils.getResolutionScope(property, context, ResolutionUtils.getResolutionFacade(property)); - KotlinType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false); - actions.add(new ChangeVariableTypeFix(property, typeToInsert)); + val getter = property.getter + val initializer = property.initializer + if (QuickFixUtil.canEvaluateTo(initializer, diagnosticElement) || getter != null && QuickFixUtil.canFunctionOrGetterReturnExpression(getter, diagnosticElement)) { + val scope = property.getResolutionScope(context, property.getResolutionFacade()) + val typeToInsert = expressionType.approximateWithResolvableType(scope, false) + actions.add(ChangeVariableTypeFix(property, typeToInsert)) } } - PsiElement expressionParent = expression.getParent(); + val expressionParent = diagnosticElement.parent // Mismatch in returned expression: - KtCallableDeclaration function = expressionParent instanceof KtReturnExpression - ? BindingContextUtilsKt.getTargetFunction((KtReturnExpression) expressionParent, context) - : PsiTreeUtil.getParentOfType(expression, KtFunction.class, true); - if (function instanceof KtFunction && QuickFixUtil.canFunctionOrGetterReturnExpression(function, expression)) { - LexicalScope scope = ScopeUtils.getResolutionScope(function, context, ResolutionUtils.getResolutionFacade(function)); - KotlinType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false); - actions.add(new ChangeFunctionReturnTypeFix((KtFunction) function, typeToInsert)); + val function = if (expressionParent is KtReturnExpression) + expressionParent.getTargetFunction(context) + else + PsiTreeUtil.getParentOfType(diagnosticElement, KtFunction::class.java, true) + if (function is KtFunction && QuickFixUtil.canFunctionOrGetterReturnExpression(function, diagnosticElement)) { + val scope = function.getResolutionScope(context, function.getResolutionFacade()) + val typeToInsert = expressionType.approximateWithResolvableType(scope, false) + actions.add(ChangeFunctionReturnTypeFix(function, typeToInsert)) } // Fixing overloaded operators: - if (expression instanceof KtOperationExpression) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, context); + if (diagnosticElement is KtOperationExpression) { + val resolvedCall = diagnosticElement.getResolvedCall(context) if (resolvedCall != null) { - KtFunction declaration = getFunctionDeclaration(resolvedCall); + val declaration = getFunctionDeclaration(resolvedCall) if (declaration != null) { - actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); + actions.add(ChangeFunctionReturnTypeFix(declaration, expectedType)) } } } // Change function return type when TYPE_MISMATCH is reported on call expression: - if (expression instanceof KtCallExpression) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, context); + if (diagnosticElement is KtCallExpression) { + val resolvedCall = diagnosticElement.getResolvedCall(context) if (resolvedCall != null) { - KtFunction declaration = getFunctionDeclaration(resolvedCall); + val declaration = getFunctionDeclaration(resolvedCall) if (declaration != null) { - actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); + actions.add(ChangeFunctionReturnTypeFix(declaration, expectedType)) } } } // KT-10063: arrayOf() bounding single array element - KtAnnotationEntry annotationEntry = PsiTreeUtil.getParentOfType(expression, KtAnnotationEntry.class); + val annotationEntry = PsiTreeUtil.getParentOfType(diagnosticElement, KtAnnotationEntry::class.java) if (annotationEntry != null) { - if (KotlinBuiltIns.isArray(expectedType) && - TypeUtilsKt.isSubtypeOf(expressionType, expectedType.getArguments().get(0).getType()) || - KotlinBuiltIns.isPrimitiveArray(expectedType)) { - actions.add(new AddArrayOfTypeFix(expression, expectedType)); + if (KotlinBuiltIns.isArray(expectedType) && expressionType.isSubtypeOf(expectedType.arguments[0].type) || KotlinBuiltIns.isPrimitiveArray(expectedType)) { + actions.add(AddArrayOfTypeFix(diagnosticElement, expectedType)) } } - ResolvedCall resolvedCall = CallUtilKt.getParentResolvedCall(expression, context, true); + val resolvedCall = diagnosticElement.getParentResolvedCall(context, true) if (resolvedCall != null) { // to fix 'type mismatch' on 'if' branches // todo: the same with 'when' - KtExpression parentIf = QuickFixUtil.getParentIfForBranch(expression); - KtExpression argumentExpression = (parentIf != null) ? parentIf : expression; - ValueArgument valueArgument = CallUtilKt.getValueArgumentForExpression(resolvedCall.getCall(), argumentExpression); + val parentIf = QuickFixUtil.getParentIfForBranch(diagnosticElement) + val argumentExpression = parentIf ?: diagnosticElement + val valueArgument = resolvedCall.call.getValueArgumentForExpression(argumentExpression) if (valueArgument != null) { - KtParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument); - KtExpression expressionFromArgument = valueArgument.getArgumentExpression(); - KotlinType valueArgumentType = - diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE - ? expressionType - : expressionFromArgument != null ? context.getType(expressionFromArgument) : null; + val correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument) + val expressionFromArgument = valueArgument.getArgumentExpression() + val valueArgumentType = if (diagnostic.factory === Errors.NULL_FOR_NONNULL_TYPE) + expressionType + else if (expressionFromArgument != null) context.getType(expressionFromArgument) else null if (correspondingParameter != null && valueArgumentType != null) { - KtCallableDeclaration callable = PsiTreeUtil.getParentOfType(correspondingParameter, KtCallableDeclaration.class, true); - LexicalScope scope = callable != null ? ScopeUtils.getResolutionScope(callable, context, ResolutionUtils - .getResolutionFacade(callable)) : null; - KotlinType typeToInsert = TypeUtils.approximateWithResolvableType(valueArgumentType, scope, true); - actions.add(new ChangeParameterTypeFix(correspondingParameter, typeToInsert)); + val callable = PsiTreeUtil.getParentOfType(correspondingParameter, KtCallableDeclaration::class.java, true) + val scope = callable?.getResolutionScope(context, callable.getResolutionFacade()) + val typeToInsert = valueArgumentType.approximateWithResolvableType(scope, true) + actions.add(ChangeParameterTypeFix(correspondingParameter, typeToInsert)) } } } - return actions; + return actions } - @Nullable - private static KtFunction getFunctionDeclaration(@NotNull ResolvedCall resolvedCall) { - PsiElement result = QuickFixUtil.safeGetDeclaration(resolvedCall.getResultingDescriptor()); - if (result instanceof KtFunction) { - return (KtFunction) result; + companion object { + private val LOG = Logger.getInstance(QuickFixFactoryForTypeMismatchError::class.java) + + private fun getFunctionDeclaration(resolvedCall: ResolvedCall<*>): KtFunction? { + val result = QuickFixUtil.safeGetDeclaration(resolvedCall.resultingDescriptor) + if (result is KtFunction) { + return result + } + return null } - return null; } }