don't perform full resolve and stub building for isInheritor() checks
#KT-8656 Fixed
This commit is contained in:
+6
@@ -204,6 +204,12 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return UtilsPackage.<PsiClass>emptyOrSingletonList(KotlinLightClassForPackage.Factory.create(psiManager, packageFqName, scope, filesWithCallables));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject) {
|
||||
return bindingContext.get(BindingContext.CLASS, classOrObject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public BindingTraceContext createTrace() {
|
||||
|
||||
+34
-23
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.JetLanguage
|
||||
import org.jetbrains.kotlin.lexer.JetTokens.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -150,8 +151,12 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
private fun getJavaFileStub(): PsiJavaFileStub = getLightClassData().javaFileStub
|
||||
|
||||
protected fun getDescriptor(): ClassDescriptor? {
|
||||
val data = getLightClassDataExactly(classOrObject)
|
||||
return data?.descriptor
|
||||
val cachedValue = getLightClassCachedValue(classOrObject)
|
||||
if (cachedValue.hasUpToDateValue()) {
|
||||
return cachedValue.value.dataForClass(classOrObject)?.descriptor
|
||||
}
|
||||
|
||||
return LightClassGenerationSupport.getInstance(project).resolveClassToDescriptor(classOrObject)
|
||||
}
|
||||
|
||||
private fun getLightClassData(): OutermostKotlinClassLightClassData {
|
||||
@@ -321,22 +326,17 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
override fun isValid(): Boolean = classOrObject.isValid
|
||||
|
||||
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
|
||||
// Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes
|
||||
if (baseClass is KotlinLightClassForExplicitDeclaration || (isInterface && !baseClass.isInterface)) {
|
||||
val qualifiedName: String?
|
||||
if (baseClass is KotlinLightClassForExplicitDeclaration) {
|
||||
val baseDescriptor = baseClass.getDescriptor()
|
||||
qualifiedName = if (baseDescriptor != null) DescriptorUtils.getFqName(baseDescriptor).asString() else null
|
||||
}
|
||||
else {
|
||||
qualifiedName = baseClass.qualifiedName
|
||||
}
|
||||
|
||||
val thisDescriptor = getDescriptor()
|
||||
return qualifiedName != null && thisDescriptor != null && checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep)
|
||||
val qualifiedName: String?
|
||||
if (baseClass is KotlinLightClassForExplicitDeclaration) {
|
||||
val baseDescriptor = baseClass.getDescriptor()
|
||||
qualifiedName = if (baseDescriptor != null) DescriptorUtils.getFqName(baseDescriptor).asString() else null
|
||||
}
|
||||
else {
|
||||
qualifiedName = baseClass.qualifiedName
|
||||
}
|
||||
|
||||
return super.isInheritor(baseClass, checkDeep)
|
||||
val thisDescriptor = getDescriptor()
|
||||
return qualifiedName != null && thisDescriptor != null && checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep)
|
||||
}
|
||||
|
||||
throws(IncorrectOperationException::class)
|
||||
@@ -399,17 +399,23 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
}
|
||||
|
||||
public fun getLightClassData(classOrObject: JetClassOrObject): OutermostKotlinClassLightClassData {
|
||||
return getLightClassCachedValue(classOrObject).value
|
||||
}
|
||||
|
||||
public fun getLightClassCachedValue(classOrObject: JetClassOrObject): CachedValue<OutermostKotlinClassLightClassData> {
|
||||
val outermostClassOrObject = getOutermostClassOrObject(classOrObject)
|
||||
return CachedValuesManager.getManager(classOrObject.project).getCachedValue(
|
||||
outermostClassOrObject,
|
||||
JAVA_API_STUB,
|
||||
KotlinJavaFileStubProvider.createForDeclaredClass(outermostClassOrObject),
|
||||
/*trackValue = */false)
|
||||
var value = outermostClassOrObject.getUserData(JAVA_API_STUB)
|
||||
if (value == null) {
|
||||
value = CachedValuesManager.getManager(classOrObject.project).createCachedValue(
|
||||
KotlinJavaFileStubProvider.createForDeclaredClass(outermostClassOrObject), false)
|
||||
value = outermostClassOrObject.putUserDataIfAbsent(JAVA_API_STUB, value)!!
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private fun getLightClassDataExactly(classOrObject: JetClassOrObject): LightClassDataForKotlinClass? {
|
||||
val data = getLightClassData(classOrObject)
|
||||
return if (data.classOrObject == classOrObject) data else data.allInnerClasses.get(classOrObject)
|
||||
return data.dataForClass(classOrObject)
|
||||
}
|
||||
|
||||
private fun getOutermostClassOrObject(classOrObject: JetClassOrObject): JetClassOrObject {
|
||||
@@ -424,11 +430,16 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
|
||||
if (qualifiedName == DescriptorUtils.getFqName(classDescriptor).asString()) return true
|
||||
|
||||
val mappedDescriptor = JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(FqName(qualifiedName))
|
||||
val mappedQName = if (mappedDescriptor == null) null else DescriptorUtils.getFqName(mappedDescriptor).asString()
|
||||
if (qualifiedName == mappedQName) return true
|
||||
|
||||
for (superType in classDescriptor.typeConstructor.supertypes) {
|
||||
val superDescriptor = superType.constructor.declarationDescriptor
|
||||
|
||||
if (superDescriptor is ClassDescriptor) {
|
||||
if (qualifiedName == DescriptorUtils.getFqName(superDescriptor).asString()) return true
|
||||
val superQName = DescriptorUtils.getFqName(superDescriptor).asString()
|
||||
if (superQName == qualifiedName || superQName == mappedQName) return true
|
||||
|
||||
if (deep) {
|
||||
if (checkSuperTypeByFQName(superDescriptor, qualifiedName, true)) {
|
||||
|
||||
+4
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
@@ -71,4 +72,7 @@ public abstract class LightClassGenerationSupport {
|
||||
|
||||
@NotNull
|
||||
public abstract Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope);
|
||||
|
||||
@Nullable
|
||||
public abstract ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ package org.jetbrains.kotlin.asJava
|
||||
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface LightClassData
|
||||
|
||||
@@ -53,4 +53,9 @@ data class OutermostKotlinClassLightClassData(
|
||||
override val classOrObject: JetClassOrObject,
|
||||
override val descriptor: ClassDescriptor?,
|
||||
val allInnerClasses: Map<JetClassOrObject, InnerKotlinClassLightClassData>
|
||||
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics
|
||||
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics {
|
||||
|
||||
fun dataForClass(cls: JetClassOrObject): LightClassDataForKotlinClass? =
|
||||
if (cls == classOrObject) this else allInnerClasses[cls]
|
||||
|
||||
}
|
||||
|
||||
+11
@@ -304,6 +304,17 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject) {
|
||||
try {
|
||||
return (ClassDescriptor) ResolvePackage.resolveToDescriptor(classOrObject);
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass getLightClassForDecompiledPackage(@NotNull FqName packageFqName, @NotNull List<JetFile> filesWithCallables) {
|
||||
JetFile firstFile = filesWithCallables.iterator().next();
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.junit.Assert
|
||||
|
||||
public class KotlinLightClassInheritorTest : JetLightCodeInsightFixtureTestCase() {
|
||||
public fun testAnnotation() {
|
||||
doTestInheritorByText("annotation class A", "java.lang.annotation.Annotation", false)
|
||||
}
|
||||
|
||||
public fun testEnum() {
|
||||
doTestInheritorByText("enum class A", "java.lang.Enum", false)
|
||||
}
|
||||
|
||||
public fun testIterable() {
|
||||
doTestInheritorByText("abstract class A<T> : Iterable<T>", "java.lang.Iterable", false)
|
||||
}
|
||||
|
||||
public fun testIterableDeep() {
|
||||
doTestInheritorByText("abstract class A<T> : List<T>", "java.lang.Iterable", true)
|
||||
}
|
||||
|
||||
public fun testObjectDeep() {
|
||||
doTestInheritorByText("abstract class A<T> : List<T>", "java.lang.Object", true)
|
||||
}
|
||||
|
||||
private fun doTestInheritorByText(text: String, superQName: String, checkDeep: Boolean) {
|
||||
val file = myFixture.configureByText("A.kt", text) as JetFile
|
||||
val jetClass = file.declarations.filterIsInstance<JetClass>().single()
|
||||
val psiClass = LightClassGenerationSupport.getInstance(project).getPsiClass(jetClass)!!
|
||||
val baseClass = JavaPsiFacade.getInstance(project).findClass(superQName, GlobalSearchScope.allScope(project))!!
|
||||
Assert.assertTrue(psiClass.isInheritor(baseClass, checkDeep))
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = JetLightProjectDescriptor.INSTANCE
|
||||
}
|
||||
Reference in New Issue
Block a user