java: add fix to expand 'var' type when type annotation is used (IDEA-248364)

GitOrigin-RevId: 826f1e07587dc4d85214f5d0cafd5776d3448a95
This commit is contained in:
Anna Kozlova
2020-08-18 11:11:09 +00:00
committed by intellij-monorepo-bot
parent 0ef97dc482
commit 8fc89fc6f5
5 changed files with 117 additions and 47 deletions
@@ -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());
@@ -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;
}
}
@@ -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;
}
}
@@ -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 {}
@@ -0,0 +1,10 @@
// "Replace 'var' with explicit type" "true"
import java.lang.annotation.*;
class Main {
{
@An<caret>no var b = "hello";
}
}
@Target(ElementType.TYPE_USE)
@interface Anno {}