From a67d97bdf8a0c77b65a26e790cd86faab4fbee0b Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Wed, 12 Feb 2020 13:34:12 +0300 Subject: [PATCH] Remove redundant fake facade classes Fixed #KT-35122 #EA-218642 #EA-217640 --- .../jetbrains/kotlin/asJava/LightClassUtil.kt | 1 - .../FakeLightClassForFileOfPackage.java | 123 ------------------ .../kotlin/asJava/finder/JavaElementFinder.kt | 33 +++-- .../idea/caches/project/getModuleInfo.kt | 2 - .../caches/resolve/IDEKotlinAsJavaSupport.kt | 43 ++---- .../LightClassesClasspathSortingTest.kt | 1 - 6 files changed, 29 insertions(+), 174 deletions(-) delete mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt index ecbd8d3fecb..55d15904e5f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt @@ -173,7 +173,6 @@ object LightClassUtil { val classesWithMatchingFqName = JavaElementFinder.getInstance(project).findClasses(fqName.asString(), GlobalSearchScope.allScope(project)) return classesWithMatchingFqName.singleOrNull() ?: classesWithMatchingFqName.find { - // NOTE: for multipart facades this works via FakeLightClassForFileOfPackage it.containingFile?.virtualFile == ktFile.virtualFile } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java deleted file mode 100644 index 9bccca502fb..00000000000 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010-2016 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 org.jetbrains.kotlin.asJava.classes; - -import com.intellij.lang.Language; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.light.AbstractLightClass; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation; -import org.jetbrains.kotlin.asJava.finder.JavaElementFinder; -import org.jetbrains.kotlin.idea.KotlinLanguage; -import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind; -import org.jetbrains.kotlin.psi.KtClassOrObject; -import org.jetbrains.kotlin.psi.KtFile; - -import java.util.List; - -/** - * This class serves as a workaround for usages of {@link JavaElementFinder#findClasses} which eventually only need names of files - * containing the class. When queried for a package class (e.g. test/TestPackage), {@code findClasses} along with a - * {@link KtLightClassForFacade} would also return multiple instances of this class for each file present in the package. The client - * code can make use of every file in the package then, since {@code getContainingFile} of these instances will represent the whole package. - *

- * See {@link LineBreakpoint#findClassCandidatesInSourceContent} for the primary usage this was introduced - */ -public class FakeLightClassForFileOfPackage extends AbstractLightClass implements KtLightClass { - private final KtLightClassForFacade delegate; - private final KtFile file; - - public FakeLightClassForFileOfPackage(@NotNull KtLightClassForFacade delegate, @NotNull KtFile file) { - super(delegate.getManager()); - this.delegate = delegate; - this.file = file; - } - - @NotNull - @Override - public PsiClass getClsDelegate() { - return delegate; - } - - @Nullable - @Override - public KtClassOrObject getKotlinOrigin() { - return null; - } - - @Override - public PsiFile getContainingFile() { - return file; - } - - @Override - public boolean isValid() { - // This is intentionally false to prevent using this as a real class - return false; - } - - @NotNull - @Override - public PsiClass getDelegate() { - return delegate; - } - - @NotNull - @Override - public PsiElement copy() { - return new FakeLightClassForFileOfPackage(delegate, file); - } - - @Override - public String getText() { - return null; - } - - @NotNull - @Override - public Language getLanguage() { - return KotlinLanguage.INSTANCE; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof FakeLightClassForFileOfPackage)) return false; - - FakeLightClassForFileOfPackage other = (FakeLightClassForFileOfPackage) obj; - return file == other.file && delegate.equals(other.delegate); - } - - @Override - public int hashCode() { - return file.hashCode() * 31 + delegate.hashCode(); - } - - @NotNull - @Override - public LightClassOriginKind getOriginKind() { - return LightClassOriginKind.SOURCE; - } - - @Nullable - @Override - public List getGivenAnnotations() { - return null; - } -} diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt index 4c18266db20..d63783768df 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.kt @@ -21,12 +21,12 @@ import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.project.Project import com.intellij.openapi.util.Condition import com.intellij.psi.* +import com.intellij.psi.impl.compiled.ClsClassImpl import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.PsiUtilCore import com.intellij.util.SmartList import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport -import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.FqName @@ -58,7 +58,9 @@ class JavaElementFinder( answer.addAll(kotlinAsJavaSupport.getFacadeClasses(qualifiedName, scope)) answer.addAll(kotlinAsJavaSupport.getKotlinInternalClasses(qualifiedName, scope)) - return answer.sortByClasspathPreferringNonFakeFiles(scope).toTypedArray() + sortByPreferenceToSourceFile(answer, scope) + + return answer.toTypedArray() } // Finds explicitly declared classes and objects, not package classes @@ -141,15 +143,22 @@ class JavaElementFinder( answer.add(aClass) } - return answer.sortByClasspathPreferringNonFakeFiles(scope).toTypedArray() + sortByPreferenceToSourceFile(answer, scope) + + return answer.toTypedArray() } - override fun getPackageFiles(psiPackage: PsiPackage, scope: GlobalSearchScope): Array { - val packageFQN = FqName(psiPackage.qualifiedName) - // TODO: this does not take into account JvmPackageName annotation - return kotlinAsJavaSupport.findFilesForPackage(packageFQN, scope).toTypedArray() + private fun sortByPreferenceToSourceFile(list: SmartList, searchScope: GlobalSearchScope) { + if (list.size < 2) return + // NOTE: this comparator might violate the contract depending on the scope passed + ContainerUtil.quickSort(list, byClasspathComparator(searchScope)) + list.sortBy { it !is ClsClassImpl } } + // TODO: this does not take into account JvmPackageName annotation + override fun getPackageFiles(psiPackage: PsiPackage, scope: GlobalSearchScope): Array = + kotlinAsJavaSupport.findFilesForPackage(FqName(psiPackage.qualifiedName), scope).toTypedArray() + override fun getPackageFilesFilter(psiPackage: PsiPackage, scope: GlobalSearchScope): Condition? { return Condition { input -> if (input !is KtFile) { @@ -184,15 +193,5 @@ class JavaElementFinder( } } } - - private fun List.sortByClasspathPreferringNonFakeFiles(searchScope: GlobalSearchScope): List { - val result = this.toMutableList() - // NOTE: this comparator might violate the contract depending on the scope passed - ContainerUtil.quickSort(result, byClasspathComparator(searchScope)) - result.sortBy { - it is FakeLightClassForFileOfPackage - } - return result - } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt index 13dd9997cff..0f2e23b0e34 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt @@ -15,7 +15,6 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications @@ -214,7 +213,6 @@ private fun KtLightElement<*, *>.processLightElement(c: ModuleInfoCollector< } val element = kotlinOrigin ?: when (this) { - is FakeLightClassForFileOfPackage -> this.getContainingFile()!! is KtLightClassForFacade -> this.files.first() else -> return c.onFailure("Light element without origin is referenced by resolve:\n$this\n${this.clsDelegate.text}") } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt index f8910fd5cda..1e7894d6e80 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt @@ -12,6 +12,7 @@ import com.intellij.psi.impl.compiled.ClsClassImpl import com.intellij.psi.impl.compiled.ClsFileImpl import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.SmartList import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory import org.jetbrains.kotlin.asJava.classes.* @@ -34,7 +35,6 @@ import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.utils.sure -import java.util.* class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport() { private val psiManager: PsiManager = PsiManager.getInstance(project) @@ -151,19 +151,6 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport return KtLightClassForScript.create(script) } - private fun withFakeLightClasses( - lightClassForFacade: KtLightClassForFacade - ): List { - val lightClasses = ArrayList() - lightClasses.add(lightClassForFacade) - if (lightClassForFacade.files.size > 1) { - lightClasses.addAll(lightClassForFacade.files.map { - FakeLightClassForFileOfPackage(lightClassForFacade, it) - }) - } - return lightClasses - } - override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection { val filesByModule = findFilesForFacade(facadeFqName, scope).groupBy(PsiElement::getModuleInfoPreferringJvmPlatform) @@ -215,24 +202,20 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport facadeFqName: FqName, facadeFiles: List, moduleInfo: IdeaModuleInfo - ): List { - val (clsFiles, _) = facadeFiles.partition { it is KtClsFile } - val facadesFromCls = clsFiles.mapNotNull { createLightClassForDecompiledKotlinFile(it as KtClsFile) } - val facadesFromSources = createFacadesForSourceFiles(moduleInfo, facadeFqName) - return facadesFromSources + facadesFromCls + ): List = SmartList().apply { + + tryCreateFacadesForSourceFiles(moduleInfo, facadeFqName)?.let { sourcesFacade -> + add(sourcesFacade) + } + + facadeFiles.filterIsInstance().mapNotNullTo(this) { + createLightClassForDecompiledKotlinFile(it) + } } - private fun createFacadesForSourceFiles( - moduleInfo: IdeaModuleInfo, - facadeFqName: FqName - ): List { - if (moduleInfo !is ModuleSourceInfo && moduleInfo !is PlatformModuleInfo) return listOf() - - val lightClassForFacade = KtLightClassForFacade.createForFacade( - psiManager, facadeFqName, moduleInfo.contentScope() - ) - - return if (lightClassForFacade !== null) withFakeLightClasses(lightClassForFacade) else emptyList() + private fun tryCreateFacadesForSourceFiles(moduleInfo: IdeaModuleInfo, facadeFqName: FqName): PsiClass? { + if (moduleInfo !is ModuleSourceInfo && moduleInfo !is PlatformModuleInfo) return null + return KtLightClassForFacade.createForFacade(psiManager, facadeFqName, moduleInfo.contentScope()) } override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection { diff --git a/idea/tests/org/jetbrains/kotlin/asJava/LightClassesClasspathSortingTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/LightClassesClasspathSortingTest.kt index c2c3fc6d606..8441be022bc 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/LightClassesClasspathSortingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/asJava/LightClassesClasspathSortingTest.kt @@ -46,7 +46,6 @@ class LightClassesClasspathSortingTest : KotlinLightCodeInsightFixtureTestCase() val psiClass = JavaPsiFacade.getInstance(project).findClass(fqName, ResolveScopeManager.getElementResolveScope(file)) assertNotNull(psiClass, "Can't find class for $fqName") - psiClass!! assert(psiClass is KtLightClassForSourceDeclaration || psiClass is KtLightClassForFacade) { "Should be an explicit light class, but was $fqName ${psiClass::class.java}" } assert(psiClass !is KtLightClassForDecompiledDeclaration) { "Should not be decompiled light class: $fqName ${psiClass::class.java}" } }