@Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { if (!super.isAvailable(project, editor, file)) { return false; } JetTypeReference typeReference = annotationEntry.getTypeReference(); if (typeReference == null) { return false; } JetSimpleNameExpression referenceExpression = PsiTreeUtil.findChildOfType(typeReference, JetSimpleNameExpression.class); if (referenceExpression == null) { return false; } PsiReference reference = ReferenceUtilKt.getMainReference(referenceExpression); PsiElement target = reference.resolve(); if (target instanceof JetClass) { annotationClass = (JetClass) target; return QuickFixUtil.canModifyElement(annotationClass); } return false; }
@Nullable private static JetFunction getFunctionDeclaration(@NotNull ResolvedCall<?> resolvedCall) { PsiElement result = QuickFixUtil.safeGetDeclaration(resolvedCall.getResultingDescriptor()); if (result instanceof JetFunction) { return (JetFunction) result; } return null; }
@NotNull @Override protected List<IntentionAction> doCreateActions(@NotNull Diagnostic diagnostic) { List<IntentionAction> actions = new LinkedList<IntentionAction>(); BindingContext context = ResolutionUtils.analyzeFully((JetFile) diagnostic.getPsiFile()); PsiElement diagnosticElement = diagnostic.getPsiElement(); if (!(diagnosticElement instanceof JetExpression)) { LOG.error("Unexpected element: " + diagnosticElement.getText()); return Collections.emptyList(); } JetExpression expression = (JetExpression) diagnosticElement; JetType expectedType; JetType expressionType; if (diagnostic.getFactory() == Errors.TYPE_MISMATCH) { DiagnosticWithParameters2<JetExpression, JetType, JetType> diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic); expectedType = diagnosticWithParameters.getA(); expressionType = diagnosticWithParameters.getB(); } else if (diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE) { DiagnosticWithParameters1<JetConstantExpression, JetType> diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic); expectedType = diagnosticWithParameters.getA(); expressionType = TypeUtilsKt.makeNullable(expectedType); } else if (diagnostic.getFactory() == Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) { DiagnosticWithParameters2<JetConstantExpression, String, JetType> diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic); expectedType = diagnosticWithParameters.getB(); expressionType = context.getType(expression); if (expressionType == null) { LOG.error("No type inferred: " + expression.getText()); return Collections.emptyList(); } } else { LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic)); return Collections.emptyList(); } // We don't want to cast a cast or type-asserted expression: if (!(expression instanceof JetBinaryExpressionWithTypeRHS) && !(expression.getParent() instanceof JetBinaryExpressionWithTypeRHS)) { actions.add(new CastExpressionFix(expression, expectedType)); } // Property initializer type mismatch property type: JetProperty property = PsiTreeUtil.getParentOfType(expression, JetProperty.class); if (property != null) { JetPropertyAccessor getter = property.getGetter(); JetExpression initializer = property.getInitializer(); if (QuickFixUtil.canEvaluateTo(initializer, expression) || (getter != null && QuickFixUtil.canFunctionOrGetterReturnExpression( property.getGetter(), expression))) { LexicalScope scope = CorePackage.getResolutionScope( property, context, ResolutionUtils.getResolutionFacade(property)); JetType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false); actions.add(new ChangeVariableTypeFix(property, typeToInsert)); } } PsiElement expressionParent = expression.getParent(); // Mismatch in returned expression: JetCallableDeclaration function = expressionParent instanceof JetReturnExpression ? BindingContextUtilPackage.getTargetFunction( (JetReturnExpression) expressionParent, context) : PsiTreeUtil.getParentOfType(expression, JetFunction.class, true); if (function instanceof JetFunction && QuickFixUtil.canFunctionOrGetterReturnExpression(function, expression)) { LexicalScope scope = CorePackage.getResolutionScope( function, context, ResolutionUtils.getResolutionFacade(function)); JetType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false); actions.add(new ChangeFunctionReturnTypeFix((JetFunction) function, typeToInsert)); } // Fixing overloaded operators: if (expression instanceof JetOperationExpression) { ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context); if (resolvedCall != null) { JetFunction declaration = getFunctionDeclaration(resolvedCall); if (declaration != null) { actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); } } } // Change function return type when TYPE_MISMATCH is reported on call expression: if (expression instanceof JetCallExpression) { ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context); if (resolvedCall != null) { JetFunction declaration = getFunctionDeclaration(resolvedCall); if (declaration != null) { actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); } } } ResolvedCall<? extends CallableDescriptor> 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 = diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE ? expressionType : context.getType(valueArgument.getArgumentExpression()); if (correspondingParameter != null && valueArgumentType != null) { JetCallableDeclaration callable = PsiTreeUtil.getParentOfType( correspondingParameter, JetCallableDeclaration.class, true); LexicalScope scope = callable != null ? CorePackage.getResolutionScope( callable, context, ResolutionUtils.getResolutionFacade(callable)) : null; JetType typeToInsert = TypeUtils.approximateWithResolvableType(valueArgumentType, scope, true); actions.add(new ChangeParameterTypeFix(correspondingParameter, typeToInsert)); } } } return actions; }