NotNullFieldNotInitialized: option to ignore fields initialized in setUp() method (IDEA-CR-50086)

GitOrigin-RevId: 82fb6e512e21188ebcbd1fe4a1af66c2383fdb5f
This commit is contained in:
Tagir Valeev
2019-07-17 08:51:17 +03:00
committed by intellij-monorepo-bot
parent 1986c0f830
commit 6ef7573dee
5 changed files with 51 additions and 11 deletions
@@ -4,14 +4,14 @@ package com.intellij.codeInspection.nullable;
import com.intellij.codeInsight.Nullability;
import com.intellij.codeInsight.NullabilityAnnotationInfo;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.AddVariableInitializerFix;
import com.intellij.codeInsight.daemon.impl.quickfix.DeleteElementFix;
import com.intellij.codeInsight.daemon.impl.quickfix.InitializeFinalFieldInConstructorFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -22,13 +22,17 @@ import java.util.List;
public class NotNullFieldNotInitializedInspection extends AbstractBaseJavaLocalInspectionTool {
private static final String IGNORE_IMPLICITLY_WRITTEN_FIELDS_NAME = "IGNORE_IMPLICITLY_WRITTEN_FIELDS";
private static final String IGNORE_FIELDS_WRITTEN_IN_SETUP_NAME = "IGNORE_FIELDS_WRITTEN_IN_SETUP";
public boolean IGNORE_IMPLICITLY_WRITTEN_FIELDS = true;
public boolean IGNORE_FIELDS_WRITTEN_IN_SETUP = true;
@Nullable
@Override
public JComponent createOptionsPanel() {
return new SingleCheckboxOptionsPanel(InspectionsBundle.message("inspection.notnull.field.not.initialized.option"),
this, IGNORE_IMPLICITLY_WRITTEN_FIELDS_NAME);
MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
panel.addCheckbox(InspectionsBundle.message("inspection.notnull.field.not.initialized.option.implicit"), IGNORE_IMPLICITLY_WRITTEN_FIELDS_NAME);
panel.addCheckbox(InspectionsBundle.message("inspection.notnull.field.not.initialized.option.setup"), IGNORE_FIELDS_WRITTEN_IN_SETUP_NAME);
return panel;
}
@NotNull
@@ -46,9 +50,10 @@ public class NotNullFieldNotInitializedInspection extends AbstractBaseJavaLocalI
}
boolean implicitWrite = (IGNORE_IMPLICITLY_WRITTEN_FIELDS || isOnTheFly) && UnusedSymbolUtil.isImplicitWrite(field);
if (IGNORE_IMPLICITLY_WRITTEN_FIELDS && implicitWrite) {
return;
}
if (IGNORE_IMPLICITLY_WRITTEN_FIELDS && implicitWrite) return;
boolean writtenInSetup = (IGNORE_FIELDS_WRITTEN_IN_SETUP || isOnTheFly) && isWrittenInSetup(field);
if (IGNORE_FIELDS_WRITTEN_IN_SETUP && writtenInSetup) return;
boolean byDefault = info.isContainer();
PsiAnnotation annotation = info.getAnnotation();
@@ -61,7 +66,12 @@ public class NotNullFieldNotInitializedInspection extends AbstractBaseJavaLocalI
if (implicitWrite) {
fixes.add(new SetInspectionOptionFix(NotNullFieldNotInitializedInspection.this,
IGNORE_IMPLICITLY_WRITTEN_FIELDS_NAME,
InspectionsBundle.message("inspection.notnull.field.not.initialized.option"), true));
InspectionsBundle.message("inspection.notnull.field.not.initialized.option.implicit"), true));
}
if (writtenInSetup) {
fixes.add(new SetInspectionOptionFix(NotNullFieldNotInitializedInspection.this,
IGNORE_FIELDS_WRITTEN_IN_SETUP_NAME,
InspectionsBundle.message("inspection.notnull.field.not.initialized.option.setup"), true));
}
if (ownAnnotation) {
fixes.add(new DeleteElementFix(annotation, "Remove not-null annotation"));
@@ -75,4 +85,15 @@ public class NotNullFieldNotInitializedInspection extends AbstractBaseJavaLocalI
}
};
}
private static boolean isWrittenInSetup(PsiField field) {
PsiMethod method = TestFrameworks.getInstance().findSetUpMethod(field.getContainingClass());
if (method != null) {
PsiCodeBlock body = method.getBody();
if (body != null && HighlightControlFlowUtil.variableDefinitelyAssignedIn(field, body)) {
return true;
}
}
return false;
}
}
@@ -17,7 +17,7 @@ Reports fields annotated as not-null which are not initialized in constructor. E
<code>getValue</code> may return null if setter was not called.
</p>
<!-- tooltip end -->
<p>Use the checkbox below to control whether warning should be issued if field could be initialized implicitly
(e.g. via dependency injection).</p>
<p>Use the checkboxes below to control whether warning should be issued if field could be initialized implicitly
(e.g. via dependency injection) or if field is written in test case setUp() method.</p>
</body>
</html>
@@ -0,0 +1,14 @@
import org.jetbrains.annotations.NotNull;
public class SetupJunit extends junit.framework.TestCase {
@NotNull String foo;
<warning descr="Not-null fields must be initialized">@NotNull</warning> String bar;
public void setUp() {
foo = "foo";
}
public void notSetUp() {
bar = "bar";
}
}
@@ -44,6 +44,10 @@ public class NotNullFieldNotInitializedInspectionTest extends LightJavaCodeInsig
}, getTestRootDisposable());
doTest();
}
public void testSetupJunit() {
myFixture.addClass("package junit.framework; public class TestCase {}");
doTest();
}
private void doTest() {
myFixture.enableInspections(new NotNullFieldNotInitializedInspection());
@@ -156,7 +156,8 @@ inspection.return.separated.from.computation.quickfix=Move ''return'' closer to
inspection.return.separated.from.computation.family.quickfix=Move 'return' closer to computation of the result
inspection.notnull.field.not.initialized.display.name=@NotNull field is not initialized
inspection.notnull.field.not.initialized.option=Ignore fields which could be initialized implicitly
inspection.notnull.field.not.initialized.option.implicit=Ignore fields which could be initialized implicitly
inspection.notnull.field.not.initialized.option.setup=Ignore fields initialized in setUp() method
inspection.nullable.problems.display.name=@NotNull/@Nullable problems
#check box options