Change properties to methods in light class hierarchy

There's a Kotlin-Java-Kotlin hierarchy with an abstract property in a
superclass and its implementation (as a get-method) in the Java subclass, which
caused problems because Kotlin subclass can't have both (different symbols,
same JVM signatures)
This commit is contained in:
Alexander Udalov
2015-02-04 12:03:30 +03:00
parent cafc1ea24d
commit 1c87464695
15 changed files with 35 additions and 24 deletions
@@ -21,5 +21,5 @@ import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.psi.JetClassOrObject
public trait KotlinLightClass : PsiClass, KotlinLightElement<JetClassOrObject, PsiClass> { public trait KotlinLightClass : PsiClass, KotlinLightElement<JetClassOrObject, PsiClass> {
val fqName: FqName public fun getFqName(): FqName
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.psi.JetDeclaration
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
public trait KotlinLightElement<T : JetDeclaration, D : PsiElement> { public trait KotlinLightElement<T : JetDeclaration, D : PsiElement> {
public val origin: T? public fun getOrigin(): T?
public val delegate: D
public fun getDelegate(): D
} }
@@ -34,8 +34,8 @@ import com.intellij.psi.util.MethodSignatureBackedByPsiMethod
open public class KotlinLightMethodForDeclaration( open public class KotlinLightMethodForDeclaration(
manager: PsiManager, manager: PsiManager,
override val delegate: PsiMethod, private val delegate: PsiMethod,
override val origin: JetDeclaration, private val origin: JetDeclaration,
containingClass: PsiClass containingClass: PsiClass
): LightMethod(manager, delegate, containingClass), KotlinLightMethod { ): LightMethod(manager, delegate, containingClass), KotlinLightMethod {
@@ -65,8 +65,12 @@ open public class KotlinLightMethodForDeclaration(
}, false) }, false)
} }
override fun getNavigationElement() : PsiElement = origin override fun getNavigationElement(): PsiElement = origin
override fun getOriginalElement() : PsiElement = origin override fun getOriginalElement(): PsiElement = origin
override fun getDelegate(): PsiMethod = delegate
override fun getOrigin(): JetDeclaration = origin
override fun getParent(): PsiElement? = getContainingClass() override fun getParent(): PsiElement? = getContainingClass()
@@ -82,7 +86,7 @@ open public class KotlinLightMethodForDeclaration(
} }
override fun isEquivalentTo(another: PsiElement?): Boolean { override fun isEquivalentTo(another: PsiElement?): Boolean {
if (another is KotlinLightMethod && origin == another.origin) { if (another is KotlinLightMethod && origin == another.getOrigin()) {
return true return true
} }
@@ -24,11 +24,15 @@ import com.intellij.psi.PsiElement
public class KotlinLightMethodForTraitFakeOverride( public class KotlinLightMethodForTraitFakeOverride(
manager: PsiManager, manager: PsiManager,
override val delegate: PsiMethod, private val delegate: PsiMethod,
override val origin: JetDeclaration, private val origin: JetDeclaration,
containingClass: PsiClass containingClass: PsiClass
) : KotlinLightMethodForDeclaration(manager, delegate, origin, containingClass) { ) : KotlinLightMethodForDeclaration(manager, delegate, origin, containingClass) {
override fun getDelegate(): PsiMethod = delegate
override fun getOrigin(): JetDeclaration = origin
override fun copy(): PsiElement { override fun copy(): PsiElement {
return KotlinLightMethodForTraitFakeOverride(getManager()!!, delegate, origin.copy() as JetDeclaration, getContainingClass()!!) return KotlinLightMethodForTraitFakeOverride(getManager(), delegate, origin.copy() as JetDeclaration, getContainingClass())
} }
} }
@@ -97,7 +97,7 @@ public fun JetTypeParameter.toPsiTypeParameters(): List<PsiTypeParameter> {
// Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise // Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise
public val PsiElement.unwrapped: PsiElement? public val PsiElement.unwrapped: PsiElement?
get() = if (this is KotlinLightElement<*, *>) origin else this get() = if (this is KotlinLightElement<*, *>) getOrigin() else this
public val PsiElement.namedUnwrappedElement: PsiNamedElement? public val PsiElement.namedUnwrappedElement: PsiNamedElement?
get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>() get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>()
@@ -48,7 +48,7 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDes
} }
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor { fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
if (this is KotlinLightMethod) throw AssertionError("Light methods are not allowed here: ${origin?.getText()}") if (this is KotlinLightMethod) throw AssertionError("Light methods are not allowed here: ${getOrigin()?.getText()}")
val resolver = JavaResolveExtension.getResolver(getProject(), this) val resolver = JavaResolveExtension.getResolver(getProject(), this)
val methodDescriptor = when { val methodDescriptor = when {
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.name.FqName
class KotlinLightClassForDecompiledDeclaration( class KotlinLightClassForDecompiledDeclaration(
private val clsClass: ClsClassImpl, private val clsClass: ClsClassImpl,
override val origin: JetClassOrObject? private val origin: JetClassOrObject?
) : KotlinWrappingLightClass(clsClass.getManager()) { ) : KotlinWrappingLightClass(clsClass.getManager()) {
override fun copy() = this override fun copy() = this
@@ -38,5 +38,7 @@ class KotlinLightClassForDecompiledDeclaration(
override fun getDelegate() = clsClass override fun getDelegate() = clsClass
override val fqName: FqName = origin?.getFqName() ?: FqName(clsClass.getQualifiedName()) override fun getOrigin() = origin
override fun getFqName() = origin?.getFqName() ?: FqName(clsClass.getQualifiedName())
} }
@@ -111,7 +111,7 @@ private fun KotlinLightElement<*, *>.getModuleInfoForLightElement(): IdeaModuleI
if (this is KotlinLightClassForDecompiledDeclaration) { if (this is KotlinLightClassForDecompiledDeclaration) {
return getModuleInfoByVirtualFile(getProject(), getContainingFile().getVirtualFile(), false) return getModuleInfoByVirtualFile(getProject(), getContainingFile().getVirtualFile(), false)
} }
val element = origin ?: when (this) { val element = getOrigin() ?: when (this) {
is FakeLightClassForFileOfPackage -> this.getContainingFile()!! is FakeLightClassForFileOfPackage -> this.getContainingFile()!!
is KotlinLightClassForPackage -> this.getFiles().first() is KotlinLightClassForPackage -> this.getFiles().first()
else -> throw IllegalStateException("Unknown light class without origin is referenced by IDE lazy resolve: $javaClass") else -> throw IllegalStateException("Unknown light class without origin is referenced by IDE lazy resolve: $javaClass")
@@ -140,7 +140,7 @@ fun PsiReference.isPropertyReadOnlyUsage(): Boolean {
val refTarget = resolve() val refTarget = resolve()
if (refTarget is KotlinLightMethod) { if (refTarget is KotlinLightMethod) {
val origin = refTarget.origin val origin = refTarget.getOrigin()
val declaration: JetNamedDeclaration? = when (origin) { val declaration: JetNamedDeclaration? = when (origin) {
is JetPropertyAccessor -> origin.getNonStrictParentOfType<JetProperty>() is JetPropertyAccessor -> origin.getNonStrictParentOfType<JetProperty>()
is JetProperty, is JetParameter -> origin as JetNamedDeclaration is JetProperty, is JetParameter -> origin as JetNamedDeclaration
@@ -286,7 +286,7 @@ class TypeInstantiationItems(
val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter) val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter)
for (inheritor in ClassInheritorsSearch.search(parameters)) { for (inheritor in ClassInheritorsSearch.search(parameters)) {
val descriptor = if (inheritor is KotlinLightClass && inheritor !is KotlinLightClassForDecompiledDeclaration) { val descriptor = if (inheritor is KotlinLightClass && inheritor !is KotlinLightClassForDecompiledDeclaration) {
val origin = inheritor.origin ?: continue val origin = inheritor.getOrigin() ?: continue
val declaration = toFromOriginalFileMapper.toSyntheticFile(origin) ?: continue val declaration = toFromOriginalFileMapper.toSyntheticFile(origin) ?: continue
resolutionFacade.resolveToDescriptor(declaration) resolutionFacade.resolveToDescriptor(declaration)
} }
@@ -105,7 +105,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
} }
if (elementAt is KotlinLightClass) { if (elementAt is KotlinLightClass) {
return getContextElement(elementAt.origin) return getContextElement(elementAt.getOrigin())
} }
val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false) val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false)
@@ -78,7 +78,7 @@ public class JetChangeSignatureData(
val overrides = lightMethod?.let { OverridingMethodsSearch.search(it).findAll() } ?: Collections.emptyList() val overrides = lightMethod?.let { OverridingMethodsSearch.search(it).findAll() } ?: Collections.emptyList()
overrides.map { method -> overrides.map { method ->
if (method is KotlinLightMethod) { if (method is KotlinLightMethod) {
val overridingDeclaration = method.origin val overridingDeclaration = method.getOrigin()
val overridingDescriptor = overridingDeclaration?.resolveToDescriptor() as FunctionDescriptor val overridingDescriptor = overridingDeclaration?.resolveToDescriptor() as FunctionDescriptor
JetFunctionDefinitionUsage<PsiElement>(overridingDeclaration, overridingDescriptor, primaryFunction, null) JetFunctionDefinitionUsage<PsiElement>(overridingDeclaration, overridingDescriptor, primaryFunction, null)
} }
@@ -36,7 +36,7 @@ public class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
} }
override fun canProcessElement(element: PsiElement): Boolean { override fun canProcessElement(element: PsiElement): Boolean {
return element is JetNamedFunction || (element is KotlinLightMethod && element.origin is JetNamedFunction) return element is JetNamedFunction || (element is KotlinLightMethod && element.getOrigin() is JetNamedFunction)
} }
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? { override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
@@ -50,7 +50,7 @@ public class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
val substitutedJavaElement = javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor) val substitutedJavaElement = javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor)
return when (substitutedJavaElement) { return when (substitutedJavaElement) {
is KotlinLightMethod -> substitutedJavaElement.origin as? JetNamedFunction is KotlinLightMethod -> substitutedJavaElement.getOrigin() as? JetNamedFunction
else -> substitutedJavaElement else -> substitutedJavaElement
} }
} }
@@ -210,7 +210,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val typeArguments = convertTypeArguments(expression) val typeArguments = convertTypeArguments(expression)
if (target is KotlinLightMethod) { if (target is KotlinLightMethod) {
val origin = target.origin val origin = target.getOrigin()
val isTopLevel = origin?.getStrictParentOfType<JetClassOrObject>() == null val isTopLevel = origin?.getStrictParentOfType<JetClassOrObject>() == null
if (origin is JetProperty || origin is JetPropertyAccessor || origin is JetParameter) { if (origin is JetProperty || origin is JetPropertyAccessor || origin is JetParameter) {
val property = if (origin is JetPropertyAccessor) val property = if (origin is JetPropertyAccessor)
@@ -369,7 +369,7 @@ class TypeConverter(val converter: Converter) {
override fun fromAnnotations(owner: PsiModifierListOwner): Mutability { override fun fromAnnotations(owner: PsiModifierListOwner): Mutability {
if (owner is KotlinLightElement<*, *>) { if (owner is KotlinLightElement<*, *>) {
val jetDeclaration = owner.origin as? JetCallableDeclaration ?: return Mutability.Default val jetDeclaration = owner.getOrigin() as? JetCallableDeclaration ?: return Mutability.Default
val descriptor = converter.resolverForConverter.resolveToDescriptor(jetDeclaration) as? CallableDescriptor ?: return Mutability.Default val descriptor = converter.resolverForConverter.resolveToDescriptor(jetDeclaration) as? CallableDescriptor ?: return Mutability.Default
val type = descriptor.getReturnType() ?: return Mutability.Default val type = descriptor.getReturnType() ?: return Mutability.Default
val classDescriptor = TypeUtils.getClassDescriptor(type) ?: return Mutability.Default val classDescriptor = TypeUtils.getClassDescriptor(type) ?: return Mutability.Default