diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/NotNullFieldNotInitializedInspection.java b/java/java-impl/src/com/intellij/codeInspection/nullable/NotNullFieldNotInitializedInspection.java index e2417d887191..8f28d8ee7680 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/NotNullFieldNotInitializedInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/nullable/NotNullFieldNotInitializedInspection.java @@ -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; + } } diff --git a/java/java-impl/src/inspectionDescriptions/NotNullFieldNotInitialized.html b/java/java-impl/src/inspectionDescriptions/NotNullFieldNotInitialized.html index 4888bff59887..3f8c15bc8e2c 100644 --- a/java/java-impl/src/inspectionDescriptions/NotNullFieldNotInitialized.html +++ b/java/java-impl/src/inspectionDescriptions/NotNullFieldNotInitialized.html @@ -17,7 +17,7 @@ Reports fields annotated as not-null which are not initialized in constructor. E getValue may return null if setter was not called.

-

Use the checkbox below to control whether warning should be issued if field could be initialized implicitly - (e.g. via dependency injection).

+

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.

\ No newline at end of file diff --git a/java/java-tests/testData/inspection/notNullField/SetupJunit.java b/java/java-tests/testData/inspection/notNullField/SetupJunit.java new file mode 100644 index 000000000000..f84b64ddb12d --- /dev/null +++ b/java/java-tests/testData/inspection/notNullField/SetupJunit.java @@ -0,0 +1,14 @@ +import org.jetbrains.annotations.NotNull; + +public class SetupJunit extends junit.framework.TestCase { + @NotNull String foo; + @NotNull String bar; + + public void setUp() { + foo = "foo"; + } + + public void notSetUp() { + bar = "bar"; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/NotNullFieldNotInitializedInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/NotNullFieldNotInitializedInspectionTest.java index b201e4178b93..65b48a201825 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/NotNullFieldNotInitializedInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/NotNullFieldNotInitializedInspectionTest.java @@ -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()); diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 0307bc838710..4d0e5fad914d 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -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