From 2c12d26d281f43a6eb0b67c7154c42bc7f0120e7 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Wed, 27 May 2020 14:16:18 +0300 Subject: [PATCH] KT-18538 Unwrap fake override in `ShortenReferences` - Fake override prevents reference shortener from shortening of static methods declared in the class bases when they are located not in direct parent of the class (for example, in grand- or grand-grand-parent) - The completion uses descriptor with unwrapped fake override when it performs the insertion. It leads to inserting the name of the base which actually contains the static method instead of the direct parent class. Now, when reference shortener compares unwrapped descriptors, this problem should be fixed during insertion handling --- .../idea/completion/BasicLookupElementFactory.kt | 6 ++---- .../multifile/StaticMethodFromGrandParent-1.java | 2 ++ .../multifile/StaticMethodFromGrandParent-1.kt | 5 +++++ .../multifile/StaticMethodFromGrandParent-2.java | 3 +++ .../multifile/StaticMethodFromGrandParent.kt.after | 5 +++++ .../test/handlers/CompletionMultifileHandlerTest.kt | 11 ++++++++++- .../jetbrains/kotlin/idea/core/ShortenReferences.kt | 5 ++++- .../org/jetbrains/kotlin/idea/core/descriptorUtils.kt | 4 ++++ .../replaceWith/ReplaceWithAnnotationAnalyzer.kt | 6 ++---- ...redundantGrandParentClassQualifier.dependency.java | 7 +++++++ .../java/redundantGrandParentClassQualifier.kt | 5 +++++ .../java/redundantGrandParentClassQualifier.kt.after | 5 +++++ ...GrandParentClassQualifierAmbiguous.dependency.java | 9 +++++++++ .../redundantGrandParentClassQualifierAmbiguous.kt | 5 +++++ ...dundantGrandParentClassQualifierAmbiguous.kt.after | 5 +++++ .../kotlin/shortenRefs/ShortenRefsTestGenerated.java | 10 ++++++++++ 16 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.java create mode 100644 idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.kt create mode 100644 idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-2.java create mode 100644 idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent.kt.after create mode 100644 idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.dependency.java create mode 100644 idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt create mode 100644 idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt.after create mode 100644 idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.dependency.java create mode 100644 idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt create mode 100644 idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt.after diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt index 5a1d7d67b0b..6d3159c08ca 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.idea.completion.handlers.KotlinClassifierInsertHandl import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject +import org.jetbrains.kotlin.idea.core.unwrapIfFakeOverride import org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor @@ -51,10 +52,7 @@ class BasicLookupElementFactory( includeClassTypeArguments: Boolean = true, parametersAndTypeGrayed: Boolean = false ): LookupElement { - val _descriptor = if (descriptor is CallableMemberDescriptor) - DescriptorUtils.unwrapFakeOverride(descriptor) - else - descriptor + val _descriptor = descriptor.unwrapIfFakeOverride() return createLookupElementUnwrappedDescriptor(_descriptor, qualifyNestedClasses, includeClassTypeArguments, parametersAndTypeGrayed) } diff --git a/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.java b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.java new file mode 100644 index 00000000000..5e99ae99df1 --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.java @@ -0,0 +1,2 @@ +public class Base extends GrandBase { +} \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.kt b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.kt new file mode 100644 index 00000000000..983f43016c5 --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-1.kt @@ -0,0 +1,5 @@ +class Inheritor : Base() { + init { + fooBa + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-2.java b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-2.java new file mode 100644 index 00000000000..6aaa195d98a --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent-2.java @@ -0,0 +1,3 @@ +public class GrandBase { + public static void fooBar() {} +} \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent.kt.after b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent.kt.after new file mode 100644 index 00000000000..5349a1ae558 --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/StaticMethodFromGrandParent.kt.after @@ -0,0 +1,5 @@ +class Inheritor : Base() { + init { + fooBar() + } +} \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt index db2d62d0ba0..4592e2898fd 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt @@ -30,6 +30,10 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() { doTest() } + fun testStaticMethodFromGrandParent() { + doTest('\n', "StaticMethodFromGrandParent-1.java", "StaticMethodFromGrandParent-2.java") + } + fun testTopLevelFunctionImport() { doTest() } @@ -113,8 +117,13 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() { fun doTest(completionChar: Char = '\n', vararg extraFileNames: String, tailText: String? = null) { val fileName = getTestName(false) + val defaultFiles = listOf("$fileName-1.kt", "$fileName-2.kt") + val filteredFiles = defaultFiles.filter { File(testDataPath, it).exists() } + + require(filteredFiles.isNotEmpty()) { "At least one of $defaultFiles should exist!" } + configureByFiles(null, *extraFileNames) - configureByFiles(null, "$fileName-1.kt", "$fileName-2.kt") + configureByFiles(null, *filteredFiles.toTypedArray()) complete(2) if (myItems != null) { val item = if (tailText == null) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt index 32879bff09d..b6a58aa7263 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt @@ -552,7 +552,10 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT // targetMatch == false, but shorten still can be preformed // TODO: Add possibility to check if descriptor from completion can't be resolved after shorten and not preform shorten than val resolvedCallsMatch = if (resolvedCall != null && resolvedCallWhenShort != null) { - resolvedCall.resultingDescriptor.original == resolvedCallWhenShort.resultingDescriptor.original + val originalCallDescriptor = resolvedCall.resultingDescriptor.original.unwrapIfFakeOverride() + val shortenedCallDescriptor = resolvedCallWhenShort.resultingDescriptor.original.unwrapIfFakeOverride() + + originalCallDescriptor == shortenedCallDescriptor } else { val resolvedCalls = selector.getCall(bindingContext)?.resolveCandidates(bindingContext, resolutionFacade) ?: emptyList() val callWhenShort = selectorAfterShortening.getCall(newContext) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt index 1d1019556b8..695deabe6a0 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt @@ -141,3 +141,7 @@ fun D.getDeepestSuperDeclarations(withThis: Boole return overriddenDeclarations.filterNot(DescriptorUtils::isOverride) } + +fun T.unwrapIfFakeOverride(): T { + return if (this is CallableMemberDescriptor) DescriptorUtils.unwrapFakeOverride(this) else this +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt index 9954dff28ff..68f8427ddf7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.codeInliner.CodeToInline import org.jetbrains.kotlin.idea.codeInliner.CodeToInlineBuilder +import org.jetbrains.kotlin.idea.core.unwrapIfFakeOverride import org.jetbrains.kotlin.idea.project.findAnalyzerServices import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.mainReference @@ -43,10 +44,7 @@ object ReplaceWithAnnotationAnalyzer { resolutionFacade: ResolutionFacade, reformat: Boolean ): CodeToInline? { - val originalDescriptor = when (symbolDescriptor) { - is CallableMemberDescriptor -> DescriptorUtils.unwrapFakeOverride(symbolDescriptor) - else -> symbolDescriptor - }.original + val originalDescriptor = symbolDescriptor.unwrapIfFakeOverride().original return analyzeOriginal(annotation, originalDescriptor, resolutionFacade, reformat) } diff --git a/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.dependency.java b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.dependency.java new file mode 100644 index 00000000000..d49437c8953 --- /dev/null +++ b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.dependency.java @@ -0,0 +1,7 @@ +public class Container { + public static class GrandBase { + public static void foo() {} + } + + public static class Base extends GrandBase {} +} \ No newline at end of file diff --git a/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt new file mode 100644 index 00000000000..371a9fa58e0 --- /dev/null +++ b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt @@ -0,0 +1,5 @@ +class C : Container.Base() { + init { + Container.GrandBase.foo() + } +} diff --git a/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt.after b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt.after new file mode 100644 index 00000000000..fc48439e4bc --- /dev/null +++ b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt.after @@ -0,0 +1,5 @@ +class C : Container.Base() { + init { + foo() + } +} diff --git a/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.dependency.java b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.dependency.java new file mode 100644 index 00000000000..c8f642a7db0 --- /dev/null +++ b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.dependency.java @@ -0,0 +1,9 @@ +public class Container { + public static class GrandBase { + public static void foo() {} + } + + public static class Base extends GrandBase { + public static void foo() {} + } +} \ No newline at end of file diff --git a/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt new file mode 100644 index 00000000000..371a9fa58e0 --- /dev/null +++ b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt @@ -0,0 +1,5 @@ +class C : Container.Base() { + init { + Container.GrandBase.foo() + } +} diff --git a/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt.after b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt.after new file mode 100644 index 00000000000..70fe2d4b77b --- /dev/null +++ b/idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt.after @@ -0,0 +1,5 @@ +class C : Container.Base() { + init { + Container.GrandBase.foo() + } +} diff --git a/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java index 7ce628bca25..d4d66526fab 100644 --- a/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java @@ -301,6 +301,16 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { runTest("idea/testData/shortenRefs/java/innerClassOnDemandImport.kt"); } + @TestMetadata("redundantGrandParentClassQualifier.kt") + public void testRedundantGrandParentClassQualifier() throws Exception { + runTest("idea/testData/shortenRefs/java/redundantGrandParentClassQualifier.kt"); + } + + @TestMetadata("redundantGrandParentClassQualifierAmbiguous.kt") + public void testRedundantGrandParentClassQualifierAmbiguous() throws Exception { + runTest("idea/testData/shortenRefs/java/redundantGrandParentClassQualifierAmbiguous.kt"); + } + @TestMetadata("staticClassNoImports.kt") public void testStaticClassNoImports() throws Exception { runTest("idea/testData/shortenRefs/java/staticClassNoImports.kt");