[java-inspections] Quick-fix for missing not-null annotation on type element

GitOrigin-RevId: 6c7d91b8f30015eb1b5f51be422951ba8ef6b36b
This commit is contained in:
Tagir Valeev
2021-03-19 07:27:28 +00:00
committed by intellij-monorepo-bot
parent a395ba4819
commit afc371e029
8 changed files with 119 additions and 17 deletions
@@ -155,6 +155,7 @@ service.uses=Uses service <a href="#javaClass/{0}">{0}</a><br><div style='margin
suppress.for.parameter=Suppress for parameter
suppress.for.statement.with.comment=Suppress for statement with comment
intention.add.annotation.family=Add annotation
intention.add.type.annotation.family=Add type annotation
intention.text.remove.annotation=Remove
scope.package=Package {0}
@@ -0,0 +1,48 @@
// Copyright 2000-2021 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.intention;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiTypeElement;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public class AddTypeAnnotationFix implements LocalQuickFix {
private final @NotNull String myAnnotationToAdd;
@SafeFieldForPreview
private final @NotNull Collection<String> myAnnotationsToRemove;
public AddTypeAnnotationFix(@NotNull String annotationToAdd, @NotNull Collection<String> annotationsToRemove) {
myAnnotationToAdd = annotationToAdd;
myAnnotationsToRemove = annotationsToRemove;
}
@Override
public @NotNull String getName() {
return JavaAnalysisBundle.message("inspection.i18n.quickfix.annotate.as", StringUtil.getShortName(myAnnotationToAdd));
}
@Override
public @NotNull String getFamilyName() {
return JavaAnalysisBundle.message("intention.add.type.annotation.family");
}
@Override
public void applyFix(@NotNull Project project,
@NotNull ProblemDescriptor descriptor) {
PsiTypeElement typeElement = ObjectUtils.tryCast(descriptor.getStartElement(), PsiTypeElement.class);
if (typeElement == null || !typeElement.acceptsAnnotations()) return;
for (PsiAnnotation annotation : typeElement.getAnnotations()) {
if (myAnnotationsToRemove.contains(annotation.getQualifiedName())) {
annotation.delete();
}
}
typeElement.addAnnotation(myAnnotationToAdd);
}
}
@@ -7,6 +7,7 @@ import com.intellij.codeInsight.NullabilityAnnotationInfo;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.codeInsight.intention.AddTypeAnnotationFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
@@ -257,9 +258,11 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection
PsiTypeElement[] typeArguments = getReferenceTypeArguments(reference);
if (typeParameters.length > 0 && typeParameters.length == typeArguments.length && !(typeArguments[0].getType() instanceof PsiDiamondType)) {
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeElement typeArgument = typeArguments[i];
if (DfaPsiUtil.getTypeNullability(JavaPsiFacade.getElementFactory(element.getProject()).createType(typeParameters[i])) ==
Nullability.NOT_NULL && DfaPsiUtil.getTypeNullability(typeArguments[i].getType()) != Nullability.NOT_NULL) {
reportProblem(holder, typeArguments[i], "non.null.type.argument.is.expected");
Nullability.NOT_NULL && DfaPsiUtil.getTypeNullability(typeArgument.getType()) != Nullability.NOT_NULL) {
AddTypeAnnotationFix fix = new AddTypeAnnotationFix(manager.getDefaultNotNull(), manager.getNullables());
reportProblem(holder, typeArgument, fix, "non.null.type.argument.is.expected");
}
}
}
@@ -0,0 +1,7 @@
import typeUse.*;
class Bar<T extends @NotNull Object> {
public static void main(String[] args) {
Bar<<warning descr="Non-null type argument is expected">S<caret>tring</warning>> bar;
}
}
@@ -0,0 +1,7 @@
import typeUse.*;
class Bar<T extends @NotNull Object> {
public static void main(String[] args) {
Bar<<warning descr="Non-null type argument is expected">@Nullable S<caret>tring</warning>> bar;
}
}
@@ -0,0 +1,7 @@
import typeUse.*;
class Bar<T extends @NotNull Object> {
public static void main(String[] args) {
Bar<@NotNull S<caret>tring> bar;
}
}
@@ -0,0 +1,7 @@
import typeUse.*;
class Bar<T extends @NotNull Object> {
public static void main(String[] args) {
Bar<@NotNull S<caret>tring> bar;
}
}
@@ -45,6 +45,12 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest
myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
}
private void doTestWithFix(String intentionAction) {
doTest();
myFixture.launchAction(myFixture.findSingleIntention(intentionAction));
myFixture.checkResultByFile(getTestName(false) + "_after.java");
}
@Override
public void setUp() throws Exception {
super.setUp();
@@ -289,30 +295,22 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest
}
public void testAnnotateQuickFixOnMethodReference() {
doTest();
myFixture.launchAction(myFixture.findSingleIntention("Annotate"));
myFixture.checkResultByFile(getTestName(false) + "_after.java");
doTestWithFix("Annotate");
}
public void testAnnotateOverridingParametersOnNotNullMethod() {
myInspection.REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true;
doTest();
myFixture.launchAction(myFixture.findSingleIntention("Annotate overridden method parameters"));
myFixture.checkResultByFile(getTestName(false) + "_after.java");
doTestWithFix("Annotate overridden method parameters");
}
public void testRemoveMethodAnnotationRemovesOverriders() {
myInspection.REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true;
doTest();
myFixture.launchAction(myFixture.findSingleIntention("Remove annotation"));
myFixture.checkResultByFile(getTestName(false) + "_after.java");
doTestWithFix("Remove annotation");
}
public void testRemoveParameterAnnotationRemovesOverriders() {
myInspection.REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true;
doTest();
myFixture.launchAction(myFixture.findSingleIntention("Remove annotation"));
myFixture.checkResultByFile(getTestName(false) + "_after.java");
doTestWithFix("Remove annotation");
}
public void testNullPassedToNullableParameter() {
@@ -343,8 +341,32 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest
public void testOverridersHaveNonDefaultAnnotation() {
myFixture.addClass("package org.eclipse.jdt.annotation;\n\nimport java.lang.annotation.*;\n\n@Target(ElementType.PARAMETER) public @interface NonNull { }");
myInspection.REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS = true;
doTest();
myFixture.launchAction(myFixture.findSingleIntention("Annotate overridden method parameters"));
myFixture.checkResultByFile(getTestName(false) + "_after.java");
doTestWithFix("Annotate overridden method parameters");
}
public void testQuickFixOnTypeArgument() {
DataFlowInspection8Test.setupTypeUseAnnotations("typeUse", myFixture);
NullableNotNullManager manager = NullableNotNullManager.getInstance(getProject());
String oldDefault = manager.getDefaultNotNull();
try {
manager.setDefaultNotNull("typeUse.NotNull");
doTestWithFix("Annotate as @NotNull");
}
finally {
manager.setDefaultNotNull(oldDefault);
}
}
public void testQuickFixOnTypeArgumentNullable() {
DataFlowInspection8Test.setupTypeUseAnnotations("typeUse", myFixture);
NullableNotNullManager manager = NullableNotNullManager.getInstance(getProject());
String oldDefault = manager.getDefaultNotNull();
try {
manager.setDefaultNotNull("typeUse.NotNull");
doTestWithFix("Annotate as @NotNull");
}
finally {
manager.setDefaultNotNull(oldDefault);
}
}
}