diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceContributor.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceContributor.java index fad39cce1c91..ab2da9e706f5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceContributor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceContributor.java @@ -15,11 +15,13 @@ */ package com.intellij.psi.impl.source.resolve.reference.impl; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PsiJavaElementPattern; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceSet; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -73,15 +75,7 @@ public class JavaReflectionReferenceContributor extends PsiReferenceContributor } }); - registrar.registerReferenceProvider(CLASS_PATTERN, new JavaReflectionReferenceProvider() { - @Override - protected PsiReference[] getReferencesByMethod(@NotNull PsiLiteralExpression literalArgument, - @NotNull PsiReferenceExpression methodReference, - @NotNull ProcessingContext context) { - - return new JavaClassReferenceProvider().getReferencesByElement(literalArgument, context); - } - }); + registrar.registerReferenceProvider(CLASS_PATTERN, new ReflectionClassNameReferenceProvider()); registrar.registerReferenceProvider(METHOD_HANDLE_PATTERN, new JavaLangInvokeHandleReference.JavaLangInvokeHandleReferenceProvider()); @@ -101,4 +95,26 @@ public class JavaReflectionReferenceContributor extends PsiReferenceContributor registrar.registerReferenceProvider(ATOMIC_NUMERIC_PATTERN, atomicProvider); registrar.registerReferenceProvider(ATOMIC_REFERENCE_PATTERN, atomicProvider); } + + private static class ReflectionClassNameReferenceProvider extends JavaClassReferenceProvider { + + ReflectionClassNameReferenceProvider() { + setOption(JavaClassReferenceProvider.ALLOW_DOLLAR_NAMES, Boolean.TRUE); + setOption(JavaClassReferenceProvider.JVM_FORMAT, Boolean.TRUE); + } + + @NotNull + @Override + public PsiReference[] getReferencesByString(String str, @NotNull PsiElement position, int offsetInPosition) { + if (StringUtil.isEmpty(str)) { + return PsiReference.EMPTY_ARRAY; + } + return new JavaClassReferenceSet(str, position, offsetInPosition, true, this) { + @Override + public boolean isAllowDollarInNames() { + return true; + } + }.getAllReferences(); + } + } } diff --git a/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested.java b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested.java index ce74eb2de764..fa30d94ea2b2 100644 --- a/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested.java +++ b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested.java @@ -1,6 +1,6 @@ import foo.bar.*; class Main { void foo() throws ReflectiveOperationException { - Class.forName("foo.bar.PublicClass."); + Class.forName("foo.bar.PublicClass$"); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNestedAutocomplete.java b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNestedAutocomplete.java new file mode 100644 index 000000000000..760ca7e83a51 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNestedAutocomplete.java @@ -0,0 +1,6 @@ +import foo.bar.*; +class Main { + void foo() throws ReflectiveOperationException { + Class.forName("foo.bar.PublicClass$Nested"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNestedAutocomplete_after.java b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNestedAutocomplete_after.java new file mode 100644 index 000000000000..cbc06bb873f3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNestedAutocomplete_after.java @@ -0,0 +1,6 @@ +import foo.bar.*; +class Main { + void foo() throws ReflectiveOperationException { + Class.forName("foo.bar.PublicClass$NestedClass"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested_after.java b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested_after.java index faa113a76dca..cbc06bb873f3 100644 --- a/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested_after.java +++ b/java/java-tests/testData/codeInsight/completion/reflection/ClassForNameNested_after.java @@ -1,6 +1,6 @@ import foo.bar.*; class Main { void foo() throws ReflectiveOperationException { - Class.forName("foo.bar.PublicClass.NestedClass"); + Class.forName("foo.bar.PublicClass$NestedClass"); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaReflectionCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaReflectionCompletionTest.java index 2c836d187a81..aa1c87b8fdd6 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaReflectionCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/JavaReflectionCompletionTest.java @@ -165,9 +165,17 @@ public class JavaReflectionCompletionTest extends LightFixtureCompletionTestCase doTest(0, "one", "two"); } - public void testClassForNameNested() { + public void testClassForNameNestedAutocomplete() { myFixture.addClass("package foo.bar; public class PublicClass { public static class NestedClass {} }"); - doTest(0, "NestedClass"); + doTest(-1, () -> assertNull("Auto-completed", myFixture.getLookupElementStrings())); + } + + public void testClassForNameNested() { + myFixture.addClass("package foo.bar; public class PublicClass {" + + " public static class NestedClass {}" + + " public class InnerClass {}" + + "}"); + doTest(1, "InnerClass", "NestedClass"); } public void testWithClassLoader() { diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/JavaReflectionClassNavigationTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/JavaReflectionClassNavigationTest.kt index 2a607889f819..6c9a76621230 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/JavaReflectionClassNavigationTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/JavaReflectionClassNavigationTest.kt @@ -31,12 +31,12 @@ class JavaReflectionClassNavigationTest : JavaReflectionClassNavigationTestBase( fun testPublicInnerClass() { myFixture.addClass("package foo.bar; public class PublicClass { public class PublicInnerClass {} }") - doTest("foo.bar.PublicClass.PublicInnerClass") + doTest("foo.bar.PublicClass\$PublicInnerClass") } fun testPublicInnerClass2() { myFixture.addClass("package foo.bar; public class PublicClass { public class PublicInnerClass {} }") - doTest("foo.bar.PublicClass.PublicInnerClass") + doTest("foo.bar.PublicClass\$PublicInnerClass") } fun testPackageLocalClass() { @@ -46,17 +46,22 @@ class JavaReflectionClassNavigationTest : JavaReflectionClassNavigationTestBase( fun testPrivateInnerClass() { myFixture.addClass("package foo.bar; public class PublicClass { private class PrivateInnerClass {} }") - doTest("foo.bar.PublicClass.PrivateInnerClass") + doTest("foo.bar.PublicClass\$PrivateInnerClass") } fun testPrivateInnerClass2() { myFixture.addClass("package foo.bar; public class PublicClass { private class PrivateInnerClass {} }") - doTest("foo.bar.PublicClass.PrivateInnerClass") + doTest("foo.bar.PublicClass\$PrivateInnerClass") } fun testWithClassLoader() { myFixture.addClass("package foo.bar; public class PublicClass {}") - doTest("foo.bar.PublicClass.PrivateInnerClass", { "Thread.currentThread().getContextClassLoader().loadClass(\"$it\")" }) + doTest("foo.bar.PublicClass\$PrivateInnerClass", { "Thread.currentThread().getContextClassLoader().loadClass(\"$it\")" }) + } + + fun testNestedClassDefaultPackage() { + myFixture.addClass("public class Outer { public static class Inner {} }") + doTest("Outer\$Inner") } } @@ -73,11 +78,11 @@ abstract class JavaReflectionClassNavigationTestBase : LightCodeInsightFixtureTe protected fun doTest(className: String, usageFormatter: (String) -> String = { "Class.forName(\"$it\")" }) { val caretPos = className.indexOf("") val atCaret: String - var expectedName = className + var expectedName = className.replace('$', '.') if (caretPos >= 0) { atCaret = className - val dotPos = className.indexOf(".", caretPos + 1) - if (dotPos >= 0) expectedName = className.substring(0, dotPos).replace("", "") + val dotPos = expectedName.indexOf(".", caretPos + 1) + if (dotPos >= 0) expectedName = expectedName.substring(0, dotPos).replace("", "") } else { atCaret = className + ""