diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/testOnly/TestOnlyInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/testOnly/TestOnlyInspection.java index d0001749ed06..d6c4c80abfd4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/testOnly/TestOnlyInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/testOnly/TestOnlyInspection.java @@ -54,7 +54,8 @@ public class TestOnlyInspection extends BaseJavaBatchLocalInspectionTool { @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder h, boolean isOnTheFly) { return new JavaElementVisitor() { - @Override public void visitCallExpression(PsiCallExpression e) { + @Override + public void visitCallExpression(PsiCallExpression e) { validate(e, e.resolveMethod(), h); } @@ -68,7 +69,7 @@ public class TestOnlyInspection extends BaseJavaBatchLocalInspectionTool { @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - if (reference.getParent() instanceof PsiNewExpression + if (reference.getParent() instanceof PsiNewExpression || reference.getParent() instanceof PsiAnonymousClass || PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class) != null) { return; @@ -82,6 +83,7 @@ public class TestOnlyInspection extends BaseJavaBatchLocalInspectionTool { private static void validate(@NotNull PsiElement reference, @Nullable PsiMember member, ProblemsHolder h) { if (member == null || !isAnnotatedAsTestOnly(member)) return; if (isInsideTestOnlyMethod(reference)) return; + if (isInsideTestOnlyField(reference)) return; if (isInsideTestClass(reference)) return; if (isUnderTestSources(reference)) return; @@ -93,7 +95,7 @@ public class TestOnlyInspection extends BaseJavaBatchLocalInspectionTool { member.hasModifierProperty(PsiModifier.PROTECTED) ? PsiModifier.PACKAGE_LOCAL : PsiModifier.PRIVATE; } - + LightModifierList modList = new LightModifierList(member.getManager(), JavaLanguage.INSTANCE, modifier); if (JavaResolveUtil.isAccessible(member, member.getContainingClass(), modList, reference, null, null)) { return; @@ -123,13 +125,16 @@ public class TestOnlyInspection extends BaseJavaBatchLocalInspectionTool { } private static boolean isInsideTestOnlyMethod(PsiElement e) { - PsiMethod m = getTopLevelParentOfType(e, PsiMethod.class); - return isAnnotatedAsTestOnly(m); + return isAnnotatedAsTestOnly(getTopLevelParentOfType(e, PsiMethod.class)); + } + + private static boolean isInsideTestOnlyField(PsiElement e) { + return isAnnotatedAsTestOnly(getTopLevelParentOfType(e, PsiField.class)); } private static boolean isAnnotatedAsTestOnly(@Nullable PsiMember m) { if (m == null) return false; - return AnnotationUtil.isAnnotated(m, AnnotationUtil.TEST_ONLY, false, false) + return AnnotationUtil.isAnnotated(m, AnnotationUtil.TEST_ONLY, false, false) || findVisibleForTestingAnnotation(m) != null || isAnnotatedAsTestOnly(m.getContainingClass()); } @@ -158,9 +163,9 @@ public class TestOnlyInspection extends BaseJavaBatchLocalInspectionTool { } private static void reportProblem(PsiElement e, PsiMember target, ProblemsHolder h) { - String message = target instanceof PsiClass - ? InspectionsBundle.message("inspection.test.only.problems.test.only.class.reference") - : InspectionsBundle.message("inspection.test.only.problems.test.only.method.call"); + String message = InspectionsBundle.message(target instanceof PsiClass + ? "inspection.test.only.problems.test.only.class.reference" + : "inspection.test.only.problems.test.only.method.call"); h.registerProblem(e, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } } diff --git a/java/java-tests/testData/inspection/testOnly/insideField/expected.xml b/java/java-tests/testData/inspection/testOnly/insideField/expected.xml new file mode 100644 index 000000000000..bf29b442fde9 --- /dev/null +++ b/java/java-tests/testData/inspection/testOnly/insideField/expected.xml @@ -0,0 +1,12 @@ + + + + A.java + 14 + testInsideField + <default> + + Test-only method is called in production code + + + diff --git a/java/java-tests/testData/inspection/testOnly/insideField/src/A.java b/java/java-tests/testData/inspection/testOnly/insideField/src/A.java new file mode 100644 index 000000000000..4c3af301bb4e --- /dev/null +++ b/java/java-tests/testData/inspection/testOnly/insideField/src/A.java @@ -0,0 +1,17 @@ +public class A { + @org.jetbrains.annotations.TestOnly + public static final String MY_FIELD = "VALUE"; + + @org.jetbrains.annotations.TestOnly + public static final Runnable MY_TEST_ONLY_RUNNABLE = new Runnable() { + public void run() { + System.out.println(MY_FIELD); + } + }; + + public static final Runnable MY_PRODUCTION_RUNNABLE = new Runnable() { + public void run() { + System.out.println(MY_FIELD); + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/testOnly/insideField/src/C.java b/java/java-tests/testData/inspection/testOnly/insideField/src/C.java new file mode 100644 index 000000000000..dbcea8c5bc7c --- /dev/null +++ b/java/java-tests/testData/inspection/testOnly/insideField/src/C.java @@ -0,0 +1,10 @@ +public class C { + @org.junit.Test + public void foo() { + new Runnable() { + public void run() { + System.out.println(A.MY_FIELD); + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/testOnly/insideField/test/D.java b/java/java-tests/testData/inspection/testOnly/insideField/test/D.java new file mode 100644 index 000000000000..3cf73676c457 --- /dev/null +++ b/java/java-tests/testData/inspection/testOnly/insideField/test/D.java @@ -0,0 +1,15 @@ +public class D { + public static final Runnable MY_RUNNABLE = new Runnable() { + public void run() { + System.out.println(A.MY_FIELD); + } + }; + + public void test() { + new Runnable() { + public void run() { + System.out.println(A.MY_FIELD); + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/TestOnlyInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/TestOnlyInspectionTest.java index 07d17637f218..1a116d820520 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/TestOnlyInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/TestOnlyInspectionTest.java @@ -29,6 +29,7 @@ public class TestOnlyInspectionTest extends InspectionTestCase { protected void setupRootModel(String testDir, VirtualFile[] sourceDir, String jdkName) { super.setupRootModel(testDir, sourceDir, jdkName); VirtualFile projectDir = LocalFileSystem.getInstance().findFileByPath(testDir); + assertNotNull(projectDir); VirtualFile test = projectDir.findChild("test"); if (test != null) PsiTestUtil.addSourceRoot(myModule, test, true); } @@ -39,29 +40,33 @@ public class TestOnlyInspectionTest extends InspectionTestCase { return new AnalysisScope(myModule); } - public void testSimple() throws Exception { + public void testSimple() { doTest(); } - public void testInsideInner() throws Exception { + public void testInsideInner() { doTest(); } - public void testConstructor() throws Exception { + public void testConstructor() { doTest(); } - public void testVisibleForTesting() throws Exception { doTest(); } + public void testVisibleForTesting() { doTest(); } - public void testUnresolved() throws Exception { + public void testUnresolved() { doTest(); // shouldn't throw } - public void testClass() throws Exception { + public void testClass() { + doTest(); + } + + public void testInsideField() { doTest(); } - private void doTest() throws Exception { + private void doTest() { TestOnlyInspection i = new TestOnlyInspection(); doTest("testOnly/" + getTestName(true), new LocalInspectionToolWrapper(i), "java 1.5"); }