From 36e1149e518012181d31cdb427057b5e583d32f3 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Wed, 3 Jul 2019 18:03:42 +0900 Subject: [PATCH] Light classes: Fix getTextOffset() and getTextRange() for property accessors Before this commit, getTextOffset() and getTextRange() coming from the super class, returned numbers for the property, not for its accessor. This commit fixes the inconsistency. --- .../asJava/builder/LightElementOrigin.kt | 4 ++- .../classes/ultraLightMembersCreator.kt | 28 +++++++++++++---- .../asJava/classes/ultraLightMethods.kt | 22 ++++++++----- .../kotlin/asJava/classes/ultraLightUtils.kt | 5 ++- .../asJava/elements/KtLightMethodImpl.kt | 25 ++++++++++++++- .../lightClasses/LightClassBehaviorTest.kt | 31 +++++++++++++++++++ 6 files changed, 98 insertions(+), 17 deletions(-) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightElementOrigin.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightElementOrigin.kt index e30bdf732a4..156bd910352 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightElementOrigin.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightElementOrigin.kt @@ -51,6 +51,7 @@ interface LightMemberOrigin : LightElementOrigin { override val originalElement: KtDeclaration? override val originKind: JvmDeclarationOriginKind val parametersForJvmOverloads: List? get() = null + val auxiliaryOriginalElement: KtDeclaration? get() = null fun isEquivalentTo(other: LightMemberOrigin?): Boolean fun copy(): LightMemberOrigin @@ -59,7 +60,8 @@ interface LightMemberOrigin : LightElementOrigin { data class LightMemberOriginForDeclaration( override val originalElement: KtDeclaration, override val originKind: JvmDeclarationOriginKind, - override val parametersForJvmOverloads: List? = null + override val parametersForJvmOverloads: List? = null, + override val auxiliaryOriginalElement: KtDeclaration? = null ) : LightMemberOrigin { override fun isEquivalentTo(other: LightMemberOrigin?): Boolean { if (other !is LightMemberOriginForDeclaration) return false diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt index db9535afaf7..dcfb4e825c4 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt @@ -11,6 +11,7 @@ import com.intellij.psi.impl.light.LightMethodBuilder import com.intellij.psi.impl.light.LightModifierList import com.intellij.psi.impl.light.LightParameterListBuilder import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_OVERLOADS_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind internal class UltraLightMembersCreator( private val containingClass: KtLightClass, @@ -364,9 +366,16 @@ internal class UltraLightMembersCreator( val result = arrayListOf() if (needsAccessor(ktGetter)) { - val getterName = computeMethodName(ktGetter ?: declaration, JvmAbi.getterName(propertyName), MethodType.GETTER) - val getterPrototype = lightMethod(getterName, ktGetter ?: declaration, onlyJvmStatic || forceStatic) - val getterWrapper = KtUltraLightMethodForSourceDeclaration(getterPrototype, declaration, support, containingClass) + val auxiliaryOrigin = ktGetter ?: declaration + val lightMemberOrigin = LightMemberOriginForDeclaration( + originalElement = declaration, + originKind = JvmDeclarationOriginKind.OTHER, + auxiliaryOriginalElement = auxiliaryOrigin + ) + + val getterName = computeMethodName(auxiliaryOrigin, JvmAbi.getterName(propertyName), MethodType.GETTER) + val getterPrototype = lightMethod(getterName, auxiliaryOrigin, onlyJvmStatic || forceStatic) + val getterWrapper = KtUltraLightMethodForSourceDeclaration(getterPrototype, lightMemberOrigin, support, containingClass) val getterType: PsiType by lazyPub { methodReturnType(declaration, getterWrapper, isSuspendFunction = false) } getterPrototype.setMethodReturnType { getterType } addReceiverParameter(declaration, getterWrapper) @@ -374,10 +383,17 @@ internal class UltraLightMembersCreator( } if (mutable && needsAccessor(ktSetter)) { - val setterName = computeMethodName(ktSetter ?: declaration, JvmAbi.setterName(propertyName), MethodType.SETTER) - val setterPrototype = lightMethod(setterName, ktSetter ?: declaration, onlyJvmStatic || forceStatic) + val auxiliaryOrigin = ktSetter ?: declaration + val lightMemberOrigin = LightMemberOriginForDeclaration( + originalElement = declaration, + originKind = JvmDeclarationOriginKind.OTHER, + auxiliaryOriginalElement = auxiliaryOrigin + ) + + val setterName = computeMethodName(auxiliaryOrigin, JvmAbi.setterName(propertyName), MethodType.SETTER) + val setterPrototype = lightMethod(setterName, auxiliaryOrigin, onlyJvmStatic || forceStatic) .setMethodReturnType(PsiType.VOID) - val setterWrapper = KtUltraLightMethodForSourceDeclaration(setterPrototype, declaration, support, containingClass) + val setterWrapper = KtUltraLightMethodForSourceDeclaration(setterPrototype, lightMemberOrigin, support, containingClass) addReceiverParameter(declaration, setterWrapper) val setterParameter = ktSetter?.parameter setterPrototype.addParameter( diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt index f8a040ba0c1..c93480750d1 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt @@ -11,6 +11,7 @@ import com.intellij.psi.impl.PsiSuperMethodImplUtil import com.intellij.psi.impl.light.LightMethodBuilder import com.intellij.psi.impl.light.LightTypeParameterListBuilder import com.intellij.psi.util.MethodSignatureBackedByPsiMethod +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.builder.MemberIndex import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation @@ -27,14 +28,12 @@ import org.jetbrains.kotlin.types.KotlinType internal abstract class KtUltraLightMethod( internal val delegate: LightMethodBuilder, - closestDeclarationForOrigin: KtDeclaration?, + lightMemberOrigin: LightMemberOrigin?, protected val support: KtUltraLightSupport, containingClass: KtLightClass ) : KtLightMethodImpl( { delegate }, - closestDeclarationForOrigin?.let { - LightMemberOriginForDeclaration(it, JvmDeclarationOriginKind.OTHER) - }, + lightMemberOrigin, containingClass ), KtUltraLightElementWithNullabilityAnnotation { @@ -103,15 +102,22 @@ internal abstract class KtUltraLightMethod( internal class KtUltraLightMethodForSourceDeclaration( delegate: LightMethodBuilder, - declaration: KtDeclaration, + lightMemberOrigin: LightMemberOrigin?, support: KtUltraLightSupport, containingClass: KtLightClass ) : KtUltraLightMethod( delegate, - declaration, + lightMemberOrigin, support, containingClass ) { + constructor( + delegate: LightMethodBuilder, + declaration: KtDeclaration, + support: KtUltraLightSupport, + containingClass: KtLightClass + ) : this(delegate, LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER), support, containingClass) + override val kotlinTypeForNullabilityAnnotation: KotlinType? get() = kotlinOrigin?.getKotlinType() @@ -128,12 +134,12 @@ internal class KtUltraLightMethodForSourceDeclaration( internal class KtUltraLightMethodForDescriptor( private val descriptor: FunctionDescriptor, delegate: LightMethodBuilder, - closestDeclarationForOrigin: KtDeclaration?, + lightMemberOrigin: LightMemberOrigin?, support: KtUltraLightSupport, containingClass: KtUltraLightClass ) : KtUltraLightMethod( delegate, - closestDeclarationForOrigin, + lightMemberOrigin, support, containingClass ) { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index 375fc9a501d..9c4a1432543 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -18,6 +18,7 @@ import com.intellij.psi.impl.light.LightParameterListBuilder import com.intellij.util.BitUtil.isSet import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.builtins.KotlinBuiltIns @@ -38,6 +39,7 @@ import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.replace @@ -217,7 +219,8 @@ fun KtUltraLightClass.createGeneratedMethodFromDescriptor( ?: DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtDeclaration ?: kotlinOrigin - val wrapper = KtUltraLightMethodForDescriptor(descriptor, lightMethod, kotlinOrigin, support, this) + val lightMemberOrigin = LightMemberOriginForDeclaration(kotlinOrigin, JvmDeclarationOriginKind.OTHER) + val wrapper = KtUltraLightMethodForDescriptor(descriptor, lightMethod, lightMemberOrigin, support, this) descriptor.extensionReceiverParameter?.let { receiver -> lightMethod.addParameter(KtUltraLightParameterForDescriptor(receiver, kotlinOrigin, support, wrapper)) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt index 936b825a4ed..6feaf2ce096 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.asJava.elements +import com.intellij.openapi.util.TextRange import com.intellij.psi.* import com.intellij.psi.impl.compiled.ClsTypeElementImpl import com.intellij.psi.scope.PsiScopeProcessor @@ -187,11 +188,33 @@ open class KtLightMethodImpl protected constructor( } } + override fun getTextOffset(): Int { + val auxiliaryOrigin = lightMemberOrigin?.auxiliaryOriginalElement + if (auxiliaryOrigin is KtPropertyAccessor) { + return auxiliaryOrigin.textOffset + } + + return super.getTextOffset() + } + + override fun getTextRange(): TextRange { + val auxiliaryOrigin = lightMemberOrigin?.auxiliaryOriginalElement + if (auxiliaryOrigin is KtPropertyAccessor) { + return auxiliaryOrigin.textRange + } + + return super.getTextRange() + } + companion object Factory { private fun adjustMethodOrigin(origin: LightMemberOriginForDeclaration?): LightMemberOriginForDeclaration? { val originalElement = origin?.originalElement if (originalElement is KtPropertyAccessor) { - return origin.copy(originalElement.getStrictParentOfType()!!, origin.originKind) + return origin.copy( + originalElement = originalElement.getStrictParentOfType()!!, + originKind = origin.originKind, + auxiliaryOriginalElement = originalElement + ) } return origin } diff --git a/idea/tests/org/jetbrains/kotlin/idea/lightClasses/LightClassBehaviorTest.kt b/idea/tests/org/jetbrains/kotlin/idea/lightClasses/LightClassBehaviorTest.kt index ad63fce8e89..49e19e1c176 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/lightClasses/LightClassBehaviorTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/lightClasses/LightClassBehaviorTest.kt @@ -7,8 +7,10 @@ package org.jetbrains.kotlin.idea.lightClasses import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner import org.junit.runner.RunWith @@ -33,6 +35,35 @@ class LightClassBehaviorTest : KotlinLightCodeInsightFixtureTestCase() { assert(offset == range.startOffset) } + fun testPropertyAccessorOffsets() { + myFixture.configureByText( + "test.kt", """ + class A { + var a: Int + get() = 5 + set(v) {} + } + """.trimIndent() + ) + + val aClass = myFixture.javaFacade.findClass("A") as KtLightClass + val getAMethod = aClass.findMethodsByName("getA").single() as PsiMethod + val setAMethod = aClass.findMethodsByName("setA").single() as PsiMethod + + val ktClass = aClass.kotlinOrigin!! + val ktProperty = ktClass.declarations.filterIsInstance().single() + + assert(getAMethod.textOffset != setAMethod.textOffset) + + assert(getAMethod.textOffset > 0) + assert(getAMethod.textOffset != ktProperty.textOffset) + assert(getAMethod.textOffset == getAMethod.textRange.startOffset) + + assert(setAMethod.textOffset > 0) + assert(setAMethod.textOffset != ktProperty.textOffset) + assert(setAMethod.textOffset == setAMethod.textRange.startOffset) + } + override fun getProjectDescriptor(): LightProjectDescriptor { return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE }