From ada71ce3cdd7a726a6d466d332650d5c4db03d1a Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 13 Nov 2018 16:09:45 +0900 Subject: [PATCH] Evaluate: Use '_field' syntax for field value evaluation (KT-14075) --- .../kotlin/codegen/ExpressionCodegen.java | 2 +- .../kotlin/synthetic/JavaSyntheticScopes.kt | 31 ++- .../descriptors/LazyJavaClassDescriptor.kt | 4 +- .../load/kotlin/methodSignatureMapping.kt | 2 +- ...uggerFieldCompletionInformationProvider.kt | 14 ++ ...DebuggerFieldExpressionCodegenExtension.kt | 51 +++++ .../DebuggerFieldSyntheticScopeProvider.kt | 193 ++++++++++++++++++ idea/resources/META-INF/extensions/ide.xml | 4 + .../META-INF/extensions/ide.xml.as33 | 4 + .../META-INF/extensions/ide.xml.as34 | 4 + idea/resources/META-INF/jvm.xml | 4 + idea/resources/META-INF/jvm.xml.181 | 4 + .../evaluate/singleBreakpoint/fieldGetters.kt | 105 ++++++++++ .../singleBreakpoint/fieldGetters.out | 29 +++ .../tinyApp/src/forTests/FieldsGetters.java | 76 +++++++ ...KotlinEvaluateExpressionTestGenerated.java | 5 + 16 files changed, 523 insertions(+), 9 deletions(-) create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldCompletionInformationProvider.kt create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldExpressionCodegenExtension.kt create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.out create mode 100644 idea/testData/debugger/tinyApp/src/forTests/FieldsGetters.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 6ae77d5df39..811160c7cd4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1881,7 +1881,7 @@ public class ExpressionCodegen extends KtVisitor impleme } @Nullable - private ClassDescriptor getSuperCallTarget(@NotNull Call call) { + public ClassDescriptor getSuperCallTarget(@NotNull Call call) { KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call); return superExpression == null ? null : getSuperCallLabelTarget(context, superExpression); } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt index e7ee26d1022..598e0edf969 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt @@ -16,25 +16,46 @@ package org.jetbrains.kotlin.synthetic +import com.intellij.openapi.project.Project import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.java.components.SamConversionResolver import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver +import org.jetbrains.kotlin.resolve.scopes.SyntheticScope import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes import org.jetbrains.kotlin.storage.StorageManager class JavaSyntheticScopes( + private val project: Project, + private val moduleDescriptor: ModuleDescriptor, storageManager: StorageManager, lookupTracker: LookupTracker, languageVersionSettings: LanguageVersionSettings, samConventionResolver: SamConversionResolver, deprecationResolver: DeprecationResolver ): SyntheticScopes { - override val scopes = listOf( - JavaSyntheticPropertiesScope(storageManager, lookupTracker), + override val scopes = run { + val javaSyntheticPropertiesScope = JavaSyntheticPropertiesScope(storageManager, lookupTracker) + + val scopesFromExtensions = SyntheticScopeProviderExtension + .getInstances(project) + .flatMap { it.getScopes(moduleDescriptor, javaSyntheticPropertiesScope) } + + listOf( + javaSyntheticPropertiesScope, SamAdapterFunctionsScope( - storageManager, languageVersionSettings, samConventionResolver, deprecationResolver, - lookupTracker + storageManager, languageVersionSettings, samConventionResolver, deprecationResolver, + lookupTracker ) - ) + ) + scopesFromExtensions + } } + +interface SyntheticScopeProviderExtension { + companion object : ProjectExtensionDescriptor( + "org.jetbrains.kotlin.syntheticScopeProviderExtension", SyntheticScopeProviderExtension::class.java) + + fun getScopes(moduleDescriptor: ModuleDescriptor, javaSyntheticPropertiesScope: JavaSyntheticPropertiesScope): List +} \ No newline at end of file diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt index e7bf1e89a8c..5089a11f1ab 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt @@ -39,9 +39,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.util.* class LazyJavaClassDescriptor( - outerContext: LazyJavaResolverContext, + val outerContext: LazyJavaResolverContext, containingDeclaration: DeclarationDescriptor, - private val jClass: JavaClass, + val jClass: JavaClass, private val additionalSupertypeClassDescriptor: ClassDescriptor? = null ) : ClassDescriptorBase(outerContext.storageManager, containingDeclaration, jClass.name, outerContext.components.sourceElementFactory.source(jClass), diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt index eada7b31d17..8c8af81c128 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt @@ -79,7 +79,7 @@ internal val ClassDescriptor.internalName: String return computeInternalName(this, isIrBackend = false) } -internal val ClassId.internalName: String +val ClassId.internalName: String get() { return JvmClassName.byClassId(JavaToKotlinClassMap.mapKotlinToJava(asSingleFqName().toUnsafe()) ?: this).internalName } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldCompletionInformationProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldCompletionInformationProvider.kt new file mode 100644 index 00000000000..940d8e7af7f --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldCompletionInformationProvider.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.debugger.evaluate + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.completion.CompletionInformationProvider + +class DebuggerFieldCompletionInformationProvider : CompletionInformationProvider { + override fun getContainerAndReceiverInformation(descriptor: DeclarationDescriptor) = + (descriptor as? DebuggerFieldPropertyDescriptor)?.description?.let { " $it" } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldExpressionCodegenExtension.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldExpressionCodegenExtension.kt new file mode 100644 index 00000000000..39c32bcfd0e --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldExpressionCodegenExtension.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.debugger.evaluate + +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.synthetic.JavaSyntheticPropertiesScope + +class DebuggerFieldExpressionCodegenExtension : ExpressionCodegenExtension { + override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? { + val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return null + + if (propertyDescriptor is DebuggerFieldPropertyDescriptor) { + return StackValue.StackValueWithSimpleReceiver.field( + c.typeMapper.mapType(propertyDescriptor.type), + propertyDescriptor.ownerType(c.codegen.state), + propertyDescriptor.fieldName, + false, + receiver + ) + } + + if (propertyDescriptor is JavaPropertyDescriptor) { + val containingClass = propertyDescriptor.containingDeclaration as? JavaClassDescriptor + if (containingClass != null) { + val correspondingGetter = JavaSyntheticPropertiesScope(LockBasedStorageManager.NO_LOCKS, LookupTracker.DO_NOTHING) + .getSyntheticExtensionProperties(listOf(containingClass.defaultType)) + .firstOrNull { it.name == propertyDescriptor.name } + + if (correspondingGetter != null) { + return c.codegen.intermediateValueForProperty( + correspondingGetter, false, false, + c.codegen.getSuperCallTarget(resolvedCall.call), + false, receiver, resolvedCall, false + ) + } + } + } + + return null + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt new file mode 100644 index 00000000000..9a1047c4d76 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt @@ -0,0 +1,193 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.debugger.evaluate + +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl +import org.jetbrains.kotlin.incremental.KotlinLookupLocation +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.load.java.components.JavaSourceElementFactoryImpl +import org.jetbrains.kotlin.load.java.components.TypeUsage +import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor +import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor +import org.jetbrains.kotlin.load.java.lazy.types.toAttributes +import org.jetbrains.kotlin.load.java.structure.classId +import org.jetbrains.kotlin.load.kotlin.internalName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode +import org.jetbrains.kotlin.resolve.DescriptorFactory +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.SyntheticScope +import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered +import org.jetbrains.kotlin.synthetic.JavaSyntheticPropertiesScope +import org.jetbrains.kotlin.synthetic.SyntheticScopeProviderExtension +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections +import org.jetbrains.org.objectweb.asm.Type + +class DebuggerFieldSyntheticScopeProvider : SyntheticScopeProviderExtension { + override fun getScopes( + moduleDescriptor: ModuleDescriptor, + javaSyntheticPropertiesScope: JavaSyntheticPropertiesScope + ): List { + return listOf(DebuggerFieldSyntheticScope(javaSyntheticPropertiesScope)) + } +} + +private class DebuggerFieldSyntheticScope(val javaSyntheticPropertiesScope: JavaSyntheticPropertiesScope) : SyntheticScope.Default() { + private val javaSourceElementFactory = JavaSourceElementFactoryImpl() + + override fun getSyntheticExtensionProperties( + receiverTypes: Collection, + name: Name, + location: LookupLocation + ): Collection { + if (!isInEvaluator(location)) { + return emptyList() + } + + return getSyntheticExtensionProperties(receiverTypes).filter { it.name == name } + } + + private fun isInEvaluator(location: LookupLocation): Boolean { + val element = (location as? KotlinLookupLocation)?.element ?: return false + val containingFile = element.containingFile?.takeIf { it.isValid } as? KtFile ?: return false + return containingFile.suppressDiagnosticsInDebugMode + } + + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection { + val result = mutableListOf() + for (type in receiverTypes) { + val clazz = type.constructor.declarationDescriptor as? ClassDescriptor ?: continue + result += getSyntheticPropertiesForClass(clazz) + } + return result + } + + private fun getSyntheticPropertiesForClass(clazz: ClassDescriptor): Collection { + val collected = mutableMapOf() + + val syntheticPropertyNames = javaSyntheticPropertiesScope + .getSyntheticExtensionProperties(listOf(clazz.defaultType)) + .mapTo(mutableSetOf()) { it.name } + + collectPropertiesWithParent(clazz, syntheticPropertyNames, collected) + return collected.values + } + + private tailrec fun collectPropertiesWithParent( + clazz: ClassDescriptor, + syntheticNames: Set, + consumer: MutableMap + ) { + when (clazz) { + is LazyJavaClassDescriptor -> collectJavaProperties(clazz, syntheticNames, consumer) + is JavaClassDescriptor -> error("Unsupported Java class type") + else -> collectKotlinProperties(clazz, consumer) + } + + val superClass = clazz.getSuperClassNotAny() + if (superClass != null) { + collectPropertiesWithParent(superClass, syntheticNames, consumer) + } + } + + private fun collectKotlinProperties(clazz: ClassDescriptor, consumer: MutableMap) { + for (descriptor in clazz.unsubstitutedMemberScope.getDescriptorsFiltered(DescriptorKindFilter.VARIABLES)) { + val propertyDescriptor = descriptor as? PropertyDescriptor ?: continue + val name = propertyDescriptor.name + if (propertyDescriptor.backingField == null || name in consumer) continue + + val type = propertyDescriptor.type + val sourceElement = propertyDescriptor.source + + consumer[name] = createSyntheticPropertyDescriptor(clazz, type, name.asString(), "Backing field", sourceElement) { state -> + state.typeMapper.mapType(clazz.defaultType) + } + } + } + + private fun collectJavaProperties( + clazz: LazyJavaClassDescriptor, + syntheticNames: Set, + consumer: MutableMap + ) { + val javaClass = clazz.jClass + + for (field in javaClass.fields) { + val fieldName = field.name + if (field.isEnumEntry || field.isStatic || fieldName in consumer || fieldName !in syntheticNames) continue + + val ownerClassName = javaClass.classId?.internalName ?: continue + val typeResolver = clazz.outerContext.typeResolver + + val type = typeResolver.transformJavaType(field.type, TypeUsage.COMMON.toAttributes()).replaceArgumentsWithStarProjections() + val sourceElement = javaSourceElementFactory.source(field) + + consumer[fieldName] = createSyntheticPropertyDescriptor(clazz, type, fieldName.asString(), "Java field", sourceElement) { + Type.getObjectType(ownerClassName) + } + } + } + + private fun createSyntheticPropertyDescriptor( + clazz: ClassDescriptor, + type: KotlinType, + fieldName: String, + description: String, + getterSource: SourceElement, + ownerType: (GenerationState) -> Type + ): PropertyDescriptor { + val propertyDescriptor = DebuggerFieldPropertyDescriptor(clazz, fieldName, description, ownerType) + + val extensionReceiverParameter = DescriptorFactory.createExtensionReceiverParameterForCallable( + propertyDescriptor, + clazz.defaultType.replaceArgumentsWithStarProjections(), + Annotations.EMPTY + ) + + propertyDescriptor.setType(type, emptyList(), null, extensionReceiverParameter) + + val getter = PropertyGetterDescriptorImpl( + propertyDescriptor, Annotations.EMPTY, Modality.FINAL, + Visibilities.PUBLIC, false, false, false, + CallableMemberDescriptor.Kind.SYNTHESIZED, + null, getterSource + ) + + propertyDescriptor.initialize(getter, null) + + return propertyDescriptor + } +} + +internal class DebuggerFieldPropertyDescriptor( + containingDeclaration: DeclarationDescriptor, + val fieldName: String, + val description: String, + val ownerType: (GenerationState) -> Type +) : PropertyDescriptorImpl( + containingDeclaration, + null, + Annotations.EMPTY, + Modality.FINAL, + Visibilities.PUBLIC, + /*isVar = */true, + Name.identifier(fieldName + "_field"), + CallableMemberDescriptor.Kind.SYNTHESIZED, + SourceElement.NO_SOURCE, + /*lateInit = */false, + /*isConst = */false, + /*isExpect = */false, + /*isActual = */false, + /*isExternal = */false, + /*isDelegated = */false +) \ No newline at end of file diff --git a/idea/resources/META-INF/extensions/ide.xml b/idea/resources/META-INF/extensions/ide.xml index 0b7d11f1236..b052b7bb4bd 100644 --- a/idea/resources/META-INF/extensions/ide.xml +++ b/idea/resources/META-INF/extensions/ide.xml @@ -50,6 +50,10 @@ + + diff --git a/idea/resources/META-INF/extensions/ide.xml.as33 b/idea/resources/META-INF/extensions/ide.xml.as33 index d7fa2a47c4a..f8162af5d68 100644 --- a/idea/resources/META-INF/extensions/ide.xml.as33 +++ b/idea/resources/META-INF/extensions/ide.xml.as33 @@ -42,6 +42,10 @@ + + diff --git a/idea/resources/META-INF/extensions/ide.xml.as34 b/idea/resources/META-INF/extensions/ide.xml.as34 index d7fa2a47c4a..f8162af5d68 100644 --- a/idea/resources/META-INF/extensions/ide.xml.as34 +++ b/idea/resources/META-INF/extensions/ide.xml.as34 @@ -42,6 +42,10 @@ + + diff --git a/idea/resources/META-INF/jvm.xml b/idea/resources/META-INF/jvm.xml index b216dd9c69d..253919320c9 100644 --- a/idea/resources/META-INF/jvm.xml +++ b/idea/resources/META-INF/jvm.xml @@ -179,5 +179,9 @@ + + + + diff --git a/idea/resources/META-INF/jvm.xml.181 b/idea/resources/META-INF/jvm.xml.181 index 8f4d5a62e37..dcf1d2bf6a0 100644 --- a/idea/resources/META-INF/jvm.xml.181 +++ b/idea/resources/META-INF/jvm.xml.181 @@ -167,5 +167,9 @@ + + + + diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.kt new file mode 100644 index 00000000000..e1fc96a426c --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.kt @@ -0,0 +1,105 @@ +package fieldGetters + +import forTests.FieldsGetters +import forTests.FieldsGetters.* + +fun main(args: Array) { + //Breakpoint! + val a = 5 +} + +class K1 { + val a: Int = 0 + get() = field + 1 +} + +class K2 { + @JvmField + val a: Int = 0 +} + +// EXPRESSION: K1().a +// RESULT: 1: I + +// EXPRESSION: K1().a_field +// RESULT: 0: I + +// EXPRESSION: K2().a +// RESULT: 0: I + +// EXPRESSION: K2().a_field +// RESULT: 0: I + + + +// EXPRESSION: PublicField().foo +// RESULT: "a": Ljava/lang/String; + +// EXPRESSION: PublicField().foo_field +// RESULT: Unresolved reference: foo_field + +// EXPRESSION: PackagePrivateField().foo +// RESULT: "b": Ljava/lang/String; + +// EXPRESSION: PackagePrivateField().foo_field +// RESULT: Unresolved reference: foo_field + +// EXPRESSION: ProtectedField().foo +// RESULT: "c": Ljava/lang/String; + +// EXPRESSION: ProtectedField().foo_field +// RESULT: Unresolved reference: foo_field + +// EXPRESSION: PrivateField().foo +// RESULT: "d": Ljava/lang/String; + +// EXPRESSION: PrivateField().foo_field +// RESULT: Unresolved reference: foo_field + +// EXPRESSION: PublicFieldGetter().foo +// RESULT: "b": Ljava/lang/String; + +// EXPRESSION: PublicFieldGetter().foo_field +// RESULT: "a": Ljava/lang/String; + +// EXPRESSION: PrivateFieldPublicGetter().foo +// RESULT: "d": Ljava/lang/String; + +// EXPRESSION: PrivateFieldPublicGetter().foo_field +// RESULT: "c": Ljava/lang/String; + +// EXPRESSION: PrivateFieldPrivateGetter().foo +// RESULT: "f": Ljava/lang/String; + +// EXPRESSION: PrivateFieldPrivateGetter().foo_field +// RESULT: "e": Ljava/lang/String; + +// EXPRESSION: PublicGetter1().foo +// RESULT: "g": Ljava/lang/String; + +// EXPRESSION: PublicGetter1().foo_field +// RESULT: "a": Ljava/lang/String; + +// EXPRESSION: PublicGetter2().foo +// RESULT: "h": Ljava/lang/String; + +// EXPRESSION: PublicGetter2().foo_field +// RESULT: "b": Ljava/lang/String; + +// EXPRESSION: PrivateGetter1().foo +// RESULT: "d": Ljava/lang/String; + +// EXPRESSION: PrivateGetter1().foo_field +// RESULT: Unresolved reference: foo_field + +// EXPRESSION: PublicGetterOnly().foo +// RESULT: "a": Ljava/lang/String; + +// EXPRESSION: PublicGetterOnly().foo_field +// RESULT: Unresolved reference: foo_field + +// EXPRESSION: PublicFieldAndGetterInParent().foo +// RESULT: "a": Ljava/lang/String; + +// EXPRESSION: PublicFieldAndGetterInParent().foo_field +// RESULT: "b": Ljava/lang/String; \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.out new file mode 100644 index 00000000000..1b1d96df347 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.out @@ -0,0 +1,29 @@ +LineBreakpoint created at fieldGetters.kt:8 +Run Java +Connected to the target VM +fieldGetters.kt:8 +Compile bytecode for K1().a +Compile bytecode for K1().a_field +Compile bytecode for K2().a +Compile bytecode for K2().a_field +Compile bytecode for PublicField().foo +Compile bytecode for PackagePrivateField().foo +Compile bytecode for ProtectedField().foo +Compile bytecode for PrivateField().foo +Compile bytecode for PublicFieldGetter().foo +Compile bytecode for PublicFieldGetter().foo_field +Compile bytecode for PrivateFieldPublicGetter().foo +Compile bytecode for PrivateFieldPublicGetter().foo_field +Compile bytecode for PrivateFieldPrivateGetter().foo +Compile bytecode for PrivateFieldPrivateGetter().foo_field +Compile bytecode for PublicGetter1().foo +Compile bytecode for PublicGetter1().foo_field +Compile bytecode for PublicGetter2().foo +Compile bytecode for PublicGetter2().foo_field +Compile bytecode for PrivateGetter1().foo +Compile bytecode for PublicGetterOnly().foo +Compile bytecode for PublicFieldAndGetterInParent().foo +Compile bytecode for PublicFieldAndGetterInParent().foo_field +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/forTests/FieldsGetters.java b/idea/testData/debugger/tinyApp/src/forTests/FieldsGetters.java new file mode 100644 index 00000000000..b7f9eefefb5 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/forTests/FieldsGetters.java @@ -0,0 +1,76 @@ +package forTests; + +public class FieldsGetters { + public static class PublicField { + public String foo = "a"; + } + + public static class PackagePrivateField { + String foo = "b"; + } + + public static class ProtectedField { + protected String foo = "c"; + } + + public static class PrivateField { + private String foo = "d"; + } + + public static class PublicFieldGetter { + public final String foo = "a"; + + public String getFoo() { + return "b"; + } + } + + public static class PrivateFieldPublicGetter { + private final String foo = "c"; + + public String getFoo() { + return "d"; + } + } + + public static class PrivateFieldPrivateGetter { + private final String foo = "e"; + + public String getFoo() { + return "f"; + } + } + + public static class PublicGetter1 extends PublicField { + public String getFoo() { + return "g"; + } + } + + public static class PublicGetter2 extends PackagePrivateField { + public String getFoo() { + return "h"; + } + } + + public static class PrivateGetter1 extends PrivateField { + private String getFoo() { + return "g"; + } + } + + public static class PublicGetterOnly { + public String getFoo() { + return "a"; + } + } + + public static class PublicFieldAndGetterInParent extends PublicGetterOnly { + public String foo = "b"; + } + + public abstract class AbstractGetter { + public String foo = "c"; + public abstract String getFoo(); + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 50446a91c57..6e127915b9a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -136,6 +136,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractVariablesFromCall.kt"); } + @TestMetadata("fieldGetters.kt") + public void testFieldGetters() throws Exception { + runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fieldGetters.kt"); + } + @TestMetadata("fileWithError.kt") public void testFileWithError() throws Exception { runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/fileWithError.kt");