"Create class from usage": add visibility to primary constructor if needed

#KT-29844 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-01-24 15:28:49 +09:00
committed by igoriakovlev
parent b1e8238ea2
commit efa981db36
11 changed files with 84 additions and 6 deletions
@@ -531,7 +531,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
} }
} }
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> { CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> {
with((callableInfo as ClassWithPrimaryConstructorInfo).classInfo) { val classWithPrimaryConstructorInfo = callableInfo as ClassWithPrimaryConstructorInfo
with(classWithPrimaryConstructorInfo.classInfo) {
val classBody = when (kind) { val classBody = when (kind) {
ClassKind.ANNOTATION_CLASS, ClassKind.ENUM_ENTRY -> "" ClassKind.ANNOTATION_CLASS, ClassKind.ENUM_ENTRY -> ""
else -> "{\n\n}" else -> "{\n\n}"
@@ -551,8 +552,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
ClassKind.PLAIN_CLASS, ClassKind.INTERFACE -> "<>" ClassKind.PLAIN_CLASS, ClassKind.INTERFACE -> "<>"
else -> "" else -> ""
} }
val ctor =
classWithPrimaryConstructorInfo.primaryConstructorVisibility?.name?.let { " $it constructor" } ?: ""
psiFactory.createDeclaration<KtClassOrObject>( psiFactory.createDeclaration<KtClassOrObject>(
"$openMod$innerMod${kind.keyword} $safeName$typeParamList$paramList$returnTypeString $classBody" "$openMod$innerMod${kind.keyword} $safeName$typeParamList$ctor$paramList$returnTypeString $classBody"
) )
} }
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes 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.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassInfo import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassInfo
@@ -215,7 +216,8 @@ class FunctionInfo(
class ClassWithPrimaryConstructorInfo( class ClassWithPrimaryConstructorInfo(
val classInfo: ClassInfo, val classInfo: ClassInfo,
expectedTypeInfo: TypeInfo, expectedTypeInfo: TypeInfo,
modifierList: KtModifierList? = null modifierList: KtModifierList? = null,
val primaryConstructorVisibility: Visibility? = null
) : CallableInfo( ) : CallableInfo(
classInfo.name, classInfo.name,
TypeInfo.Empty, TypeInfo.Empty,
@@ -5,8 +5,11 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass 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.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult 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.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeInfoForTypeArguments 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 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( return ClassInfo(
name = name, name = name,
targetParents = filteredParents, targetParents = filteredParents,
expectedTypeInfo = expectedTypeInfo, expectedTypeInfo = expectedTypeInfo,
inner = inner, inner = inner,
typeArguments = typeArgumentInfos, typeArguments = typeArgumentInfos,
parameterInfos = parameterInfos parameterInfos = parameterInfos,
primaryConstructorVisibility = primaryConstructorVisibility
) )
} }
} }
@@ -16,6 +16,7 @@ import com.intellij.openapi.ui.DialogWrapper
import com.intellij.psi.* import com.intellij.psi.*
import org.jetbrains.annotations.Nls import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix
@@ -67,7 +68,8 @@ data class ClassInfo(
val inner: Boolean = false, val inner: Boolean = false,
val open: Boolean = false, val open: Boolean = false,
val typeArguments: List<TypeInfo> = Collections.emptyList(), val typeArguments: List<TypeInfo> = Collections.emptyList(),
val parameterInfos: List<ParameterInfo> = Collections.emptyList() val parameterInfos: List<ParameterInfo> = Collections.emptyList(),
val primaryConstructorVisibility: Visibility? = null
) { ) {
val applicableParents by lazy { val applicableParents by lazy {
targetParents.filter { targetParents.filter {
@@ -221,7 +223,8 @@ open class CreateClassFromUsageFix<E : KtElement> protected constructor(
val constructorInfo = ClassWithPrimaryConstructorInfo( val constructorInfo = ClassWithPrimaryConstructorInfo(
classInfo, classInfo,
// Need for #KT-22137 // Need for #KT-22137
if (expectedTypeInfo.isUnit) TypeInfo.Empty else expectedTypeInfo if (expectedTypeInfo.isUnit) TypeInfo.Empty else expectedTypeInfo,
primaryConstructorVisibility = classInfo.primaryConstructorVisibility
) )
val builder = CallableBuilderConfiguration( val builder = CallableBuilderConfiguration(
Collections.singletonList(constructorInfo), Collections.singletonList(constructorInfo),
@@ -0,0 +1,5 @@
// "Create class 'Bar'" "true"
// DISABLE-ERRORS
internal class Foo
val bar = <caret>Bar(Foo())
@@ -0,0 +1,9 @@
// "Create class 'Bar'" "true"
// DISABLE-ERRORS
internal class Foo
val bar = Bar(Foo())
class Bar internal constructor(foo: Foo) {
}
@@ -0,0 +1,5 @@
// "Create class 'Bar'" "true"
// DISABLE-ERRORS
private class Foo
val bar = <caret>Bar(Foo())
@@ -0,0 +1,9 @@
// "Create class 'Bar'" "true"
// DISABLE-ERRORS
private class Foo
val bar = Bar(Foo())
class Bar private constructor(foo: Foo) {
}
@@ -0,0 +1,5 @@
// "Create class 'Bar'" "true"
// DISABLE-ERRORS
class Foo
val bar = <caret>Bar(Foo())
@@ -0,0 +1,9 @@
// "Create class 'Bar'" "true"
// DISABLE-ERRORS
class Foo
val bar = Bar(Foo())
class Bar(foo: Foo) {
}
@@ -3294,6 +3294,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/notApplicableInReturn.kt"); 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") @TestMetadata("quotedName.kt")
public void testQuotedName() throws Exception { public void testQuotedName() throws Exception {
runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/quotedName.kt"); runTest("idea/testData/quickfix/createFromUsage/createClass/callExpression/quotedName.kt");