From 8fc89fc6f5818c40c73c7215aaecc8f958a93ee3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 18 Aug 2020 09:00:24 +0200 Subject: [PATCH] java: add fix to expand 'var' type when type annotation is used (IDEA-248364) GitOrigin-RevId: 826f1e07587dc4d85214f5d0cafd5776d3448a95 --- .../analysis/AnnotationsHighlightUtil.java | 16 ++-- .../ReplaceVarWithExplicitTypeFix.java | 79 +++++++++++++++++++ .../VariableTypeCanBeExplicitInspection.java | 49 +++--------- .../var2explicit/afterTypeUseAnnotation.java | 10 +++ .../var2explicit/beforeTypeUseAnnotation.java | 10 +++ 5 files changed, 117 insertions(+), 47 deletions(-) create mode 100644 java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceVarWithExplicitTypeFix.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/afterTypeUseAnnotation.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/beforeTypeUseAnnotation.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 3de56a208d9b..b59e36561789 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.daemon.JavaErrorBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; +import com.intellij.codeInsight.daemon.impl.quickfix.ReplaceVarWithExplicitTypeFix; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; @@ -262,12 +263,7 @@ public final class AnnotationsHighlightUtil { PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); for (PsiNameValuePair attribute : attributes) { final String name = attribute.getName(); - if (name != null) { - names.add(name); - } - else { - names.add(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); - } + names.add(Objects.requireNonNullElse(name, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME)); } PsiMethod[] annotationMethods = aClass.getMethods(); @@ -379,7 +375,13 @@ public final class AnnotationsHighlightUtil { return annotationError(annotation, message); } if (typeElement.isInferredType()) { - return annotationError(annotation, JavaErrorBundle.message("annotation.not.allowed.var")); + final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(annotation) + .descriptionAndTooltip(JavaErrorBundle.message("annotation.not.allowed.var")) + .create(); + QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createDeleteFix(annotation, JavaAnalysisBundle.message("intention.text.remove.annotation"))); + QuickFixAction.registerQuickFixAction(info, new ReplaceVarWithExplicitTypeFix(typeElement)); + return info; } if (!(type instanceof PsiPrimitiveType || type instanceof PsiArrayType)) { PsiJavaCodeReferenceElement ref = getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement()); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceVarWithExplicitTypeFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceVarWithExplicitTypeFix.java new file mode 100644 index 000000000000..799bea5eb5a8 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceVarWithExplicitTypeFix.java @@ -0,0 +1,79 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.codeInsight.daemon.impl.quickfix; + +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; +import com.intellij.codeInspection.VariableTypeCanBeExplicitInspection; +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.java.analysis.JavaAnalysisBundle; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ReplaceVarWithExplicitTypeFix extends LocalQuickFixAndIntentionActionOnPsiElement { + public ReplaceVarWithExplicitTypeFix(@Nullable PsiTypeElement element) { + super(element); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return JavaAnalysisBundle.message("replace.var.with.explicit.type"); + } + + + @Override + public @IntentionName @NotNull String getText() { + return getFamilyName(); + } + + @Override + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + if (startElement instanceof PsiTypeElement) { + PsiElement parent = startElement.getParent(); + if (parent instanceof PsiParameter) { + PsiElement declarationScope = ((PsiParameter)parent).getDeclarationScope(); + if (declarationScope instanceof PsiLambdaExpression) { + for (PsiParameter parameter : ((PsiLambdaExpression)declarationScope).getParameterList().getParameters()) { + PsiTypeElement typeElement = parameter.getTypeElement(); + if (typeElement != null) { + PsiTypesUtil.replaceWithExplicitType(typeElement); + } + } + return; + } + } + PsiTypesUtil.replaceWithExplicitType((PsiTypeElement)startElement); + } + } + + @Override + public boolean isAvailable(@NotNull Project project, + @NotNull PsiFile file, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + if (startElement instanceof PsiTypeElement) { + PsiElement parent = startElement.getParent(); + if (parent instanceof PsiParameter ) { + PsiElement declarationScope = ((PsiParameter)parent).getDeclarationScope(); + if (declarationScope instanceof PsiLambdaExpression) { + return ContainerUtil.and(((PsiLambdaExpression)declarationScope).getParameterList().getParameters(), + parameter -> VariableTypeCanBeExplicitInspection.getTypeElementToExpand(parameter) != null); + } + } + if (parent instanceof PsiVariable) { + return VariableTypeCanBeExplicitInspection.getTypeElementToExpand((PsiVariable)parent) != null; + } + } + return false; + } +} \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/VariableTypeCanBeExplicitInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/VariableTypeCanBeExplicitInspection.java index 5771255181ed..cbe247a99299 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/VariableTypeCanBeExplicitInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/VariableTypeCanBeExplicitInspection.java @@ -1,12 +1,11 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection; +import com.intellij.codeInsight.daemon.impl.quickfix.ReplaceVarWithExplicitTypeFix; import com.intellij.java.analysis.JavaAnalysisBundle; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; -import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -50,49 +49,19 @@ public class VariableTypeCanBeExplicitInspection extends AbstractBaseJavaLocalIn holder.registerProblem(typeElement, JavaAnalysisBundle.message("var.can.be.replaced.with.explicit.type"), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, - new ReplaceVarWithExplicitTypeFix()); - } - - private PsiTypeElement getTypeElementToExpand(PsiVariable variable) { - PsiTypeElement typeElement = variable.getTypeElement(); - if (typeElement != null && typeElement.isInferredType()) { - PsiType type = variable.getType(); - if (PsiTypesUtil.isDenotableType(type, variable)) { - return typeElement; - } - } - return null; + new ReplaceVarWithExplicitTypeFix(typeElement)); } }; } - private static class ReplaceVarWithExplicitTypeFix implements LocalQuickFix { - @Nls - @NotNull - @Override - public String getFamilyName() { - return JavaAnalysisBundle.message("replace.var.with.explicit.type"); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiElement element = descriptor.getPsiElement(); - if (element instanceof PsiTypeElement) { - PsiElement parent = element.getParent(); - if (parent instanceof PsiParameter) { - PsiElement declarationScope = ((PsiParameter)parent).getDeclarationScope(); - if (declarationScope instanceof PsiLambdaExpression) { - for (PsiParameter parameter: ((PsiLambdaExpression)declarationScope).getParameterList().getParameters()) { - PsiTypeElement typeElement = parameter.getTypeElement(); - if (typeElement != null) { - PsiTypesUtil.replaceWithExplicitType(typeElement); - } - } - return; - } - } - PsiTypesUtil.replaceWithExplicitType((PsiTypeElement)element); + public static PsiTypeElement getTypeElementToExpand(PsiVariable variable) { + PsiTypeElement typeElement = variable.getTypeElement(); + if (typeElement != null && typeElement.isInferredType()) { + PsiType type = variable.getType(); + if (PsiTypesUtil.isDenotableType(type, variable)) { + return typeElement; } } + return null; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/afterTypeUseAnnotation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/afterTypeUseAnnotation.java new file mode 100644 index 000000000000..6524cece04b7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/afterTypeUseAnnotation.java @@ -0,0 +1,10 @@ +// "Replace 'var' with explicit type" "true" +import java.lang.annotation.*; +class Main { + { + @Anno String b = "hello"; + } +} + +@Target(ElementType.TYPE_USE) +@interface Anno {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/beforeTypeUseAnnotation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/beforeTypeUseAnnotation.java new file mode 100644 index 000000000000..46434f73fb85 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/var2explicit/beforeTypeUseAnnotation.java @@ -0,0 +1,10 @@ +// "Replace 'var' with explicit type" "true" +import java.lang.annotation.*; +class Main { + { + @Anno var b = "hello"; + } +} + +@Target(ElementType.TYPE_USE) +@interface Anno {} \ No newline at end of file