From efa981db36eebc629b668e020592ab0eb0f8e239 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Fri, 24 Jan 2020 15:28:49 +0900 Subject: [PATCH] "Create class from usage": add visibility to primary constructor if needed #KT-29844 Fixed --- .../callableBuilder/CallableBuilder.kt | 7 +++++-- .../callableBuilder/CallableInfo.kt | 4 +++- ...CreateClassFromConstructorCallActionFactory.kt | 15 ++++++++++++++- .../createClass/CreateClassFromUsageFix.kt | 7 +++++-- .../callExpression/parameterClassIsInternal.kt | 5 +++++ .../parameterClassIsInternal.kt.after | 9 +++++++++ .../callExpression/parameterClassIsPrivate.kt | 5 +++++ .../parameterClassIsPrivate.kt.after | 9 +++++++++ .../callExpression/parameterClassIsPublic.kt | 5 +++++ .../parameterClassIsPublic.kt.after | 9 +++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 15 +++++++++++++++ 11 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index d5be2eb0f17..80cc29978e0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -531,7 +531,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { } } CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> { - with((callableInfo as ClassWithPrimaryConstructorInfo).classInfo) { + val classWithPrimaryConstructorInfo = callableInfo as ClassWithPrimaryConstructorInfo + with(classWithPrimaryConstructorInfo.classInfo) { val classBody = when (kind) { ClassKind.ANNOTATION_CLASS, ClassKind.ENUM_ENTRY -> "" else -> "{\n\n}" @@ -551,8 +552,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { ClassKind.PLAIN_CLASS, ClassKind.INTERFACE -> "<>" else -> "" } + val ctor = + classWithPrimaryConstructorInfo.primaryConstructorVisibility?.name?.let { " $it constructor" } ?: "" psiFactory.createDeclaration( - "$openMod$innerMod${kind.keyword} $safeName$typeParamList$paramList$returnTypeString $classBody" + "$openMod$innerMod${kind.keyword} $safeName$typeParamList$ctor$paramList$returnTypeString $classBody" ) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt index 0aac74417ac..689871ed9e3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder import com.intellij.psi.PsiElement import com.intellij.util.ArrayUtil import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes +import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassInfo @@ -215,7 +216,8 @@ class FunctionInfo( class ClassWithPrimaryConstructorInfo( val classInfo: ClassInfo, expectedTypeInfo: TypeInfo, - modifierList: KtModifierList? = null + modifierList: KtModifierList? = null, + val primaryConstructorVisibility: Visibility? = null ) : CallableInfo( classInfo.name, TypeInfo.Empty, diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt index f2ea75f83c6..21baeddd84f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt @@ -5,8 +5,11 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult +import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeInfoForTypeArguments @@ -88,13 +91,23 @@ object CreateClassFromConstructorCallActionFactory : CreateClassFromUsageFactory val typeArgumentInfos = if (inAnnotationEntry) Collections.emptyList() else callExpr.getTypeInfoForTypeArguments() + val argumentClassVisibilities = valueArguments.mapNotNull { + (it.getArgumentExpression()?.getCallableDescriptor() as? ClassConstructorDescriptor)?.containingDeclaration?.visibility + } + val primaryConstructorVisibility = when { + Visibilities.PRIVATE in argumentClassVisibilities -> Visibilities.PRIVATE + Visibilities.INTERNAL in argumentClassVisibilities -> Visibilities.INTERNAL + else -> null + } + return ClassInfo( name = name, targetParents = filteredParents, expectedTypeInfo = expectedTypeInfo, inner = inner, typeArguments = typeArgumentInfos, - parameterInfos = parameterInfos + parameterInfos = parameterInfos, + primaryConstructorVisibility = primaryConstructorVisibility ) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt index 4abb8335f03..af61ff4c50c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt @@ -16,6 +16,7 @@ import com.intellij.openapi.ui.DialogWrapper import com.intellij.psi.* import org.jetbrains.annotations.Nls import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix @@ -67,7 +68,8 @@ data class ClassInfo( val inner: Boolean = false, val open: Boolean = false, val typeArguments: List = Collections.emptyList(), - val parameterInfos: List = Collections.emptyList() + val parameterInfos: List = Collections.emptyList(), + val primaryConstructorVisibility: Visibility? = null ) { val applicableParents by lazy { targetParents.filter { @@ -221,7 +223,8 @@ open class CreateClassFromUsageFix protected constructor( val constructorInfo = ClassWithPrimaryConstructorInfo( classInfo, // Need for #KT-22137 - if (expectedTypeInfo.isUnit) TypeInfo.Empty else expectedTypeInfo + if (expectedTypeInfo.isUnit) TypeInfo.Empty else expectedTypeInfo, + primaryConstructorVisibility = classInfo.primaryConstructorVisibility ) val builder = CallableBuilderConfiguration( Collections.singletonList(constructorInfo), diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt new file mode 100644 index 00000000000..986a07edca6 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt @@ -0,0 +1,5 @@ +// "Create class 'Bar'" "true" +// DISABLE-ERRORS +internal class Foo + +val bar = Bar(Foo()) diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt.after b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt.after new file mode 100644 index 00000000000..3bfe69c12d3 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt.after @@ -0,0 +1,9 @@ +// "Create class 'Bar'" "true" +// DISABLE-ERRORS +internal class Foo + +val bar = Bar(Foo()) + +class Bar internal constructor(foo: Foo) { + +} diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt new file mode 100644 index 00000000000..3f8b2feff0b --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt @@ -0,0 +1,5 @@ +// "Create class 'Bar'" "true" +// DISABLE-ERRORS +private class Foo + +val bar = Bar(Foo()) diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt.after b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt.after new file mode 100644 index 00000000000..46fdc914110 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt.after @@ -0,0 +1,9 @@ +// "Create class 'Bar'" "true" +// DISABLE-ERRORS +private class Foo + +val bar = Bar(Foo()) + +class Bar private constructor(foo: Foo) { + +} diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt new file mode 100644 index 00000000000..c24c6158cae --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt @@ -0,0 +1,5 @@ +// "Create class 'Bar'" "true" +// DISABLE-ERRORS +class Foo + +val bar = Bar(Foo()) diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt.after b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt.after new file mode 100644 index 00000000000..a18037cb888 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt.after @@ -0,0 +1,9 @@ +// "Create class 'Bar'" "true" +// DISABLE-ERRORS +class Foo + +val bar = Bar(Foo()) + +class Bar(foo: Foo) { + +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index a48dfb53164..466c3ed4e4f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3294,6 +3294,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/notApplicableInReturn.kt"); } + @TestMetadata("parameterClassIsInternal.kt") + public void testParameterClassIsInternal() throws Exception { + runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsInternal.kt"); + } + + @TestMetadata("parameterClassIsPrivate.kt") + public void testParameterClassIsPrivate() throws Exception { + runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPrivate.kt"); + } + + @TestMetadata("parameterClassIsPublic.kt") + public void testParameterClassIsPublic() throws Exception { + runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/parameterClassIsPublic.kt"); + } + @TestMetadata("quotedName.kt") public void testQuotedName() throws Exception { runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/quotedName.kt");