diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java index 50907cf63dd5..aa41a87a7b78 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java @@ -18,27 +18,30 @@ package com.intellij.psi.impl.source.resolve.reference.impl; import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.codeInsight.completion.JavaLookupElementBuilder; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiTypesUtil; -import com.intellij.psi.util.PsiUtilCore; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.siyeh.ig.psiutils.ParenthesesUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * @author Konstantin Bulenkov */ public class JavaLangClassMemberReference extends PsiReferenceBase implements InsertHandler { + private static final RecursionGuard ourGuard = RecursionManager.createGuard("JavaLangClassMemberReference"); private final PsiExpression myContext; public JavaLangClassMemberReference(PsiLiteralExpression literal, PsiExpression context) { @@ -76,42 +79,115 @@ public class JavaLangClassMemberReference extends PsiReferenceBase getPsiClass(initializer)); + } + } + } return null; } - private static boolean isClass(PsiClass aClass) { + private static PsiExpression getInitializer(@NotNull PsiVariable variable, @NotNull PsiExpression usage) { + PsiExpression initializer = variable.getInitializer(); + if (initializer != null) { + if (variable.hasModifierProperty(PsiModifier.FINAL)) { + return initializer; + } + if (variable instanceof PsiLocalVariable) { + PsiDeclarationStatement declarationStatement = ObjectUtils.tryCast(variable.getParent(), PsiDeclarationStatement.class); + if (declarationStatement != null) { + PsiStatement usageStatement = PsiTreeUtil.getParentOfType(usage, PsiStatement.class); + if (PsiTreeUtil.getNextSiblingOfType(declarationStatement, PsiStatement.class) == usageStatement) { + return initializer; + } + PsiElement scope = PsiUtil.getVariableCodeBlock(variable, usage); + if (scope != null && HighlightControlFlowUtil.isEffectivelyFinal(variable, scope, null)) { + return initializer; + } + } + } + } + PsiStatement usageStatement = PsiTreeUtil.getParentOfType(usage, PsiStatement.class); + if (usageStatement != null) { + return getAssignedVisibleInUsage(variable, usageStatement); + } + // TODO: handle other initializations and assignments where the class can be resolved unambiguously + return null; + } + + @Nullable + private static PsiExpression getAssignedVisibleInUsage(@NotNull PsiVariable variable, PsiStatement usageStatement) { + PsiStatement previousStatement = PsiTreeUtil.getPrevSiblingOfType(usageStatement, PsiStatement.class); + if (previousStatement instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement)previousStatement).getExpression(); + if (expression instanceof PsiAssignmentExpression && + JavaTokenType.EQ.equals(((PsiAssignmentExpression)expression).getOperationTokenType())) { + PsiExpression lExpression = ((PsiAssignmentExpression)expression).getLExpression(); + lExpression = ParenthesesUtils.stripParentheses(lExpression); + if (lExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)lExpression).resolve() == variable) { + return ((PsiAssignmentExpression)expression).getRExpression(); + } + } + } + return null; + } + + private static boolean isJavaLangClass(PsiClass aClass) { return aClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(aClass.getQualifiedName()); } + private static boolean isJavaLangObject(PsiClass aClass) { + return aClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName()); + } + @Nullable private Type getType() { - boolean selfFound = false; - for (PsiElement child : myContext.getParent().getChildren()) { - if (!selfFound) { - if (child == myContext) { - selfFound = true; - } - continue; - } - - if (child instanceof PsiIdentifier) { - return Type.fromString(child.getText()); - } + PsiMethodCallExpression methodCall = PsiTreeUtil.getParentOfType(myElement, PsiMethodCallExpression.class); + if (methodCall != null) { + String name = methodCall.getMethodExpression().getReferenceName(); + return Type.fromString(name); } return null; } @@ -120,31 +196,39 @@ public class JavaLangClassMemberReference extends PsiReferenceBase fields = new ArrayList<>(); - for (PsiField field : psiClass.getFields()) { - if (isPublic(field)) { - fields.add(field); - } + if (type != null) { + final PsiClass psiClass = getPsiClass(); + if (psiClass != null) { + switch (type) { + + case DECLARED_FIELD: + return psiClass.getFields(); + + case FIELD: + return ContainerUtil.filter(psiClass.getAllFields(), JavaLangClassMemberReference::isPublic).toArray(); + + case DECLARED_METHOD: + return Arrays.stream(psiClass.getMethods()) + .filter(method -> !method.isConstructor()) + .map(this::lookupMethod) + .toArray(); + + case METHOD: + return Arrays.stream(psiClass.getAllMethods()) + .filter(method -> isPublic(method) && !method.isConstructor() && !isJavaLangObject(method.getContainingClass())) + .map(this::lookupMethod) + .toArray(); } - return fields.toArray(); - } else if (type == Type.DECLARED_METHOD || type == Type.METHOD) { - final List elements = new ArrayList<>(); - for (PsiMethod method : psiClass.getMethods()) { - if (type == Type.DECLARED_METHOD || isPublic(method)) { - elements.add(JavaLookupElementBuilder.forMethod(method, PsiSubstitutor.EMPTY).withInsertHandler(this)); - } - } - return elements.toArray(); } } return EMPTY_ARRAY; } + @NotNull + private LookupElementBuilder lookupMethod(PsiMethod method) { + return JavaLookupElementBuilder.forMethod(method, PsiSubstitutor.EMPTY).withInsertHandler(this); + } + @Override public void handleInsert(InsertionContext context, LookupElement item) { final Object object = item.getObject(); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceProvider.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceProvider.java index 3a871db45f61..7fc87f6862b2 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceProvider.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceProvider.java @@ -16,10 +16,8 @@ package com.intellij.psi.impl.source.resolve.reference.impl; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author Konstantin Bulenkov @@ -29,28 +27,23 @@ public class JavaReflectionReferenceProvider extends PsiReferenceProvider { @Override public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { if (element instanceof PsiLiteralExpression) { - String value = getValue(((PsiLiteralExpression)element)); - final PsiElement expressionList; - if (value != null && (expressionList = element.getParent()) instanceof PsiExpressionList) { - final PsiElement methodCall = expressionList.getParent(); - final PsiExpression classAccess; - if (methodCall != null && (classAccess = getContext(methodCall)) != null) { - return new PsiReference[]{new JavaLangClassMemberReference((PsiLiteralExpression)element, classAccess)}; + PsiLiteralExpression literal = (PsiLiteralExpression)element; + if (literal.getValue() instanceof String) { + PsiElement parent = element.getParent(); + if (parent instanceof PsiExpressionList) { + PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiMethodCallExpression) { + PsiReferenceExpression methodReference = ((PsiMethodCallExpression)grandParent).getMethodExpression(); + PsiExpression qualifier = methodReference.getQualifierExpression(); + if (qualifier instanceof PsiClassObjectAccessExpression || + qualifier instanceof PsiMethodCallExpression || + qualifier instanceof PsiReferenceExpression) { + return new PsiReference[]{new JavaLangClassMemberReference(literal, qualifier)}; + } + } } } } return PsiReference.EMPTY_ARRAY; } - - @Nullable - private static PsiExpression getContext(PsiElement methodCall) { - final PsiClassObjectAccessExpression expression = PsiTreeUtil.findChildOfType(methodCall, PsiClassObjectAccessExpression.class); - return expression == null ? PsiTreeUtil.findChildOfType(methodCall, PsiMethodCallExpression.class) : expression; - } - - @Nullable - private static String getValue(PsiLiteralExpression element) { - final Object value = element.getValue(); - return value instanceof String ? (String)value : null; - } } diff --git a/java/java-tests/testData/codeInsight/completion/reflection/AssignChain.java b/java/java-tests/testData/codeInsight/completion/reflection/AssignChain.java new file mode 100644 index 000000000000..a2fa1d8883ec --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/AssignChain.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Class a,b,c,d; + a = Class.forName("Test"); + b = a; + c = b; + d = c; + d.getField(""); + } +} + +class Test { + public int num; + public int num2; +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/AssignChain_after.java b/java/java-tests/testData/codeInsight/completion/reflection/AssignChain_after.java new file mode 100644 index 000000000000..6db7e6db6c75 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/AssignChain_after.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Class a,b,c,d; + a = Class.forName("Test"); + b = a; + c = b; + d = c; + d.getField("num2"); + } +} + +class Test { + public int num; + public int num2; +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/AssignCycle.java b/java/java-tests/testData/codeInsight/completion/reflection/AssignCycle.java new file mode 100644 index 000000000000..2df004860285 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/AssignCycle.java @@ -0,0 +1,16 @@ +class Main { + void foo() { + Class a,b,c,d; + d = Class.forName("Test"); + a = d; + b = a; + c = b; + d = c; + d.getField(""); + } +} + +class Test { + public int num; + public int num2; +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/AssignCycle_after.java b/java/java-tests/testData/codeInsight/completion/reflection/AssignCycle_after.java new file mode 100644 index 000000000000..2df004860285 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/AssignCycle_after.java @@ -0,0 +1,16 @@ +class Main { + void foo() { + Class a,b,c,d; + d = Class.forName("Test"); + a = d; + b = a; + c = b; + d = c; + d.getField(""); + } +} + +class Test { + public int num; + public int num2; +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/CallChain.java b/java/java-tests/testData/codeInsight/completion/reflection/CallChain.java new file mode 100644 index 000000000000..43e0ea3d2d95 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/CallChain.java @@ -0,0 +1,12 @@ +class Main { + void foo() throws ReflectiveOperationException { + bar().getField(""); + } + + Class bar() throws ClassNotFoundException { return (Class) Class.forName("Test"); } +} + +class Test { + public int num; + public void method(){} +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/CallChain_after.java b/java/java-tests/testData/codeInsight/completion/reflection/CallChain_after.java new file mode 100644 index 000000000000..eec06b89a894 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/CallChain_after.java @@ -0,0 +1,12 @@ +class Main { + void foo() throws ReflectiveOperationException { + bar().getField("num"); + } + + Class bar() throws ClassNotFoundException { return (Class) Class.forName("Test"); } +} + +class Test { + public int num; + public void method(){} +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredField.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredField.java new file mode 100644 index 000000000000..e99b844f5e18 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredField.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getDeclaredField(""); + } +} + +class Test extends Parent { + public int num; + int num3; +} + +class Parent { + public int num2; + int num4; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredField_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredField_after.java new file mode 100644 index 000000000000..a77aa80c0baf --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredField_after.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getDeclaredField("num3"); + } +} + +class Test extends Parent { + public int num; + int num3; +} + +class Parent { + public int num2; + int num4; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredMethod.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredMethod.java new file mode 100644 index 000000000000..91c0ce6ad438 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredMethod.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getDeclaredMethod(""); + } +} + +class Test extends Parent { + public void method(){} + void method3(){} +} + +class Parent { + public void method2(){} + void method4(){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredMethod_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredMethod_after.java new file mode 100644 index 000000000000..b12e584f3a42 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedDeclaredMethod_after.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getDeclaredMethod("method3"); + } +} + +class Test extends Parent { + public void method(){} + void method3(){} +} + +class Parent { + public void method2(){} + void method4(){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedField.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedField.java new file mode 100644 index 000000000000..756d8dc0c645 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedField.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getField(""); + } +} + +class Test extends Parent { + public int num; + void int num3; +} + +class Parent { + public int num2; + int num4; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedField_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedField_after.java new file mode 100644 index 000000000000..204ceb814951 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedField_after.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getField("num2"); + } +} + +class Test extends Parent { + public int num; + void int num3; +} + +class Parent { + public int num2; + int num4; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedMethod.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedMethod.java new file mode 100644 index 000000000000..26aed417ce7c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedMethod.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getMethod(""); + } +} + +class Test extends Parent { + public void method(){} + void method3(){} +} + +class Parent { + public void method2(){} + void method4(){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InheritedMethod_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InheritedMethod_after.java new file mode 100644 index 000000000000..8de56b7bd562 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InheritedMethod_after.java @@ -0,0 +1,15 @@ +class Main { + void foo() { + Test.class.getMethod("method2"); + } +} + +class Test extends Parent { + public void method(){} + void method3(){} +} + +class Parent { + public void method2(){} + void method4(){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InitChain.java b/java/java-tests/testData/codeInsight/completion/reflection/InitChain.java new file mode 100644 index 000000000000..9274f88a4620 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InitChain.java @@ -0,0 +1,21 @@ +class Main { + void foo() { + Class a = Class.forName("Test"); + Class b = a; + Class c = b; + Class d = c; + Class e = d; + Class f = e; + Class g = f; + Class h = g; + Class i = h; + Class j = i; + Class k = j; + k.getField(""); + } +} + +class Test { + public int num; + public int num2; +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InitChain_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InitChain_after.java new file mode 100644 index 000000000000..b8876d0da642 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InitChain_after.java @@ -0,0 +1,21 @@ +class Main { + void foo() { + Class a = Class.forName("Test"); + Class b = a; + Class c = b; + Class d = c; + Class e = d; + Class f = e; + Class g = f; + Class h = g; + Class i = h; + Class j = i; + Class k = j; + k.getField("num2"); + } +} + +class Test { + public int num; + public int num2; +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InitRaw.java b/java/java-tests/testData/codeInsight/completion/reflection/InitRaw.java new file mode 100644 index 000000000000..3e3faf29f113 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InitRaw.java @@ -0,0 +1,11 @@ +class Main { + void foo() { + Class c = Test.class; + c.getMethod(""); + } +} + +class Test { + public void method(){} + public void method2(int n){} +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InitRaw_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InitRaw_after.java new file mode 100644 index 000000000000..81f99e55dfe0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InitRaw_after.java @@ -0,0 +1,11 @@ +class Main { + void foo() { + Class c = Test.class; + c.getMethod("method2", int.class); + } +} + +class Test { + public void method(){} + public void method2(int n){} +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InitWithType.java b/java/java-tests/testData/codeInsight/completion/reflection/InitWithType.java new file mode 100644 index 000000000000..efa4d883739e --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InitWithType.java @@ -0,0 +1,13 @@ +class Main { + void foo() { + Class c = bar(); + c.getMethod(""); + } + + Class bar() { return Test.class; } +} + +class Test { + public void method(){} + public void method2(int n){} +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/InitWithType_after.java b/java/java-tests/testData/codeInsight/completion/reflection/InitWithType_after.java new file mode 100644 index 000000000000..b3580f4e06ec --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/InitWithType_after.java @@ -0,0 +1,13 @@ +class Main { + void foo() { + Class c = bar(); + c.getMethod("method2", int.class); + } + + Class bar() { return Test.class; } +} + +class Test { + public void method(){} + public void method2(int n){} +} diff --git a/java/java-tests/testData/codeInsight/completion/reflection/Jdk14.java b/java/java-tests/testData/codeInsight/completion/reflection/Jdk14.java new file mode 100644 index 000000000000..4c73e541bb03 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/Jdk14.java @@ -0,0 +1,9 @@ +class Main { + void foo() { + Test.class.getMethod(""); + } +} + +class Test { + public void method(){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/Jdk14_after.java b/java/java-tests/testData/codeInsight/completion/reflection/Jdk14_after.java new file mode 100644 index 000000000000..1d0e6611c913 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/Jdk14_after.java @@ -0,0 +1,9 @@ +class Main { + void foo() { + Test.class.getMethod("method"); + } +} + +class Test { + public void method(){} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaReflectionCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaReflectionCompletionTest.java index 6183e27db4a5..3c7de208da2a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaReflectionCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaReflectionCompletionTest.java @@ -16,6 +16,8 @@ package com.intellij.codeInsight.completion; import com.intellij.JavaTestUtil; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.testFramework.IdeaTestUtil; /** * @author Konstantin Bulenkov @@ -72,10 +74,54 @@ public class JavaReflectionCompletionTest extends LightFixtureCompletionTestCase doTest(0, "foo"); } + public void testInheritedMethod() throws Exception { + doTest(1, "method", "method2"); + } + + public void testInheritedDeclaredMethod() throws Exception { + doTest(1, "method", "method3"); + } + + public void testInheritedField() throws Exception { + doTest(1, "num", "num2"); + } + + public void testInheritedDeclaredField() throws Exception { + doTest(1, "num", "num3"); + } + + public void testInitRaw() throws Exception { + doTest(1, "method", "method2"); + } + + public void testInitWithType() throws Exception { + doTest(1, "method", "method2"); + } + + public void testInitChain() throws Exception { + doTest(1, "num", "num2"); + } + + public void testAssignChain() throws Exception { + doTest(1, "num", "num2"); + } + + public void testAssignCycle() throws Exception { + doTest(-1); // check that the recursion guard breaks the cycle + } + + public void testCallChain() throws Exception { + doTest(0, "num"); + } + + public void testJdk14() throws Exception { + IdeaTestUtil.withLevel(myFixture.getModule(), LanguageLevel.JDK_1_4, () -> doTest(0, "method")); + } + private void doTest(int index, String... expected) { configureByFile(getTestName(false) + ".java"); assertStringItems(expected); - selectItem(getLookup().getItems().get(index)); + if (index >= 0) selectItem(getLookup().getItems().get(index)); myFixture.checkResultByFile(getTestName(false) + "_after.java"); } }