diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 54365f614c6..db0a356b1ca 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -268,9 +268,7 @@ public class JvmCodegenUtil { @NotNull public static CallableMemberDescriptor getDirectMember(@NotNull CallableMemberDescriptor descriptor) { - return descriptor instanceof PropertyAccessorDescriptor - ? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty() - : descriptor; + return DescriptorUtils.getDirectMember(descriptor); } public static boolean isArgumentWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 68b253ca40b..043c687891c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -224,7 +224,7 @@ public class KotlinTypeMapper { } } - CallableMemberDescriptor directMember = getDirectMember(descriptor); + CallableMemberDescriptor directMember = DescriptorUtils.getDirectMember(descriptor); if (directMember instanceof DeserializedCallableMemberDescriptor) { String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember, publicFacade); @@ -946,7 +946,7 @@ public class KotlinTypeMapper { return null; } - descriptor = getDirectMember(descriptor); + descriptor = DescriptorUtils.getDirectMember(descriptor); assert descriptor instanceof DeserializedCallableMemberDescriptor : "Descriptor without sources should be instance of DeserializedCallableMemberDescriptor, but: " + descriptor; @@ -1039,7 +1039,7 @@ public class KotlinTypeMapper { writeVoidReturn(sw); } else { - CallableMemberDescriptor directMember = getDirectMember(f); + CallableMemberDescriptor directMember = DescriptorUtils.getDirectMember(f); KotlinType thisIfNeeded = null; if (OwnerKind.DEFAULT_IMPLS == kind) { ReceiverTypeAndTypeParameters receiverTypeAndTypeParameters = TypeMapperUtilsKt.patchTypeParametersForDefaultImplMethod(directMember); diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index 4a607109393..ea89948906e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -841,18 +841,20 @@ internal class DescriptorRendererImpl( private fun renderProperty(property: PropertyDescriptor, builder: StringBuilder) { if (!startFromName) { - builder.renderAnnotations(property) - renderVisibility(property.visibility, builder) + if (!startFromDeclarationKeyword) { + builder.renderAnnotations(property) + renderVisibility(property.visibility, builder) - if (property.isConst) { - builder.append("const ") + if (property.isConst) { + builder.append("const ") + } + + renderExternal(property, builder) + renderModalityForCallable(property, builder) + renderOverride(property, builder) + renderLateInit(property, builder) + renderMemberKind(property, builder) } - - renderExternal(property, builder) - renderModalityForCallable(property, builder) - renderOverride(property, builder) - renderLateInit(property, builder) - renderMemberKind(property, builder) renderValVarPrefix(property, builder) renderTypeParameters(property.typeParameters, builder, true) renderReceiver(property, builder) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java index 4e24de63e74..4b52c7c9cf3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java @@ -600,4 +600,12 @@ public class DescriptorUtils { throw new IllegalStateException("Function not found"); } + + @NotNull + public static CallableMemberDescriptor getDirectMember(@NotNull CallableMemberDescriptor descriptor) { + return descriptor instanceof PropertyAccessorDescriptor + ? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty() + : descriptor; + } + } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceProtectedToPublishedApiCallFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceProtectedToPublishedApiCallFix.kt index b1e2caa2578..fe48b266514 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceProtectedToPublishedApiCallFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceProtectedToPublishedApiCallFix.kt @@ -20,8 +20,8 @@ import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.SmartPsiElementPointer +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory @@ -31,12 +31,9 @@ import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName -import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer -import org.jetbrains.kotlin.resolve.source.KotlinSourceElement +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.source.getPsi class ReplaceProtectedToPublishedApiCallFix( @@ -44,31 +41,44 @@ class ReplaceProtectedToPublishedApiCallFix( val classOwnerPointer: SmartPsiElementPointer, val originalName: String, val paramNames: Map, - val signature: String + val signature: String, + val isProperty: Boolean, + val isVar: Boolean ) : KotlinQuickFixAction(element) { override fun getFamilyName() = "Replace with @PublishedApi bridge call" - val newFunctionName = "`${originalName.newName}`" + val newName = "`${originalName.newName}`" - override fun getText() = "Replace with generated @PublishedApi bridge call '$newFunctionName(...)'" + override fun getText() = "Replace with generated @PublishedApi bridge call '$newName${if (!isProperty) "(...)" else ""}'" override fun invoke(project: Project, editor: Editor?, file: KtFile) { val element = element ?: return - val isPublishedFunctionAlreadyExists = false/*TODO*/ - if (!isPublishedFunctionAlreadyExists) { + val isPublishedMemberAlreadyExists = false/*TODO*/ + if (!isPublishedMemberAlreadyExists) { val classOwner = classOwnerPointer.element ?: return + val newMember: KtDeclaration = + if (isProperty) { + KtPsiFactory(classOwner).createProperty( + "@kotlin.PublishedApi\n" + + "internal " + signature.replaceFirst("$originalName:", "$newName:") + + "\n" + + "get() = $originalName\n" + + if (isVar) "set(value) { $originalName = value }" else "" + ) - val function = KtPsiFactory(classOwner).createFunction( - "@kotlin.PublishedApi\n" + - "internal "+//${extensionType?.let { it + "." } ?: ""}$newFunctionName(${paramNames.entries.map { it.key + " :" + it.value }.joinToString(", ")}) = " + - signature.replaceFirst("$originalName(", "$newFunctionName(") + - " = $originalName(${paramNames.keys.map { it }.joinToString(", ")})" - ) - val newFunction = classOwner.addDeclaration(function) - ShortenReferences.DEFAULT.process(newFunction) + } + else { + KtPsiFactory(classOwner).createFunction( + "@kotlin.PublishedApi\n" + + "internal " + signature.replaceFirst("$originalName(", "$newName(") + + " = $originalName(${paramNames.keys.map { it }.joinToString(", ")})" + ) + } + + ShortenReferences.DEFAULT.process(classOwner.addDeclaration(newMember)) } - element.replace(KtPsiFactory(element).createExpression(newFunctionName)) + element.replace(KtPsiFactory(element).createExpression(newName)) } companion object : KotlinSingleIntentionActionFactory() { @@ -80,15 +90,19 @@ class ReplaceProtectedToPublishedApiCallFix( override fun createAction(diagnostic: Diagnostic): IntentionAction? { val psiElement = diagnostic.psiElement as? KtExpression ?: return null - val descriptor = DiagnosticFactory.cast(diagnostic, Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE).a - val isProperty = descriptor is PropertyAccessorDescriptor || descriptor is PropertyDescriptor - if (isProperty) return null/*TODO support properties*/ + val descriptor = DiagnosticFactory.cast(diagnostic, Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE).a.let { + if (it is CallableMemberDescriptor) DescriptorUtils.getDirectMember(it) else it + } + val isProperty = descriptor is PropertyDescriptor + val isVar = descriptor is PropertyDescriptor && descriptor.isVar val signature = signatureRenderer.render(descriptor) val paramNameAndType = descriptor.valueParameters.associate { it.name.asString() to it.type.getJetTypeFqName(false)} val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return null val source = classDescriptor.source.getPsi() as? KtClass ?: return null - return ReplaceProtectedToPublishedApiCallFix(psiElement, source.createSmartPointer(), descriptor.name.asString(), paramNameAndType, signature) + return ReplaceProtectedToPublishedApiCallFix( + psiElement, source.createSmartPointer(), descriptor.name.asString(), paramNameAndType, signature, isProperty, isVar + ) } val String.newName: String diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt new file mode 100644 index 00000000000..19081e838c3 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt @@ -0,0 +1,16 @@ +// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true" +annotation class Z + +open class ABase { + @Z + protected var String.prop: Int + get() = 1 + set(field) = {} + + + inline fun test() { + { + "123".prop + }() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt.after new file mode 100644 index 00000000000..440a7586e25 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt.after @@ -0,0 +1,23 @@ +// "Replace with generated @PublishedApi bridge call '`access$test`(...)'" "true" +annotation class Z + +open class ABase { + @Z + protected var String.prop: Int + get() = 1 + set(field) = {} + + + inline fun test() { + { + "123".`access$prop` + }() + } + + @PublishedApi + internal var String.`access$prop`: Int + get() = prop + set(value) { + prop = value + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt new file mode 100644 index 00000000000..5472952d0a8 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt @@ -0,0 +1,13 @@ +// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true" +annotation class Z + +open class ABase { + @Z + protected val prop = 1 + + inline fun test() { + { + prop + }() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt.after new file mode 100644 index 00000000000..eee67dce219 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt.after @@ -0,0 +1,17 @@ +// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true" +annotation class Z + +open class ABase { + @Z + protected val prop = 1 + + inline fun test() { + { + `access$prop` + }() + } + + @PublishedApi + internal val `access$prop`: Int + get() = prop +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt new file mode 100644 index 00000000000..d14d0c73e4a --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt @@ -0,0 +1,13 @@ +// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true" +annotation class Z + +open class ABase { + @Z + protected var prop = 1 + + inline fun test() { + { + prop + }() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt.after new file mode 100644 index 00000000000..5606e32f0b7 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt.after @@ -0,0 +1,20 @@ +// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true" +annotation class Z + +open class ABase { + @Z + protected var prop = 1 + + inline fun test() { + { + `access$prop` + }() + } + + @PublishedApi + internal var `access$prop`: Int + get() = prop + set(value) { + prop = value + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 8f76a861d74..1c3560ea75b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -4869,6 +4869,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("extensionVar.kt") + public void testExtensionVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extensionVar.kt"); + doTest(fileName); + } + @TestMetadata("generic.kt") public void testGeneric() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/generic.kt"); @@ -4892,6 +4898,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simple.kt"); doTest(fileName); } + + @TestMetadata("simpleVal.kt") + public void testSimpleVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVal.kt"); + doTest(fileName); + } + + @TestMetadata("simpleVar.kt") + public void testSimpleVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/simpleVar.kt"); + doTest(fileName); + } } @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/safeCall")