From 7d0c6385b211f255e6f7d073355bbdd0de62aff0 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 27 Aug 2014 12:17:37 +0200 Subject: [PATCH 1/9] additional project disposed check for BaseClassesAnalysisAction --- .../src/com/intellij/analysis/BaseClassesAnalysisAction.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/analysis/BaseClassesAnalysisAction.java b/java/java-impl/src/com/intellij/analysis/BaseClassesAnalysisAction.java index 383e62d40b47..42d3722fbaf3 100644 --- a/java/java-impl/src/com/intellij/analysis/BaseClassesAnalysisAction.java +++ b/java/java-impl/src/com/intellij/analysis/BaseClassesAnalysisAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,9 @@ public abstract class BaseClassesAnalysisAction extends BaseAnalysisAction { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { + if (project.isDisposed()) { + return; + } if (!upToDate) { final int i = Messages.showYesNoCancelDialog(getProject(), AnalysisScopeBundle.message("recompile.confirmation.message"), AnalysisScopeBundle.message("project.is.out.of.date"), Messages.getWarningIcon()); From a371e3dd99e0628f204ad4b62fb33abde8e0fb4c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 27 Aug 2014 12:28:59 +0200 Subject: [PATCH 2/9] SSR: better project disposed check location --- .../intellij/structuralsearch/plugin/ui/SearchCommand.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java index 9394eabc2a57..80f0c7b8ce0d 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java @@ -56,6 +56,7 @@ public class SearchCommand { } public void matchingFinished() { + if (project.isDisposed()) return; findEnded(); progress.setText(SSRBundle.message("found.progress.message", count)); } @@ -132,9 +133,7 @@ public class SearchCommand { } protected void findEnded() { - if (!project.isDisposed()) { - StructuralSearchPlugin.getInstance(project).setSearchInProgress(false); - } + StructuralSearchPlugin.getInstance(project).setSearchInProgress(false); } protected void foundUsage(MatchResult result, Usage usage) { From 90beef4af533d4df2316673a0f656f359173caf1 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 27 Aug 2014 14:25:37 +0200 Subject: [PATCH 3/9] "'native' method naming convention" inspection should not ignore static methods --- .../ig/naming/NativeMethodNamingConventionInspectionBase.java | 2 +- .../inspectionDescriptions/NativeMethodNamingConvention.html | 4 ++-- .../NativeMethodNamingConvention.java | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java index a8ceb11a11b1..2231fa152678 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java @@ -77,7 +77,7 @@ public class NativeMethodNamingConventionInspectionBase extends ConventionInspec @Override public void visitMethod(@NotNull PsiMethod method) { super.visitMethod(method); - if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) { + if (method.isConstructor()) { return; } if (!method.hasModifierProperty(PsiModifier.NATIVE)) { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html index c2e866b3d223..ecb7c975965f 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html @@ -1,11 +1,11 @@ -Reports 'native' methods whose names are either too short, too long, or do not follow +Reports native methods whose names are either too short, too long, or do not follow the specified regular expression pattern. Methods that override library methods are ignored by this inspection.

-Use the fields below to specify minimum length, maximum length and regular expression expected for 'native' method names. +Use the fields below to specify minimum length, maximum length and regular expression expected for native method names. Specify 0 to not check the length of names. Regular expressions are in standard java.util.regex format.

New in 14 diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java index 9f39c4ceb884..9b8a8e66d289 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java @@ -28,4 +28,6 @@ public class NativeMethodNamingConvention implements Runnable public native void run(); private void a() {} + + public static native void b(); } From 7d562a3ec5eee554732ba759c3f4446f99b7b591 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 27 Aug 2014 14:36:34 +0200 Subject: [PATCH 4/9] IG: ignore native methods automatically when "'native' method naming convention" inspection is enabled, instead of using checkbox --- ...tanceMethodNamingConventionInspectionBase.java | 15 +-------------- ...taticMethodNamingConventionInspectionBase.java | 15 +-------------- .../InstanceMethodNamingConvention.html | 2 -- .../NativeMethodNamingConvention.html | 2 ++ .../StaticMethodNamingConvention.html | 2 -- ...tanceMethodNamingConventionInspectionTest.java | 8 ++++++++ ...taticMethodNamingConventionInspectionTest.java | 8 ++++++++ 7 files changed, 20 insertions(+), 32 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java index 3ec38f55053c..e04b515e7cbc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java @@ -18,22 +18,16 @@ package com.siyeh.ig.naming; import com.intellij.psi.PsiIdentifier; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; -import com.intellij.util.ui.CheckBox; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.LibraryUtil; import com.siyeh.ig.psiutils.MethodUtils; import org.jetbrains.annotations.NotNull; -import javax.swing.*; - public class InstanceMethodNamingConventionInspectionBase extends ConventionInspection { private static final int DEFAULT_MIN_LENGTH = 4; private static final int DEFAULT_MAX_LENGTH = 32; - @SuppressWarnings("PublicField") - public boolean ignoreNativeMethods = true; - @Override @NotNull public String getDisplayName() { @@ -58,13 +52,6 @@ public class InstanceMethodNamingConventionInspectionBase extends ConventionInsp return InspectionGadgetsBundle.message("instance.method.name.convention.problem.descriptor.regex.mismatch", getRegex()); } - @Override - public JComponent[] createExtraOptions() { - return new JComponent[] { - new CheckBox("ignore 'native' methods", this, "ignoreNativeMethods") - }; - } - @Override protected String getDefaultRegex() { return "[a-z][A-Za-z\\d]*"; @@ -93,7 +80,7 @@ public class InstanceMethodNamingConventionInspectionBase extends ConventionInsp if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) { return; } - if (ignoreNativeMethods && method.hasModifierProperty(PsiModifier.NATIVE)) { + if (method.hasModifierProperty(PsiModifier.NATIVE) && isInspectionEnabled("NativeMethodNamingConvention", method)) { return; } final PsiIdentifier nameIdentifier = method.getNameIdentifier(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java index 116d2208e452..3e0d08998ec0 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java @@ -17,20 +17,14 @@ package com.siyeh.ig.naming; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; -import com.intellij.util.ui.CheckBox; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspectionVisitor; import org.jetbrains.annotations.NotNull; -import javax.swing.*; - public class StaticMethodNamingConventionInspectionBase extends ConventionInspection { private static final int DEFAULT_MIN_LENGTH = 4; private static final int DEFAULT_MAX_LENGTH = 32; - @SuppressWarnings("PublicField") - public boolean ignoreNativeMethods = true; - @Override @NotNull public String getDisplayName() { @@ -60,13 +54,6 @@ public class StaticMethodNamingConventionInspectionBase extends ConventionInspec getRegex()); } - @Override - public JComponent[] createExtraOptions() { - return new JComponent[]{ - new CheckBox("ignore 'native' methods", this, "ignoreNativeMethods") - }; - } - @Override protected String getDefaultRegex() { return "[a-z][A-Za-z\\d]*"; @@ -95,7 +82,7 @@ public class StaticMethodNamingConventionInspectionBase extends ConventionInspec if (!method.hasModifierProperty(PsiModifier.STATIC)) { return; } - if (ignoreNativeMethods && method.hasModifierProperty(PsiModifier.NATIVE)) { + if (method.hasModifierProperty(PsiModifier.NATIVE) && isInspectionEnabled("NativeMethodNamingConvention", method)) { return; } final String name = method.getName(); diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html index a6933cf0c7b8..4bf1c67710c5 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html @@ -8,8 +8,6 @@ methods are ignored by this inspection. Use the fields below to specify minimum length, maximum length and regular expression expected for instance method names. Specify 0 to not check the length of names. Regular expressions are in standard java.util.regex format.

-Use the checkbox below to ignore native methods. -

\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html index ecb7c975965f..2ffd3a2a27a3 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html @@ -3,6 +3,8 @@ Reports native methods whose names are either too short, too long, or do not follow the specified regular expression pattern. Methods that override library methods are ignored by this inspection. +When this inspection is enabled, the Instance method naming convention and +'static' method naming convention inspections will ignore native methods automatically.

Use the fields below to specify minimum length, maximum length and regular expression expected for native method names. diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html index 37d12a6af08d..c0ced0ba01bd 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html @@ -7,8 +7,6 @@ the specified regular expression pattern. Use the fields below to specify minimum length, maximum length and regular expression expected for static method names. Specify 0 to not check the length of names. Regular expressions are in standard java.util.regex format.

-Use the checkbox below to ignore native methods. -

\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java index e408509b51d5..6479236acbb3 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java @@ -23,6 +23,14 @@ import com.siyeh.ig.LightInspectionTestCase; */ public class InstanceMethodNamingConventionInspectionTest extends LightInspectionTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + final NativeMethodNamingConventionInspection inspection = new NativeMethodNamingConventionInspection(); + inspection.m_minLength = 0; + myFixture.enableInspections(inspection); + } + @Override protected InspectionProfileEntry getInspection() { return new InstanceMethodNamingConventionInspection(); diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java index 53e2b6a37f87..5c1eb29822c9 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java @@ -23,6 +23,14 @@ import com.siyeh.ig.LightInspectionTestCase; */ public class StaticMethodNamingConventionInspectionTest extends LightInspectionTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + final NativeMethodNamingConventionInspection inspection = new NativeMethodNamingConventionInspection(); + inspection.m_minLength = 0; + myFixture.enableInspections(inspection); + } + @Override protected InspectionProfileEntry getInspection() { return new StaticMethodNamingConventionInspection(); From 95e967e93f959c5fadee95172ab2198f53073bcc Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 28 Aug 2014 10:01:20 +0200 Subject: [PATCH 5/9] simplify and test "Test method with incorrect signature" inspection --- ...TestMethodIsPublicVoidNoArgInspection.java | 31 ++++--------- .../src/com/siyeh/ig/psiutils/TestUtils.java | 45 +++++++++--------- .../TestMethodIsPublicVoidNoArg.html | 4 +- .../JUnit3TestMethodIsPublicVoidNoArg.java | 16 +++++++ .../JUnit4TestMethodIsPublicVoidNoArg.java | 24 ++++++++++ ...MethodIsPublicVoidNoArgInspectionTest.java | 46 +++++++++++++++++++ 6 files changed, 122 insertions(+), 44 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java index 02d8cd5b7c8e..4b9a794a143a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,14 @@ */ package com.siyeh.ig.junit; -import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiParameterList; +import com.intellij.psi.PsiType; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.TestUtils; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class TestMethodIsPublicVoidNoArgInspection extends BaseInspection { @@ -70,23 +70,20 @@ public class TestMethodIsPublicVoidNoArgInspection extends BaseInspection { @Override public void visitMethod(@NotNull PsiMethod method) { //note: no call to super; - @NonNls final String methodName = method.getName(); - if (!methodName.startsWith("test") && - !TestUtils.isJUnit4TestMethod(method)) { + if (method.isConstructor()) { + return; + } + if (!TestUtils.isJUnit3TestMethod(method) && !TestUtils.isJUnit4TestMethod(method)) { return; } final PsiType returnType = method.getReturnType(); - if (returnType == null) { - return; - } final PsiParameterList parameterList = method.getParameterList(); final boolean takesArguments; final boolean isStatic; if (parameterList.getParametersCount() == 0) { takesArguments = false; isStatic = method.hasModifierProperty(PsiModifier.STATIC); - if (!isStatic && returnType.equals(PsiType.VOID) && - method.hasModifierProperty(PsiModifier.PUBLIC)) { + if (!isStatic && PsiType.VOID.equals(returnType) && method.hasModifierProperty(PsiModifier.PUBLIC)) { return; } } @@ -94,14 +91,6 @@ public class TestMethodIsPublicVoidNoArgInspection extends BaseInspection { isStatic = false; takesArguments = true; } - final PsiClass targetClass = method.getContainingClass(); - if (!AnnotationUtil.isAnnotated(method, "org.junit.Test", true)) { - if (targetClass == null || - !InheritanceUtil.isInheritor(targetClass, - "junit.framework.TestCase")) { - return; - } - } registerMethodError(method, Boolean.valueOf(takesArguments), Boolean.valueOf(isStatic)); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java index cf2133299768..dcaf8390dc5d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.util.*; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -66,34 +66,37 @@ public class TestUtils { } public static boolean isJUnitTestMethod(@Nullable PsiMethod method) { + return isRunnable(method) && (isJUnit3TestMethod(method) || isJUnit4TestMethod(method)); + } + + public static boolean isRunnable(PsiMethod method) { if (method == null) { return false; } - if (isJUnit4TestMethod(method)) { - return true; + if (method.hasModifierProperty(PsiModifier.ABSTRACT) || + method.hasModifierProperty(PsiModifier.STATIC) || + !method.hasModifierProperty(PsiModifier.PUBLIC)) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!PsiType.VOID.equals(returnType)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + return parameterList.getParametersCount() == 0; + } + + public static boolean isJUnit3TestMethod(@Nullable PsiMethod method) { + if (method == null) { + return false; } final String methodName = method.getName(); @NonNls final String test = "test"; if (!methodName.startsWith(test)) { return false; } - if (method.hasModifierProperty(PsiModifier.ABSTRACT) || - !method.hasModifierProperty(PsiModifier.PUBLIC)) { - return false; - } - final PsiType returnType = method.getReturnType(); - if (returnType == null) { - return false; - } - if (!returnType.equals(PsiType.VOID)) { - return false; - } - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.getParametersCount() != 0) { - return false; - } - final PsiClass targetClass = method.getContainingClass(); - return isJUnitTestClass(targetClass); + final PsiClass containingClass = method.getContainingClass(); + return isJUnitTestClass(containingClass); } public static boolean isJUnit4TestMethod(@Nullable PsiMethod method) { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html index a31b39a1a710..fe227cae1fbc 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html @@ -1,8 +1,8 @@ -Reports any JUnit test methods whose names which are not declared +Reports any JUnit test methods which are declared static, not declared public, do not return -void, or take arguments. +void, or have parameters. Such test methods are easy to create inadvertently, but will not be executed by JUnit test runners. diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java new file mode 100644 index 000000000000..68a5df1305f6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java @@ -0,0 +1,16 @@ +public class JUnit3TestMethodIsPublicVoidNoArg extends junit.framework.TestCase { + + public JUnit3TestMethodIsPublicVoidNoArg() {} + + void testOne() {} + + public int testTwo() { + return 2; + } + + public static void testThree() {} + + public void testFour(int i) {} + + public void testFive() {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java new file mode 100644 index 000000000000..8641acb3b49e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java @@ -0,0 +1,24 @@ +import org.junit.Test; + +public class JUnit4TestMethodIsPublicVoidNoArg { + + @Test + JUnit4TestMethodIsPublicVoidNoArg() {} + + @Test + void testOne() {} + + @Test + public int testTwo() { + return 2; + } + + @Test + public static void testThree() {} + + @Test + public void testFour(int i) {} + + @Test + public void testFive() {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java new file mode 100644 index 000000000000..72406191f2b1 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class TestMethodIsPublicVoidNoArgInspectionTest extends LightInspectionTestCase { + + public void testJUnit3TestMethodIsPublicVoidNoArg() { doTest(); } + public void testJUnit4TestMethodIsPublicVoidNoArg() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new TestMethodIsPublicVoidNoArgInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package org.junit; " + + "public @interface Test {\n" + + " java.lang.Class expected() default org.junit.Test.None.class;" + + "}", + "package junit.framework;" + + "public abstract class TestCase {}"}; + } +} From 806745bf0747b37974d77fda5c055c35c84dccce Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 28 Aug 2014 10:05:03 +0200 Subject: [PATCH 6/9] test for "JUnit test case with no tests" inspection --- .../TestCaseWithNoTestMethodsInspection.java | 15 ------- .../TestCaseWithNoTestMethods.java | 19 ++++++++ ...stCaseWithNoTestMethodsInspectionTest.java | 45 +++++++++++++++++++ 3 files changed, 64 insertions(+), 15 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java deleted file mode 100644 index f2f0afea3a7c..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.siyeh.igtest.junit; - -import junit.framework.TestCase; - -public class TestCaseWithNoTestMethodsInspection extends TestCase -{ - public TestCaseWithNoTestMethodsInspection() - { - } - - public void teardown() - { - - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java new file mode 100644 index 000000000000..559dcce72720 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java @@ -0,0 +1,19 @@ +public class TestCaseWithNoTestMethods extends junit.framework.TestCase { + + TestCaseWithNoTestMethods() {} + + public int testOne() { + return 1; + } + + public static void testTwo() {} + void testThree() {} + public void testFour(int i) {} + + public void setUp() throws Exception { + super.setUp(); + } + public void tearDown() throws Exception { + super.tearDown(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java new file mode 100644 index 000000000000..e8566eacdcd0 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class TestCaseWithNoTestMethodsInspectionTest extends LightInspectionTestCase { + + public void testTestCaseWithNoTestMethods() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new TestCaseWithNoTestMethodsInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package junit.framework;" + + "public abstract class TestCase {" + + " protected void setUp() throws Exception {}" + + " protected void tearDown() throws Exception {}" + + "}" + }; + } +} From eab9301a5b5fe4a0a23cfccfab74f76bfbb80037 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 28 Aug 2014 10:47:50 +0200 Subject: [PATCH 7/9] move test to correct location --- .../ig/naming => }/OverloadedVarargsMethodInspectionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/{com/siyeh/ig/naming => }/OverloadedVarargsMethodInspectionTest.java (97%) diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java similarity index 97% rename from plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java rename to plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java index 2ca586feef18..cc20bb3cc8fb 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.naming.com.siyeh.ig.naming; +package com.siyeh.ig.naming; import com.intellij.codeInspection.InspectionProfileEntry; import com.siyeh.ig.LightInspectionTestCase; From c1bae4745fcf575f0869e7ce9a4e89d069a01487 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 28 Aug 2014 10:58:59 +0200 Subject: [PATCH 8/9] let "Old style JUnit test method in JUnit 4 class" inspection warn in more cases and test --- ...tyleTestMethodInJUnit4ClassInspection.java | 56 ++++++------------ .../BeforeAnnotationUsed.java | 9 +++ .../JUnit3StyleTestMethodInJUnit4Class.java | 10 ++++ .../com/siyeh/ig/LightInspectionTestCase.java | 9 ++- ...TestMethodInJUnit4ClassInspectionTest.java | 57 +++++++++++++++++++ 5 files changed, 99 insertions(+), 42 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java index 8a6ebeff68ce..c39865049e95 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.siyeh.ig.DelegatingFix; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.TestUtils; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -71,70 +72,45 @@ public class JUnit3StyleTestMethodInJUnit4ClassInspection extends BaseInspection if (!name.startsWith("test")) { return; } - if (method.hasModifierProperty(PsiModifier.ABSTRACT) || !method.hasModifierProperty(PsiModifier.PUBLIC)) { + if (!TestUtils.isRunnable(method)) { return; } if (TestUtils.isJUnit4TestMethod(method)) { return; } - final PsiType returnType = method.getReturnType(); - if (returnType == null || !returnType.equals(PsiType.VOID)) { - return; - } - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.getParametersCount() != 0) { - return; - } final PsiClass containingClass = method.getContainingClass(); if (TestUtils.isJUnitTestClass(containingClass)) { return; } - if (!containsReferenceToClass(containingClass, "org.junit.Test")) { + if (!containsJUnit4Annotation(containingClass)) { return; } registerMethodError(method); } } - public static boolean containsReferenceToClass(PsiElement element, String fullyQualifiedName) { - final ClassReferenceVisitor visitor = new ClassReferenceVisitor(fullyQualifiedName); + public static boolean containsJUnit4Annotation(PsiElement element) { + final JUnit4AnnotationVisitor visitor = new JUnit4AnnotationVisitor(); element.accept(visitor); - return visitor.isReferenceFound(); + return visitor.isJUnit4AnnotationFound(); } - private static class ClassReferenceVisitor extends JavaRecursiveElementVisitor { + private static class JUnit4AnnotationVisitor extends JavaRecursiveElementWalkingVisitor { - private final String fullyQualifiedName; - private boolean referenceFound = false; - - private ClassReferenceVisitor(String fullyQualifiedName) { - this.fullyQualifiedName = fullyQualifiedName; - } + private boolean myJUnit4AnnotationFound = false; @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - super.visitReferenceElement(reference); - if (referenceFound) { + public void visitAnnotation(PsiAnnotation annotation) { + super.visitAnnotation(annotation); + @NonNls final String qualifiedName = annotation.getQualifiedName(); + if (qualifiedName == null || !qualifiedName.startsWith("org.junit.")) { return; } - if (!(reference.getParent() instanceof PsiAnnotation)) { - // optimization - return; - } - final PsiElement element = reference.resolve(); - if (!(element instanceof PsiClass) || element instanceof PsiTypeParameter) { - return; - } - final PsiClass aClass = (PsiClass)element; - final String classQualifiedName = aClass.getQualifiedName(); - if (classQualifiedName == null || !classQualifiedName.equals(fullyQualifiedName)) { - return; - } - referenceFound = true; + myJUnit4AnnotationFound = true; } - public boolean isReferenceFound() { - return referenceFound; + public boolean isJUnit4AnnotationFound() { + return myJUnit4AnnotationFound; } } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java new file mode 100644 index 000000000000..6ef566f99035 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java @@ -0,0 +1,9 @@ +import org.junit.Before; + +public class BeforeAnnotationUsed { + + @Before + public void before() {} + + public void testOldStyle() {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java new file mode 100644 index 000000000000..e5df9e6d40ba --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java @@ -0,0 +1,10 @@ +import org.junit.Test; + +public class JUnit3StyleTestMethodInJUnit4Class { + + @Test + public void junit4Test() { + } + + public void testJUnit3() {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java index d262e31333ba..951d14ad9f8b 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java @@ -109,15 +109,20 @@ public abstract class LightInspectionTestCase extends LightCodeInsightFixtureTes lastWord = lastWord.substring(0, lastWord.length() - 10); } final int length = lastWord.length(); + boolean upperCase = false; for (int i = 0; i < length; i++) { final char ch = lastWord.charAt(i); if (Character.isUpperCase(ch)) { - if (i != 0) { - basePath.append('_'); + if (!upperCase) { + upperCase = true; + if (i != 0) { + basePath.append('_'); + } } basePath.append(Character.toLowerCase(ch)); } else { + upperCase = false; basePath.append(ch); } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java new file mode 100644 index 000000000000..eb7e979f81e1 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class JUnit3StyleTestMethodInJUnit4ClassInspectionTest extends LightInspectionTestCase { + + public void testJUnit3StyleTestMethodInJUnit4Class() { doTest(); } + public void testBeforeAnnotationUsed() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new JUnit3StyleTestMethodInJUnit4ClassInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package org.junit;" + + "import java.lang.annotation.ElementType;" + + "import java.lang.annotation.Retention;" + + "import java.lang.annotation.RetentionPolicy;" + + "import java.lang.annotation.Target;" + + "@Retention(RetentionPolicy.RUNTIME)" + + "@Target({ElementType.METHOD})" + + "public @interface Before {}", + "package org.junit;" + + "import java.lang.annotation.ElementType;" + + "import java.lang.annotation.Retention;" + + "import java.lang.annotation.RetentionPolicy;" + + "import java.lang.annotation.Target;" + + "@Retention(RetentionPolicy.RUNTIME)" + + "@Target({ElementType.METHOD})" + + "public @interface Test {}" + }; + } +} From 495e455dedf127389504d0f608f1aeb26b12f3cb Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 28 Aug 2014 14:27:58 +0400 Subject: [PATCH 9/9] new inference: infinite types --- .../graphInference/InferenceSession.java | 96 ++++++++++++++----- .../CyclicParamsDependency.java | 11 ++- .../SOEDuringInferenceFromParamBounds.java | 2 +- .../GraphInferenceHighlightingTest.java | 1 - 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 06e941e2a9f7..d423cbbe83af 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -15,10 +15,12 @@ */ package com.intellij.psi.impl.source.resolve.graphInference; +import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.resolve.graphInference.constraints.*; @@ -42,6 +44,12 @@ public class InferenceSession { public static final Key LOWER_BOUND = Key.create("LowBound"); private static final Key ERASED = Key.create("UNCHECKED_CONVERSION"); + private static final Function, PsiType> UPPER_BOUND_FUNCTION = new Function, PsiType>() { + @Override + public PsiType fun(Pair pair) { + return GenericsUtil.getGreatestLowerBound(pair.first, pair.second); + } + }; private final Set myInferenceVariables = new LinkedHashSet(); private final List myConstraints = new ArrayList(); @@ -359,9 +367,7 @@ public class InferenceSession { final PsiClassType[] extendsListTypes = parameter.getExtendsListTypes(); for (PsiType classType : extendsListTypes) { classType = substituteWithInferenceVariables(mySiteSubstitutor.substitute(classType)); - HashSet dependencies = new HashSet(); - collectDependencies(classType, dependencies);//todo isProperType - if (dependencies.isEmpty() || dependencies.size() == 1 && dependencies.contains(variable)) { + if (isProperType(classType)) { added = true; } variable.addBound(classType, InferenceBound.UPPER); @@ -681,7 +687,13 @@ public class InferenceSession { while (!allVars.isEmpty()) { final List vars = InferenceVariablesOrder.resolveOrder(allVars, this); if (!myIncorporationPhase.hasCaptureConstraints(vars)) { - final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor); + PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor); + if (firstSubstitutor != null) { + final Set parameters = firstSubstitutor.getSubstitutionMap().keySet(); + if (GenericsUtil.findTypeParameterWithBoundError(parameters.toArray(new PsiTypeParameter[parameters.size()]), firstSubstitutor, myContext, true) != null) { + firstSubstitutor = null; + } + } if (firstSubstitutor != null) { substitutor = firstSubstitutor; allVars.removeAll(vars); @@ -690,19 +702,20 @@ public class InferenceSession { } final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); - for (InferenceVariable var : vars) { - final PsiTypeParameter parameter = var.getParameter(); - final PsiTypeParameter copy = elementFactory.createTypeParameterFromText("z" + parameter.getName(), null); - final PsiType lub = getLowerBound(var, substitutor); - final PsiType glb = getUpperBound(var, substitutor); - //todo add upper bound to the fresh type variable + final PsiTypeParameter[] freshParameters = createFreshVariables(vars); + for (int i = 0; i < freshParameters.length; i++) { + PsiTypeParameter parameter = freshParameters[i]; + final InferenceVariable var = vars.get(i); + final PsiType lub = getLowerBound(var, PsiSubstitutor.EMPTY); if (lub != PsiType.NULL) { - if (!TypeConversionUtil.isAssignable(glb, lub)) { - return null; + for (PsiClassType upperBoundType : parameter.getExtendsListTypes()) { + if (!TypeConversionUtil.isAssignable(upperBoundType, lub)) { + return null; + } } - copy.putUserData(LOWER_BOUND, lub); + parameter.putUserData(LOWER_BOUND, lub); } - var.addBound(elementFactory.createType(copy), InferenceBound.EQ); + var.addBound(elementFactory.createType(parameter), InferenceBound.EQ); } myIncorporationPhase.forgetCaptures(vars); if (!repeatInferencePhases(true)) { @@ -712,13 +725,38 @@ public class InferenceSession { return substitutor; } - private PsiType getLowerBound(InferenceVariable var, PsiSubstitutor substitutor) { - return composeBound(var, InferenceBound.LOWER, new Function, PsiType>() { + private PsiTypeParameter[] createFreshVariables(final List vars) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); + + PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; + final PsiTypeParameter[] yVars = new PsiTypeParameter[vars.size()]; + for (int i = 0; i < vars.size(); i++) { + InferenceVariable var = vars.get(i); + final PsiTypeParameter parameter = var.getParameter(); + yVars[i] = elementFactory.createTypeParameterFromText(getFreshVariableName(var), parameter); + substitutor = substitutor.put(var, elementFactory.createType(yVars[i])); + } + + + final PsiSubstitutor ySubstitutor = substitutor; + final String classText = "class I<" + StringUtil.join(vars, new Function() { @Override - public PsiType fun(Pair pair) { - return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager); + public String fun(InferenceVariable variable) { + final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor, true); + return getFreshVariableName(variable) + " extends " + glb.getInternalCanonicalText(); } - }, substitutor); + }, ", ") + ">{}"; + + final PsiFile file = + PsiFileFactory.getInstance(getManager().getProject()).createFileFromText("inference_dummy.java", JavaFileType.INSTANCE, classText); + LOG.assertTrue(file instanceof PsiJavaFile, classText); + final PsiClass[] classes = ((PsiJavaFile)file).getClasses(); + LOG.assertTrue(classes.length == 1, classText); + return classes[0].getTypeParameters(); + } + + private static String getFreshVariableName(InferenceVariable var) { + return var.getName(); } private PsiSubstitutor resolveSubset(Collection vars, PsiSubstitutor substitutor) { @@ -747,15 +785,19 @@ public class InferenceSession { return substitutor; } - private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) { - return composeBound(var, InferenceBound.UPPER, new Function, PsiType>() { + private PsiType getLowerBound(InferenceVariable var, PsiSubstitutor substitutor) { + return composeBound(var, InferenceBound.LOWER, new Function, PsiType>() { @Override public PsiType fun(Pair pair) { - return GenericsUtil.getGreatestLowerBound(pair.first, pair.second); + return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager); } }, substitutor); } + private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) { + return composeBound(var, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, substitutor); + } + public PsiType getEqualsBound(InferenceVariable var, PsiSubstitutor substitutor) { return composeBound(var, InferenceBound.EQ, new Function, PsiType>() { @Override @@ -769,11 +811,19 @@ public class InferenceSession { InferenceBound boundType, Function, PsiType> fun, PsiSubstitutor substitutor) { + return composeBound(variable, boundType, fun, substitutor, false); + } + + private PsiType composeBound(InferenceVariable variable, + InferenceBound boundType, + Function, PsiType> fun, + PsiSubstitutor substitutor, + boolean includeNonProperBounds) { final List lowerBounds = variable.getBounds(boundType); PsiType lub = PsiType.NULL; for (PsiType lowerBound : lowerBounds) { lowerBound = substituteNonProperBound(lowerBound, substitutor); - if (isProperType(lowerBound)) { + if (includeNonProperBounds || isProperType(lowerBound)) { if (lub == PsiType.NULL) { lub = lowerBound; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/CyclicParamsDependency.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/CyclicParamsDependency.java index 6363d95079bb..927165e23e9c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/CyclicParamsDependency.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/CyclicParamsDependency.java @@ -1,7 +1,16 @@ import java.util.List; class Sample { - , K extends List> void foo(){} + , K extends List> T foo(){ + T t = foo().get(0); + K k = foo().get(0); + + T t1 = foo().get(0).get(0); + + String s = foo(); + String s1 = foo().get(0); + return null; + } { foo(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SOEDuringInferenceFromParamBounds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SOEDuringInferenceFromParamBounds.java index 3f26bbc1ef56..90e8efb23b5d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SOEDuringInferenceFromParamBounds.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/SOEDuringInferenceFromParamBounds.java @@ -3,5 +3,5 @@ import java.util.Map; public class SOE { public static > M foo() {return null;} - public static > Map foo1() {return foo();} + public static > Map foo1() {return foo();} } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 1102f26b596e..700d5b85d097 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -57,7 +57,6 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } - @Bombed(day = 30, month = Calendar.AUGUST) public void testCyclicParamsDependency() throws Exception { doTest(); }