Create Class from Usage: Use type parameter bounds as supertypes
#KT-15242 Fixed
This commit is contained in:
@@ -92,7 +92,12 @@ private fun KotlinType.hasAnnotationMaybeExternal(fqName: FqName) = with (annota
|
|||||||
findAnnotation(fqName) ?: findExternalAnnotation(fqName)
|
findAnnotation(fqName) ?: findExternalAnnotation(fqName)
|
||||||
} != null
|
} != null
|
||||||
|
|
||||||
fun KotlinType.isResolvableInScope(scope: LexicalScope?, checkTypeParameters: Boolean): Boolean {
|
fun KotlinType.isResolvableInScope(scope: LexicalScope?, checkTypeParameters: Boolean, allowIntersections: Boolean = false): Boolean {
|
||||||
|
if (constructor is IntersectionTypeConstructor) {
|
||||||
|
if (!allowIntersections) return false
|
||||||
|
return constructor.supertypes.all { it.isResolvableInScope(scope, checkTypeParameters, allowIntersections) }
|
||||||
|
}
|
||||||
|
|
||||||
if (canBeReferencedViaImport()) return true
|
if (canBeReferencedViaImport()) return true
|
||||||
|
|
||||||
val descriptor = constructor.declarationDescriptor
|
val descriptor = constructor.declarationDescriptor
|
||||||
@@ -116,10 +121,14 @@ fun KotlinType.anonymousObjectSuperTypeOrNull(): KotlinType? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinType.getResolvableApproximations(scope: LexicalScope?, checkTypeParameters: Boolean): Sequence<KotlinType> {
|
fun KotlinType.getResolvableApproximations(
|
||||||
|
scope: LexicalScope?,
|
||||||
|
checkTypeParameters: Boolean,
|
||||||
|
allowIntersections: Boolean = false
|
||||||
|
): Sequence<KotlinType> {
|
||||||
return (listOf(this) + TypeUtils.getAllSupertypes(this))
|
return (listOf(this) + TypeUtils.getAllSupertypes(this))
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.isResolvableInScope(scope, checkTypeParameters) }
|
.filter { it.isResolvableInScope(scope, checkTypeParameters, allowIntersections) }
|
||||||
.mapNotNull mapArgs@ {
|
.mapNotNull mapArgs@ {
|
||||||
val resolvableArgs = it.arguments.filterTo(SmartSet.create()) { it.type.isResolvableInScope(scope, checkTypeParameters) }
|
val resolvableArgs = it.arguments.filterTo(SmartSet.create()) { it.type.isResolvableInScope(scope, checkTypeParameters) }
|
||||||
if (resolvableArgs.containsAll(it.arguments)) return@mapArgs it
|
if (resolvableArgs.containsAll(it.arguments)) return@mapArgs it
|
||||||
|
|||||||
+26
-23
@@ -85,13 +85,13 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
class TypeCandidate(val theType: KotlinType, scope: HierarchicalScope? = null) {
|
class TypeCandidate(val theType: KotlinType, scope: HierarchicalScope? = null) {
|
||||||
val typeParameters: Array<TypeParameterDescriptor>
|
val typeParameters: Array<TypeParameterDescriptor>
|
||||||
var renderedType: String? = null
|
var renderedTypes: List<String> = emptyList()
|
||||||
private set
|
private set
|
||||||
var renderedTypeParameters: List<RenderedTypeParameter>? = null
|
var renderedTypeParameters: List<RenderedTypeParameter>? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fakeFunction: FunctionDescriptor?) {
|
fun render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fakeFunction: FunctionDescriptor?) {
|
||||||
renderedType = theType.renderShort(typeParameterNameMap)
|
renderedTypes = theType.renderShort(typeParameterNameMap)
|
||||||
renderedTypeParameters = typeParameters.map {
|
renderedTypeParameters = typeParameters.map {
|
||||||
RenderedTypeParameter(it, it.containingDeclaration == fakeFunction, typeParameterNameMap[it]!!)
|
RenderedTypeParameter(it, it.containingDeclaration == fakeFunction, typeParameterNameMap[it]!!)
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ class TypeCandidate(val theType: KotlinType, scope: HierarchicalScope? = null) {
|
|||||||
val typeParametersInType = theType.getTypeParameters()
|
val typeParametersInType = theType.getTypeParameters()
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
typeParameters = typeParametersInType.toTypedArray()
|
typeParameters = typeParametersInType.toTypedArray()
|
||||||
renderedType = theType.renderShort(Collections.emptyMap())
|
renderedTypes = theType.renderShort(Collections.emptyMap())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typeParameters = getTypeParameterNamesNotInScope(typeParametersInType, scope).toTypedArray()
|
typeParameters = getTypeParameterNamesNotInScope(typeParametersInType, scope).toTypedArray()
|
||||||
@@ -117,8 +117,8 @@ data class RenderedTypeParameter(
|
|||||||
val text: String
|
val text: String
|
||||||
)
|
)
|
||||||
|
|
||||||
fun List<TypeCandidate>.getTypeByRenderedType(renderedType: String): KotlinType? =
|
fun List<TypeCandidate>.getTypeByRenderedType(renderedTypes: List<String>): KotlinType? =
|
||||||
firstOrNull { it.renderedType == renderedType }?.theType
|
firstOrNull { it.renderedTypes == renderedTypes }?.theType
|
||||||
|
|
||||||
class CallableBuilderConfiguration(
|
class CallableBuilderConfiguration(
|
||||||
val callableInfos: List<CallableInfo>,
|
val callableInfos: List<CallableInfo>,
|
||||||
@@ -421,7 +421,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
else null
|
else null
|
||||||
|
|
||||||
val ownerTypeString = if (isExtension) {
|
val ownerTypeString = if (isExtension) {
|
||||||
val renderedType = receiverTypeCandidate!!.renderedType!!
|
val renderedType = receiverTypeCandidate!!.renderedTypes.first()
|
||||||
val isFunctionType = receiverTypeCandidate.theType.constructor.declarationDescriptor is FunctionClassDescriptor
|
val isFunctionType = receiverTypeCandidate.theType.constructor.declarationDescriptor is FunctionClassDescriptor
|
||||||
if (isFunctionType) "($renderedType)." else "$renderedType."
|
if (isFunctionType) "($renderedType)." else "$renderedType."
|
||||||
} else ""
|
} else ""
|
||||||
@@ -569,22 +569,22 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val typeRefsToShorten = ArrayList<KtElement>()
|
val typeRefsToShorten = ArrayList<KtElement>()
|
||||||
|
|
||||||
if (config.isExtension) {
|
if (config.isExtension) {
|
||||||
val receiverTypeText = receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap)
|
val receiverTypeText = receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap).first()
|
||||||
val replacingTypeRef = KtPsiFactory(declaration).createType(receiverTypeText)
|
val replacingTypeRef = KtPsiFactory(declaration).createType(receiverTypeText)
|
||||||
val newTypeRef = (declaration as KtCallableDeclaration).setReceiverTypeReference(replacingTypeRef)!!
|
val newTypeRef = (declaration as KtCallableDeclaration).setReceiverTypeReference(replacingTypeRef)!!
|
||||||
typeRefsToShorten.add(newTypeRef)
|
typeRefsToShorten.add(newTypeRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
val returnTypeRef = declaration.getReturnTypeReference()
|
val returnTypeRefs = declaration.getReturnTypeReferences()
|
||||||
if (returnTypeRef != null) {
|
if (returnTypeRefs.isNotEmpty()) {
|
||||||
val returnType = typeCandidates[callableInfo.returnTypeInfo]!!.getTypeByRenderedType(
|
val returnType = typeCandidates[callableInfo.returnTypeInfo]!!.getTypeByRenderedType(
|
||||||
returnTypeRef.text
|
returnTypeRefs.map { it.text }
|
||||||
?: throw AssertionError("Expression for return type shouldn't be empty: declaration = ${declaration.text}")
|
?: throw AssertionError("Expression for return type shouldn't be empty: declaration = ${declaration.text}")
|
||||||
)
|
)
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
// user selected a given type
|
// user selected a given type
|
||||||
replaceWithLongerName(returnTypeRef, returnType)
|
replaceWithLongerName(returnTypeRefs, returnType)
|
||||||
typeRefsToShorten.add(declaration.getReturnTypeReference()!!)
|
typeRefsToShorten.addAll(declaration.getReturnTypeReferences())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,11 +595,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val parameterTypeRef = parameter.typeReference
|
val parameterTypeRef = parameter.typeReference
|
||||||
if (parameterTypeRef != null) {
|
if (parameterTypeRef != null) {
|
||||||
val parameterType = parameterTypeExpressions[i].typeCandidates.getTypeByRenderedType(
|
val parameterType = parameterTypeExpressions[i].typeCandidates.getTypeByRenderedType(
|
||||||
parameterTypeRef.text
|
listOf(parameterTypeRef.text)
|
||||||
?: throw AssertionError("Expression for parameter type shouldn't be empty: declaration = ${declaration.text}")
|
?: throw AssertionError("Expression for parameter type shouldn't be empty: declaration = ${declaration.text}")
|
||||||
)
|
)
|
||||||
if (parameterType != null) {
|
if (parameterType != null) {
|
||||||
replaceWithLongerName(parameterTypeRef, parameterType)
|
replaceWithLongerName(listOf(parameterTypeRef), parameterType)
|
||||||
parameterIndicesToShorten.add(i)
|
parameterIndicesToShorten.add(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -705,11 +705,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
callableInfo.parameterInfos.asSequence()
|
callableInfo.parameterInfos.asSequence()
|
||||||
.flatMap { typeCandidates[it.typeInfo]!!.asSequence() }
|
.flatMap { typeCandidates[it.typeInfo]!!.asSequence() }
|
||||||
.forEach { typeParameterMap[it.renderedType!!] = it.renderedTypeParameters!! }
|
.forEach { typeParameterMap[it.renderedTypes.first()] = it.renderedTypeParameters!! }
|
||||||
|
|
||||||
if (declaration.getReturnTypeReference() != null) {
|
if (declaration.getReturnTypeReference() != null) {
|
||||||
typeCandidates[callableInfo.returnTypeInfo]!!.forEach {
|
typeCandidates[callableInfo.returnTypeInfo]!!.forEach {
|
||||||
typeParameterMap[it.renderedType!!] = it.renderedTypeParameters!!
|
typeParameterMap[it.renderedTypes.first()] = it.renderedTypeParameters!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +745,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val parameterTypeToNamesMap = HashMap<String, Array<String>>()
|
val parameterTypeToNamesMap = HashMap<String, Array<String>>()
|
||||||
typeCandidates[parameter.typeInfo]!!.forEach { typeCandidate ->
|
typeCandidates[parameter.typeInfo]!!.forEach { typeCandidate ->
|
||||||
val suggestedNames = KotlinNameSuggester.suggestNamesByType(typeCandidate.theType, { true })
|
val suggestedNames = KotlinNameSuggester.suggestNamesByType(typeCandidate.theType, { true })
|
||||||
parameterTypeToNamesMap[typeCandidate.renderedType!!] = suggestedNames.toTypedArray()
|
parameterTypeToNamesMap[typeCandidate.renderedTypes.first()] = suggestedNames.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
// add expression to builder
|
// add expression to builder
|
||||||
@@ -758,9 +758,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
return typeParameters
|
return typeParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceWithLongerName(typeRef: KtTypeReference, theType: KotlinType) {
|
private fun replaceWithLongerName(typeRefs: List<KtTypeReference>, theType: KotlinType) {
|
||||||
val fullyQualifiedReceiverTypeRef = KtPsiFactory(typeRef).createType(theType.renderLong(typeParameterNameMap))
|
val psiFactory = KtPsiFactory(jetFileToEdit.project)
|
||||||
typeRef.replace(fullyQualifiedReceiverTypeRef)
|
val fullyQualifiedReceiverTypeRefs = theType.renderLong(typeParameterNameMap).map { psiFactory.createType(it) }
|
||||||
|
(typeRefs zip fullyQualifiedReceiverTypeRefs).forEach { (shortRef, longRef) -> shortRef.replace(longRef) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformToJavaMemberIfApplicable(declaration: KtNamedDeclaration): Boolean {
|
private fun transformToJavaMemberIfApplicable(declaration: KtNamedDeclaration): Boolean {
|
||||||
@@ -1082,10 +1083,12 @@ internal fun <D : KtNamedDeclaration> placeDeclarationInContainer(
|
|||||||
return declarationInPlace
|
return declarationInPlace
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun KtNamedDeclaration.getReturnTypeReference(): KtTypeReference? {
|
internal fun KtNamedDeclaration.getReturnTypeReference() = getReturnTypeReferences().singleOrNull()
|
||||||
|
|
||||||
|
internal fun KtNamedDeclaration.getReturnTypeReferences(): List<KtTypeReference> {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is KtCallableDeclaration -> typeReference
|
is KtCallableDeclaration -> listOfNotNull(typeReference)
|
||||||
is KtClassOrObject -> superTypeListEntries.firstOrNull()?.typeReference
|
is KtClassOrObject -> superTypeListEntries.mapNotNull { it.typeReference }
|
||||||
else -> throw AssertionError("Unexpected declaration kind: $text")
|
else -> throw AssertionError("Unexpected declaration kind: $text")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -117,7 +117,7 @@ abstract class TypeInfo(val variance: Variance) {
|
|||||||
return Collections.singletonList(callableBuilder.currentFileModule.builtIns.anyType)
|
return Collections.singletonList(callableBuilder.currentFileModule.builtIns.anyType)
|
||||||
}
|
}
|
||||||
val scope = getScopeForTypeApproximation(callableBuilder.config, callableBuilder.placement)
|
val scope = getScopeForTypeApproximation(callableBuilder.config, callableBuilder.placement)
|
||||||
val approximations = getResolvableApproximations(scope, false)
|
val approximations = getResolvableApproximations(scope, false, true)
|
||||||
return when (variance) {
|
return when (variance) {
|
||||||
Variance.IN_VARIANCE -> approximations.toList()
|
Variance.IN_VARIANCE -> approximations.toList()
|
||||||
else -> listOf(approximations.firstOrNull() ?: this)
|
else -> listOf(approximations.firstOrNull() ?: this)
|
||||||
|
|||||||
+6
-3
@@ -104,14 +104,17 @@ internal class ParameterNameExpression(
|
|||||||
internal abstract class TypeExpression(val typeCandidates: List<TypeCandidate>) : Expression() {
|
internal abstract class TypeExpression(val typeCandidates: List<TypeCandidate>) : Expression() {
|
||||||
class ForTypeReference(typeCandidates: List<TypeCandidate>) : TypeExpression(typeCandidates) {
|
class ForTypeReference(typeCandidates: List<TypeCandidate>) : TypeExpression(typeCandidates) {
|
||||||
override val cachedLookupElements: Array<LookupElement> =
|
override val cachedLookupElements: Array<LookupElement> =
|
||||||
typeCandidates.map { LookupElementBuilder.create(it, it.renderedType!!) }.toTypedArray()
|
typeCandidates.map { LookupElementBuilder.create(it, it.renderedTypes.first()) }.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ForDelegationSpecifier(typeCandidates: List<TypeCandidate>) : TypeExpression(typeCandidates) {
|
class ForDelegationSpecifier(typeCandidates: List<TypeCandidate>) : TypeExpression(typeCandidates) {
|
||||||
override val cachedLookupElements: Array<LookupElement> =
|
override val cachedLookupElements: Array<LookupElement> =
|
||||||
typeCandidates.map {
|
typeCandidates.map {
|
||||||
val descriptor = it.theType.constructor.declarationDescriptor as ClassDescriptor
|
val types = it.theType.decomposeIntersection()
|
||||||
val text = it.renderedType!! + if (descriptor.kind == ClassKind.INTERFACE) "" else "()"
|
val text = (types zip it.renderedTypes).joinToString { (type, renderedType) ->
|
||||||
|
val descriptor = type.constructor.declarationDescriptor as ClassDescriptor
|
||||||
|
renderedType + if (descriptor.kind == ClassKind.INTERFACE) "" else "()"
|
||||||
|
}
|
||||||
LookupElementBuilder.create(it, text)
|
LookupElementBuilder.create(it, text)
|
||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -50,7 +50,15 @@ internal operator fun KotlinType.contains(descriptor: ClassifierDescriptor): Boo
|
|||||||
return constructor.declarationDescriptor == descriptor || arguments.any { descriptor in it.type }
|
return constructor.declarationDescriptor == descriptor || arguments.any { descriptor in it.type }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): String {
|
internal fun KotlinType.decomposeIntersection(): List<KotlinType> {
|
||||||
|
(constructor as? IntersectionTypeConstructor)?.let {
|
||||||
|
return it.supertypes.flatMap { it.decomposeIntersection() }
|
||||||
|
}
|
||||||
|
|
||||||
|
return listOf(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.renderSingle(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): String {
|
||||||
val substitution = typeParameterNameMap
|
val substitution = typeParameterNameMap
|
||||||
.mapValues {
|
.mapValues {
|
||||||
val name = Name.identifier(it.value)
|
val name = Name.identifier(it.value)
|
||||||
@@ -77,6 +85,10 @@ private fun KotlinType.render(typeParameterNameMap: Map<TypeParameterDescriptor,
|
|||||||
return renderer.renderType(typeToRender)
|
return renderer.renderType(typeToRender)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): List<String> {
|
||||||
|
return decomposeIntersection().map { it.renderSingle(typeParameterNameMap, fq) }
|
||||||
|
}
|
||||||
|
|
||||||
internal fun KotlinType.renderShort(typeParameterNameMap: Map<TypeParameterDescriptor, String>) = render(typeParameterNameMap, false)
|
internal fun KotlinType.renderShort(typeParameterNameMap: Map<TypeParameterDescriptor, String>) = render(typeParameterNameMap, false)
|
||||||
internal fun KotlinType.renderLong(typeParameterNameMap: Map<TypeParameterDescriptor, String>) = render(typeParameterNameMap, true)
|
internal fun KotlinType.renderLong(typeParameterNameMap: Map<TypeParameterDescriptor, String>) = render(typeParameterNameMap, true)
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -23,6 +23,9 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeIn
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeIntersector
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -58,6 +61,17 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getExpectedUpperBound(element: KtUserType, context: BindingContext): KotlinType? {
|
||||||
|
val projection = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
|
||||||
|
val argumentList = projection.parent as? KtTypeArgumentList ?: return null
|
||||||
|
val index = argumentList.arguments.indexOf(projection)
|
||||||
|
val callElement = argumentList.parent as? KtCallElement ?: return null
|
||||||
|
val resolvedCall = callElement.getResolvedCall(context) ?: return null
|
||||||
|
val typeParameterDescriptor = resolvedCall.candidateDescriptor.typeParameters.getOrNull(index) ?: return null
|
||||||
|
if (typeParameterDescriptor.upperBounds.isEmpty()) return null
|
||||||
|
return TypeIntersector.getUpperBoundsAsType(typeParameterDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): ClassInfo? {
|
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): ClassInfo? {
|
||||||
val name = element.referenceExpression?.getReferencedName() ?: return null
|
val name = element.referenceExpression?.getReferencedName() ?: return null
|
||||||
if (element.parent.parent is KtConstructorCalleeExpression) return null
|
if (element.parent.parent is KtConstructorCalleeExpression) return null
|
||||||
@@ -69,13 +83,14 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
|||||||
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||||
|
|
||||||
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
|
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
|
||||||
|
val expectedUpperBound = getExpectedUpperBound(element, context)
|
||||||
|
|
||||||
val anyType = module.builtIns.anyType
|
val anyType = module.builtIns.anyType
|
||||||
|
|
||||||
return ClassInfo(
|
return ClassInfo(
|
||||||
name = name,
|
name = name,
|
||||||
targetParent = targetParent,
|
targetParent = targetParent,
|
||||||
expectedTypeInfo = TypeInfo.Empty,
|
expectedTypeInfo = expectedUpperBound?.let { TypeInfo.ByType(it, Variance.INVARIANT) } ?: TypeInfo.Empty,
|
||||||
typeArguments = element.typeArgumentsAsTypes.map {
|
typeArguments = element.typeArgumentsAsTypes.map {
|
||||||
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
|
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create class 'Foo'" "true"
|
||||||
|
interface I
|
||||||
|
|
||||||
|
fun <T : I> foo() {}
|
||||||
|
|
||||||
|
fun x() {
|
||||||
|
foo<<caret>Foo>()
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// "Create class 'Foo'" "true"
|
||||||
|
interface I
|
||||||
|
|
||||||
|
fun <T : I> foo() {}
|
||||||
|
|
||||||
|
fun x() {
|
||||||
|
foo<Foo>()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo : I {
|
||||||
|
|
||||||
|
}
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Create class 'Foo'" "true"
|
||||||
|
open class A
|
||||||
|
interface I
|
||||||
|
|
||||||
|
fun <T : I> foo() where T : A {}
|
||||||
|
|
||||||
|
fun x() {
|
||||||
|
foo<<caret>Foo>()
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// "Create class 'Foo'" "true"
|
||||||
|
open class A
|
||||||
|
interface I
|
||||||
|
|
||||||
|
fun <T : I> foo() where T : A {}
|
||||||
|
|
||||||
|
fun x() {
|
||||||
|
foo<Foo>()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo : I, A() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2279,6 +2279,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/traitNotQualifierNoTypeArgs.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/traitNotQualifierNoTypeArgs.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeArgumentWithBound.kt")
|
||||||
|
public void testTypeArgumentWithBound() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/typeArgumentWithBound.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeArgumentWithMultipleBounds.kt")
|
||||||
|
public void testTypeArgumentWithMultipleBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/typeArgumentWithMultipleBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user