Create from Usage: Implement "Create type parameter" quickfix
#KT-11525 Fixed
This commit is contained in:
@@ -101,6 +101,12 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
|||||||
- [`KT-8672`](https://youtrack.jetbrains.com/issue/KT-8672) Rename: Optimize search of parameter references in calls with named arguments
|
- [`KT-8672`](https://youtrack.jetbrains.com/issue/KT-8672) Rename: Optimize search of parameter references in calls with named arguments
|
||||||
- [`KT-9285`](https://youtrack.jetbrains.com/issue/KT-9285) Rename: Optimize search of private class members
|
- [`KT-9285`](https://youtrack.jetbrains.com/issue/KT-9285) Rename: Optimize search of private class members
|
||||||
|
|
||||||
|
#### Intention actions, inspections and quickfixes
|
||||||
|
|
||||||
|
##### New features
|
||||||
|
|
||||||
|
- [`KT-11525`](https://youtrack.jetbrains.com/issue/KT-11525) Implement "Create type parameter" quickfix
|
||||||
|
|
||||||
#### Refactorings
|
#### Refactorings
|
||||||
|
|
||||||
- [`KT-13535`](https://youtrack.jetbrains.com/issue/KT-13535) Pull Up: Remove visibility modifiers on adding 'override'
|
- [`KT-13535`](https://youtrack.jetbrains.com/issue/KT-13535) Pull Up: Remove visibility modifiers on adding 'override'
|
||||||
|
|||||||
@@ -18,18 +18,21 @@ package org.jetbrains.kotlin.psi
|
|||||||
|
|
||||||
import com.intellij.psi.PsiComment
|
import com.intellij.psi.PsiComment
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||||
|
|
||||||
object EditCommaSeparatedListHelper {
|
object EditCommaSeparatedListHelper {
|
||||||
fun <TItem: KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem): TItem {
|
@JvmOverloads
|
||||||
return addItemBefore(list, allItems, item, null)
|
fun <TItem: KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem, prefix: KtToken = KtTokens.LPAR): TItem {
|
||||||
|
return addItemBefore(list, allItems, item, null, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <TItem: KtElement> addItemAfter(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?): TItem {
|
@JvmOverloads
|
||||||
|
fun <TItem: KtElement> addItemAfter(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
|
||||||
assert(anchor == null || anchor.parent == list)
|
assert(anchor == null || anchor.parent == list)
|
||||||
if (allItems.isEmpty()) {
|
if (allItems.isEmpty()) {
|
||||||
if (list.firstChild.node.elementType == KtTokens.LPAR) {
|
if (list.firstChild.node.elementType == prefix) {
|
||||||
return list.addAfter(item, list.firstChild) as TItem
|
return list.addAfter(item, list.firstChild) as TItem
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -49,7 +52,8 @@ object EditCommaSeparatedListHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <TItem: KtElement> addItemBefore(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?): TItem {
|
@JvmOverloads
|
||||||
|
fun <TItem: KtElement> addItemBefore(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
|
||||||
val anchorAfter: TItem?
|
val anchorAfter: TItem?
|
||||||
if (allItems.isEmpty()) {
|
if (allItems.isEmpty()) {
|
||||||
assert(anchor == null)
|
assert(anchor == null)
|
||||||
@@ -65,7 +69,7 @@ object EditCommaSeparatedListHelper {
|
|||||||
anchorAfter = allItems.get(allItems.size - 1)
|
anchorAfter = allItems.get(allItems.size - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addItemAfter(list, allItems, item, anchorAfter)
|
return addItemAfter(list, allItems, item, anchorAfter, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <TItem: KtElement> removeItem(item: TItem) {
|
fun <TItem: KtElement> removeItem(item: TItem) {
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ class KtPsiFactory(private val project: Project) {
|
|||||||
return (property.getInitializer() as KtCallExpression).typeArgumentList!!
|
return (property.getInitializer() as KtCallExpression).typeArgumentList!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createTypeArgument(text: String) = createTypeArguments("<$text>").arguments.first()
|
||||||
|
|
||||||
fun createType(type: String): KtTypeReference {
|
fun createType(type: String): KtTypeReference {
|
||||||
val typeReference = createTypeIfPossible(type)
|
val typeReference = createTypeIfPossible(type)
|
||||||
if (typeReference == null || typeReference.text != type) {
|
if (typeReference == null || typeReference.text != type) {
|
||||||
@@ -316,6 +318,10 @@ class KtPsiFactory(private val project: Project) {
|
|||||||
return createFunction("fun foo$text{}").getValueParameterList()!!
|
return createFunction("fun foo$text{}").getValueParameterList()!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createTypeParameterList(text: String) = createClass("class Foo$text").typeParameterList!!
|
||||||
|
|
||||||
|
fun createTypeParameter(text: String) = createTypeParameterList("<$text>").parameters.first()!!
|
||||||
|
|
||||||
fun createFunctionLiteralParameterList(text: String): KtParameterList {
|
fun createFunctionLiteralParameterList(text: String): KtParameterList {
|
||||||
return (createExpression("{ $text -> 0}") as KtLambdaExpression).functionLiteral.valueParameterList!!
|
return (createExpression("{ $text -> 0}") as KtLambdaExpression).functionLiteral.valueParameterList!!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
|
|||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
|
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ public class KtTypeArgumentList extends KtElementImplStub<KotlinPlaceHolderStub<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public KtTypeProjection addArgument(@NotNull KtTypeProjection argument) {
|
public KtTypeProjection addArgument(@NotNull KtTypeProjection typeArgument) {
|
||||||
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getArguments(), argument);
|
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getArguments(), typeArgument, KtTokens.LT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
|
|||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
|
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||||
|
|
||||||
@@ -37,6 +38,11 @@ public class KtTypeParameterList extends KtElementImplStub<KotlinPlaceHolderStub
|
|||||||
return getStubOrPsiChildrenAsList(KtStubElementTypes.TYPE_PARAMETER);
|
return getStubOrPsiChildrenAsList(KtStubElementTypes.TYPE_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public KtTypeParameter addParameter(@NotNull KtTypeParameter typeParameter) {
|
||||||
|
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getParameters(), typeParameter, KtTokens.LT);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) {
|
public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) {
|
||||||
return visitor.visitTypeParameterList(this, data);
|
return visitor.visitTypeParameterList(this, data);
|
||||||
|
|||||||
@@ -272,3 +272,17 @@ fun dropEnclosingParenthesesIfPossible(expression: KtExpression): KtExpression {
|
|||||||
if (!KtPsiUtil.areParenthesesUseless(parent)) return expression
|
if (!KtPsiUtil.areParenthesesUseless(parent)) return expression
|
||||||
return parent.replaced(expression)
|
return parent.replaced(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KtTypeParameterListOwner.addTypeParameter(typeParameter: KtTypeParameter): KtTypeParameter? {
|
||||||
|
typeParameterList?.let { return it.addParameter(typeParameter) }
|
||||||
|
|
||||||
|
val list = KtPsiFactory(this).createTypeParameterList("<X>")
|
||||||
|
list.parameters[0].replace(typeParameter)
|
||||||
|
val leftAnchor = when (this) {
|
||||||
|
is KtClass -> nameIdentifier ?: getClassOrInterfaceKeyword()
|
||||||
|
is KtNamedFunction -> funKeyword
|
||||||
|
is KtProperty -> valOrVarKeyword
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
|
return (addAfter(list, leftAnchor) as KtTypeParameterList).parameters.first()
|
||||||
|
}
|
||||||
+16
-10
@@ -22,11 +22,13 @@ import com.intellij.openapi.util.TextRange
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallElement
|
||||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
|
|
||||||
class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallExpression>(KtCallExpression::class.java, "Add explicit type arguments"), LowPriorityAction {
|
class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallExpression>(KtCallExpression::class.java, "Add explicit type arguments"), LowPriorityAction {
|
||||||
@@ -34,17 +36,10 @@ class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallE
|
|||||||
return if (isApplicableTo(element, element.analyze())) element.calleeExpression!!.textRange else null
|
return if (isApplicableTo(element, element.analyze())) element.calleeExpression!!.textRange else null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyTo(element: KtCallExpression, editor: Editor?) {
|
override fun applyTo(element: KtCallExpression, editor: Editor?) = applyTo(element)
|
||||||
val argumentList = createTypeArguments(element, element.analyze())!!
|
|
||||||
|
|
||||||
val callee = element.calleeExpression!!
|
|
||||||
val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList
|
|
||||||
|
|
||||||
ShortenReferences.DEFAULT.process(newArgumentList)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun isApplicableTo(element: KtCallExpression, bindingContext: BindingContext): Boolean {
|
fun isApplicableTo(element: KtCallElement, bindingContext: BindingContext = element.analyze(BodyResolveMode.PARTIAL)): Boolean {
|
||||||
if (!element.typeArguments.isEmpty()) return false
|
if (!element.typeArguments.isEmpty()) return false
|
||||||
if (element.calleeExpression == null) return false
|
if (element.calleeExpression == null) return false
|
||||||
|
|
||||||
@@ -53,7 +48,18 @@ class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallE
|
|||||||
return typeArgs.isNotEmpty() && typeArgs.values.none { ErrorUtils.containsErrorType(it) }
|
return typeArgs.isNotEmpty() && typeArgs.values.none { ErrorUtils.containsErrorType(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTypeArguments(element: KtCallExpression, bindingContext: BindingContext): KtTypeArgumentList? {
|
fun applyTo(element: KtCallElement, shortenReferences: Boolean = true) {
|
||||||
|
val argumentList = createTypeArguments(element, element.analyze())!!
|
||||||
|
|
||||||
|
val callee = element.calleeExpression!!
|
||||||
|
val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList
|
||||||
|
|
||||||
|
if (shortenReferences) {
|
||||||
|
ShortenReferences.DEFAULT.process(newArgumentList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTypeArguments(element: KtCallElement, bindingContext: BindingContext): KtTypeArgumentList? {
|
||||||
val resolvedCall = element.getResolvedCall(bindingContext) ?: return null
|
val resolvedCall = element.getResolvedCall(bindingContext) ?: return null
|
||||||
|
|
||||||
val args = resolvedCall.typeArguments
|
val args = resolvedCall.typeArguments
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClas
|
|||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromReferenceExpressionActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromReferenceExpressionActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeAlias.CreateTypeAliasFromTypeReferenceActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeAlias.CreateTypeAliasFromTypeReferenceActionFactory
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterByRefActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateLocalVariableActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateLocalVariableActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
|
||||||
@@ -413,5 +414,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
|||||||
REIFIED_TYPE_PARAMETER_NO_INLINE.registerFactory(AddInlineToFunctionWithReifiedFix)
|
REIFIED_TYPE_PARAMETER_NO_INLINE.registerFactory(AddInlineToFunctionWithReifiedFix)
|
||||||
|
|
||||||
VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION.registerFactory(AddTypeAnnotationToValueParameterFix)
|
VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION.registerFactory(AddTypeAnnotationToValueParameterFix)
|
||||||
|
|
||||||
|
UNRESOLVED_REFERENCE.registerFactory(CreateTypeParameterByRefActionFactory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-5
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.PsiPackage
|
import com.intellij.psi.PsiPackage
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
import org.jetbrains.kotlin.idea.quickfix.DelegatingIntentionAction
|
import org.jetbrains.kotlin.idea.quickfix.DelegatingIntentionAction
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||||
@@ -31,17 +32,18 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.contai
|
|||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.noSubstitutions
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.noSubstitutions
|
||||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||||
import org.jetbrains.kotlin.psi.Call
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
|
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitution
|
||||||
import java.lang.AssertionError
|
import java.lang.AssertionError
|
||||||
|
import java.util.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind as ClassDescriptorKind
|
import org.jetbrains.kotlin.descriptors.ClassKind as ClassDescriptorKind
|
||||||
|
|
||||||
internal fun String.checkClassName(): Boolean = isNotEmpty() && Character.isUpperCase(first())
|
internal fun String.checkClassName(): Boolean = isNotEmpty() && Character.isUpperCase(first())
|
||||||
@@ -130,3 +132,38 @@ internal fun KtSimpleNameExpression.getCreatePackageFixIfApplicable(targetParent
|
|||||||
override fun getText(): String = "Create package '$fullName'"
|
override fun getText(): String = "Create package '$fullName'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class UnsubstitutedTypeConstraintInfo(
|
||||||
|
val typeParameter: TypeParameterDescriptor,
|
||||||
|
private val originalSubstitution: Map<TypeConstructor, TypeProjection>,
|
||||||
|
val upperBound: KotlinType
|
||||||
|
) {
|
||||||
|
fun performSubstitution(vararg substitution: Pair<TypeConstructor, TypeProjection>): TypeConstraintInfo? {
|
||||||
|
val currentSubstitution = LinkedHashMap<TypeConstructor, TypeProjection>().apply {
|
||||||
|
this.putAll(originalSubstitution)
|
||||||
|
this.putAll(substitution)
|
||||||
|
}
|
||||||
|
val substitutedUpperBound = TypeSubstitutor.create(currentSubstitution).substitute(upperBound, Variance.INVARIANT) ?: return null
|
||||||
|
return TypeConstraintInfo(typeParameter, substitutedUpperBound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TypeConstraintInfo(
|
||||||
|
val typeParameter: TypeParameterDescriptor,
|
||||||
|
val upperBound: KotlinType
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getUnsubstitutedTypeConstraintInfo(element: KtTypeElement): UnsubstitutedTypeConstraintInfo? {
|
||||||
|
val context = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val containingTypeArg = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
|
||||||
|
val argumentList = containingTypeArg.parent as? KtTypeArgumentList ?: return null
|
||||||
|
val containingTypeRef = (argumentList.parent as? KtTypeElement)?.parent as? KtTypeReference ?: return null
|
||||||
|
val containingType = containingTypeRef.getAbbreviatedTypeOrType(context) ?: return null
|
||||||
|
val baseType = containingType.constructor.declarationDescriptor?.defaultType ?: return null
|
||||||
|
val typeParameter = containingType.constructor.parameters.getOrNull(argumentList.arguments.indexOf(containingTypeArg))
|
||||||
|
val upperBound = typeParameter?.upperBounds?.singleOrNull() ?: return null
|
||||||
|
val substitution = getTypeSubstitution(baseType, containingType) ?: return null
|
||||||
|
return UnsubstitutedTypeConstraintInfo(typeParameter, substitution, upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTypeConstraintInfo(element: KtTypeElement) = getUnsubstitutedTypeConstraintInfo(element)?.performSubstitution()
|
||||||
|
|||||||
+2
-26
@@ -16,45 +16,21 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeAlias
|
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeAlias
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
|
||||||
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
|
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||||
import org.jetbrains.kotlin.idea.quickfix.IntentionActionPriority
|
import org.jetbrains.kotlin.idea.quickfix.IntentionActionPriority
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactoryWithDelegate
|
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactoryWithDelegate
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.getTypeConstraintInfo
|
||||||
|
import org.jetbrains.kotlin.psi.KtUserType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitution
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.containsError
|
import org.jetbrains.kotlin.types.typeUtil.containsError
|
||||||
|
|
||||||
object CreateTypeAliasFromTypeReferenceActionFactory : KotlinSingleIntentionActionFactoryWithDelegate<KtUserType, TypeAliasInfo>(IntentionActionPriority.LOW) {
|
object CreateTypeAliasFromTypeReferenceActionFactory : KotlinSingleIntentionActionFactoryWithDelegate<KtUserType, TypeAliasInfo>(IntentionActionPriority.LOW) {
|
||||||
override fun getElementOfInterest(diagnostic: Diagnostic) = CreateClassFromTypeReferenceActionFactory.getElementOfInterest(diagnostic)
|
override fun getElementOfInterest(diagnostic: Diagnostic) = CreateClassFromTypeReferenceActionFactory.getElementOfInterest(diagnostic)
|
||||||
|
|
||||||
data class TypeConstraintInfo(val typeParameter: TypeParameterDescriptor, val upperBound: KotlinType)
|
|
||||||
|
|
||||||
private fun getTypeConstraintInfo(element: KtUserType): TypeConstraintInfo? {
|
|
||||||
val context = element.analyze(BodyResolveMode.PARTIAL)
|
|
||||||
val containingTypeArg = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
|
|
||||||
val argumentList = containingTypeArg.parent as? KtTypeArgumentList ?: return null
|
|
||||||
val containingTypeRef = (argumentList.parent as? KtTypeElement)?.parent as? KtTypeReference ?: return null
|
|
||||||
val containingType = containingTypeRef.getAbbreviatedTypeOrType(context) ?: return null
|
|
||||||
val baseType = containingType.constructor.declarationDescriptor?.defaultType ?: return null
|
|
||||||
val typeParameter = containingType.constructor.parameters.getOrNull(argumentList.arguments.indexOf(containingTypeArg))
|
|
||||||
val upperBound = typeParameter?.upperBounds?.singleOrNull() ?: return null
|
|
||||||
val substitution = getTypeSubstitution(baseType, containingType) ?: return null
|
|
||||||
val substitutedUpperBound = TypeSubstitutor.create(substitution).substitute(upperBound, Variance.INVARIANT) ?: return null
|
|
||||||
if (substitutedUpperBound.containsError()) return null
|
|
||||||
return TypeConstraintInfo(typeParameter, substitutedUpperBound)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): TypeAliasInfo? {
|
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): TypeAliasInfo? {
|
||||||
if (element.getParentOfTypeAndBranch<KtUserType>(true) { qualifier } != null) return null
|
if (element.getParentOfTypeAndBranch<KtUserType>(true) { qualifier } != null) return null
|
||||||
|
|
||||||
|
|||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.SmartPsiElementPointer
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionFactoryWithDelegate
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.getUnsubstitutedTypeConstraintInfo
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.introduce.isObjectOrNonInnerClass
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.containsError
|
||||||
|
|
||||||
|
data class CreateTypeParameterData(
|
||||||
|
val name: String,
|
||||||
|
val declaration: KtTypeParameterListOwner,
|
||||||
|
val upperBoundType: KotlinType?,
|
||||||
|
val fakeTypeParameter: TypeParameterDescriptor
|
||||||
|
)
|
||||||
|
|
||||||
|
object CreateTypeParameterByRefActionFactory : KotlinIntentionActionFactoryWithDelegate<KtUserType, CreateTypeParameterData>() {
|
||||||
|
override fun getElementOfInterest(diagnostic: Diagnostic): KtUserType? {
|
||||||
|
val ktUserType = diagnostic.psiElement.getParentOfTypeAndBranch<KtUserType> { referenceExpression } ?: return null
|
||||||
|
if (ktUserType.qualifier != null) return null
|
||||||
|
if (ktUserType.getParentOfTypeAndBranch<KtUserType>(true) { qualifier } != null) return null
|
||||||
|
if (ktUserType.typeArgumentList != null) return null
|
||||||
|
return ktUserType
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): CreateTypeParameterData? {
|
||||||
|
val name = element.referencedName ?: return null
|
||||||
|
val declaration = element.parents.firstOrNull {
|
||||||
|
it is KtProperty || it is KtNamedFunction || it is KtClass
|
||||||
|
} as? KtTypeParameterListOwner ?: return null
|
||||||
|
val containingDescriptor = declaration.resolveToDescriptor()
|
||||||
|
val fakeTypeParameter = createFakeTypeParameterDescriptor(containingDescriptor, name)
|
||||||
|
val upperBoundType = getUnsubstitutedTypeConstraintInfo(element)?.let {
|
||||||
|
it.performSubstitution(it.typeParameter.typeConstructor to TypeProjectionImpl(fakeTypeParameter.defaultType))?.upperBound
|
||||||
|
}
|
||||||
|
if (upperBoundType != null && upperBoundType.containsError()) return null
|
||||||
|
return CreateTypeParameterData(name, declaration, upperBoundType, fakeTypeParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createFixes(
|
||||||
|
originalElementPointer: SmartPsiElementPointer<KtUserType>,
|
||||||
|
diagnostic: Diagnostic,
|
||||||
|
quickFixDataFactory: () -> CreateTypeParameterData?
|
||||||
|
): List<QuickFixWithDelegateFactory> {
|
||||||
|
val ktUserType = originalElementPointer.element ?: return emptyList()
|
||||||
|
val name = ktUserType.referencedName ?: return emptyList()
|
||||||
|
return getPossibleTypeParameterContainers(ktUserType)
|
||||||
|
.filter { it.typeParameters.all { it.name != name } }
|
||||||
|
.map {
|
||||||
|
QuickFixWithDelegateFactory factory@ {
|
||||||
|
val originalElement = originalElementPointer.element ?: return@factory null
|
||||||
|
val data = quickFixDataFactory()?.copy(declaration = it) ?: return@factory null
|
||||||
|
CreateTypeParameterFromUsageFix(originalElement, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createFakeTypeParameterDescriptor(containingDescriptor: DeclarationDescriptor, name: String): TypeParameterDescriptor {
|
||||||
|
return TypeParameterDescriptorImpl
|
||||||
|
.createWithDefaultBound(containingDescriptor, Annotations.EMPTY, false, Variance.INVARIANT, Name.identifier(name), -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPossibleTypeParameterContainers(startFrom: PsiElement): List<KtTypeParameterListOwner> {
|
||||||
|
val stopAt = startFrom.parents.firstOrNull(::isObjectOrNonInnerClass)?.parent
|
||||||
|
return (if (stopAt != null) startFrom.parents.takeWhile { it != stopAt } else startFrom.parents)
|
||||||
|
.filterIsInstance<KtTypeParameterListOwner>()
|
||||||
|
.filter {
|
||||||
|
((it is KtClass && !it.isInterface() && it !is KtEnumEntry) ||
|
||||||
|
it is KtNamedFunction ||
|
||||||
|
(it is KtProperty && !it.isLocal) ||
|
||||||
|
it is KtTypeAlias) && it.nameIdentifier != null
|
||||||
|
}
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter
|
||||||
|
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.ElementDescriptionUtil
|
||||||
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import com.intellij.usageView.UsageViewTypeLocation
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.core.addTypeParameter
|
||||||
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress
|
||||||
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
|
||||||
|
class CreateTypeParameterFromUsageFix(
|
||||||
|
originalElement: KtUserType,
|
||||||
|
private val data: CreateTypeParameterData
|
||||||
|
) : CreateFromUsageFixBase<KtUserType>(originalElement) {
|
||||||
|
override fun getText() = "Create type parameter '${data.name}' in " +
|
||||||
|
ElementDescriptionUtil.getElementDescription(data.declaration, UsageViewTypeLocation.INSTANCE) + " '${data.declaration.name}'"
|
||||||
|
|
||||||
|
override fun startInWriteAction() = false
|
||||||
|
|
||||||
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
|
val declaration = data.declaration
|
||||||
|
val usages = project.runSynchronouslyWithProgress("Searching ${declaration.name}...", true) {
|
||||||
|
runReadAction {
|
||||||
|
ReferencesSearch
|
||||||
|
.search(declaration)
|
||||||
|
.mapNotNull {
|
||||||
|
it.element.getParentOfTypeAndBranch<KtUserType> { referenceExpression } ?:
|
||||||
|
it.element.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
|
||||||
|
}
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
} ?: return
|
||||||
|
|
||||||
|
runWriteAction {
|
||||||
|
val psiFactory = KtPsiFactory(project)
|
||||||
|
|
||||||
|
val elementsToShorten = SmartList<KtElement>()
|
||||||
|
|
||||||
|
val upperBoundType = data.upperBoundType
|
||||||
|
val upperBoundText = if (upperBoundType != null && !upperBoundType.isNullableAny()) {
|
||||||
|
IdeDescriptorRenderers.SOURCE_CODE.renderType(upperBoundType)
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
val upperBound = upperBoundText?.let { psiFactory.createType(it) }
|
||||||
|
val newTypeParameterText = if (upperBound != null) "${data.name} : ${upperBound.text}" else data.name
|
||||||
|
elementsToShorten += declaration.addTypeParameter(psiFactory.createTypeParameter(newTypeParameterText))!!
|
||||||
|
|
||||||
|
val anonymizedTypeParameter = createFakeTypeParameterDescriptor(data.fakeTypeParameter.containingDeclaration, "_")
|
||||||
|
val anonymizedUpperBoundText = upperBoundType?.let {
|
||||||
|
TypeSubstitutor
|
||||||
|
.create(mapOf(data.fakeTypeParameter.typeConstructor to TypeProjectionImpl(anonymizedTypeParameter.defaultType)))
|
||||||
|
.substitute(upperBoundType, Variance.INVARIANT)
|
||||||
|
}?.let {
|
||||||
|
IdeDescriptorRenderers.SOURCE_CODE.renderType(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val anonymizedUpperBoundAsTypeArg = psiFactory.createTypeArgument(anonymizedUpperBoundText ?: "kotlin.Any?")
|
||||||
|
|
||||||
|
val callsToExplicateArguments = SmartList<KtCallElement>()
|
||||||
|
usages.forEach {
|
||||||
|
when (it) {
|
||||||
|
is KtUserType -> {
|
||||||
|
val typeArgumentList = it.typeArgumentList
|
||||||
|
elementsToShorten += if (typeArgumentList != null) {
|
||||||
|
typeArgumentList.addArgument(anonymizedUpperBoundAsTypeArg)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
it.addAfter(
|
||||||
|
psiFactory.createTypeArguments("<${anonymizedUpperBoundAsTypeArg.text}>"),
|
||||||
|
it.referenceExpression!!
|
||||||
|
) as KtTypeArgumentList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KtCallElement -> {
|
||||||
|
if (it.analyze(BodyResolveMode.PARTIAL).diagnostics.forElement(it.calleeExpression!!).any {
|
||||||
|
it.factory in Errors.TYPE_INFERENCE_ERRORS
|
||||||
|
}) {
|
||||||
|
callsToExplicateArguments += it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callsToExplicateArguments.forEach {
|
||||||
|
val typeArgumentList = it.typeArgumentList
|
||||||
|
if (typeArgumentList == null) {
|
||||||
|
InsertExplicitTypeArgumentsIntention.applyTo(it, shortenReferences = false)
|
||||||
|
|
||||||
|
val newTypeArgument = it.typeArguments.lastOrNull()
|
||||||
|
if (anonymizedUpperBoundText != null && newTypeArgument != null && newTypeArgument.text == "kotlin.Any") {
|
||||||
|
newTypeArgument.replaced(anonymizedUpperBoundAsTypeArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
elementsToShorten += it.typeArgumentList
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elementsToShorten += typeArgumentList.addArgument(anonymizedUpperBoundAsTypeArg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortenReferences.DEFAULT.process(elementsToShorten)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -216,3 +216,5 @@ fun KtExpression.mustBeParenthesizedInInitializerPosition(): Boolean {
|
|||||||
if (left?.mustBeParenthesizedInInitializerPosition() ?: false) return true
|
if (left?.mustBeParenthesizedInInitializerPosition() ?: false) return true
|
||||||
return PsiChildRange(left, operationReference).any { (it is PsiWhiteSpace) && it.textContains('\n') }
|
return PsiChildRange(left, operationReference).any { (it is PsiWhiteSpace) && it.textContains('\n') }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isObjectOrNonInnerClass(e: PsiElement): Boolean = e is KtObjectDeclaration || (e is KtClass && !e.isInner())
|
||||||
idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/classDelegatorToSuperclass.kt
Vendored
+1
@@ -1,6 +1,7 @@
|
|||||||
// "Create class 'A'" "false"
|
// "Create class 'A'" "false"
|
||||||
// ACTION: Create interface 'A'
|
// ACTION: Create interface 'A'
|
||||||
// ACTION: Create type alias 'A'
|
// ACTION: Create type alias 'A'
|
||||||
|
// ACTION: Create type parameter 'A' in class 'Foo'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: A
|
// ERROR: Unresolved reference: A
|
||||||
package p
|
package p
|
||||||
|
|||||||
Vendored
+1
@@ -6,6 +6,7 @@
|
|||||||
// ACTION: Create type alias 'A'
|
// ACTION: Create type alias 'A'
|
||||||
// ACTION: Convert to block body
|
// ACTION: Convert to block body
|
||||||
// ACTION: Remove explicit type specification
|
// ACTION: Remove explicit type specification
|
||||||
|
// ACTION: Create type parameter 'A' in function 'foo'
|
||||||
// ERROR: Unresolved reference: A
|
// ERROR: Unresolved reference: A
|
||||||
package p
|
package p
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -2,6 +2,7 @@
|
|||||||
// ACTION: Create class 'NotExistent'
|
// ACTION: Create class 'NotExistent'
|
||||||
// ACTION: Create interface 'NotExistent'
|
// ACTION: Create interface 'NotExistent'
|
||||||
// ACTION: Create type alias 'NotExistent'
|
// ACTION: Create type alias 'NotExistent'
|
||||||
|
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: NotExistent
|
// ERROR: Unresolved reference: NotExistent
|
||||||
class TPB<X : <caret>NotExistent>
|
class TPB<X : <caret>NotExistent>
|
||||||
Vendored
+1
@@ -2,6 +2,7 @@
|
|||||||
// ACTION: Create class 'NotExistent'
|
// ACTION: Create class 'NotExistent'
|
||||||
// ACTION: Create interface 'NotExistent'
|
// ACTION: Create interface 'NotExistent'
|
||||||
// ACTION: Create type alias 'NotExistent'
|
// ACTION: Create type alias 'NotExistent'
|
||||||
|
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: NotExistent
|
// ERROR: Unresolved reference: NotExistent
|
||||||
class TPB<X> where X : <caret>NotExistent
|
class TPB<X> where X : <caret>NotExistent
|
||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// ACTION: Create class 'NotExistent'
|
// ACTION: Create class 'NotExistent'
|
||||||
// ACTION: Create interface 'NotExistent'
|
// ACTION: Create interface 'NotExistent'
|
||||||
// ACTION: Create type alias 'NotExistent'
|
// ACTION: Create type alias 'NotExistent'
|
||||||
|
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: NotExistent
|
// ERROR: Unresolved reference: NotExistent
|
||||||
class TPB<X : <caret>NotExistent>
|
class TPB<X : <caret>NotExistent>
|
||||||
Vendored
+1
@@ -2,6 +2,7 @@
|
|||||||
// ACTION: Create class 'NotExistent'
|
// ACTION: Create class 'NotExistent'
|
||||||
// ACTION: Create interface 'NotExistent'
|
// ACTION: Create interface 'NotExistent'
|
||||||
// ACTION: Create type alias 'NotExistent'
|
// ACTION: Create type alias 'NotExistent'
|
||||||
|
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: NotExistent
|
// ERROR: Unresolved reference: NotExistent
|
||||||
class TPB<X> where X : <caret>NotExistent
|
class TPB<X> where X : <caret>NotExistent
|
||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// ACTION: Create class 'NotExistent'
|
// ACTION: Create class 'NotExistent'
|
||||||
// ACTION: Create interface 'NotExistent'
|
// ACTION: Create interface 'NotExistent'
|
||||||
// ACTION: Create type alias 'NotExistent'
|
// ACTION: Create type alias 'NotExistent'
|
||||||
|
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: NotExistent
|
// ERROR: Unresolved reference: NotExistent
|
||||||
class TPB<X : <caret>NotExistent>
|
class TPB<X : <caret>NotExistent>
|
||||||
Vendored
+1
@@ -2,6 +2,7 @@
|
|||||||
// ACTION: Create class 'NotExistent'
|
// ACTION: Create class 'NotExistent'
|
||||||
// ACTION: Create interface 'NotExistent'
|
// ACTION: Create interface 'NotExistent'
|
||||||
// ACTION: Create type alias 'NotExistent'
|
// ACTION: Create type alias 'NotExistent'
|
||||||
|
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||||
// ACTION: Create test
|
// ACTION: Create test
|
||||||
// ERROR: Unresolved reference: NotExistent
|
// ERROR: Unresolved reference: NotExistent
|
||||||
class TPB<X> where X : <caret>NotExistent
|
class TPB<X> where X : <caret>NotExistent
|
||||||
Vendored
+1
@@ -6,6 +6,7 @@
|
|||||||
// ACTION: Create type alias 'A'
|
// ACTION: Create type alias 'A'
|
||||||
// ACTION: Convert to block body
|
// ACTION: Convert to block body
|
||||||
// ACTION: Remove explicit type specification
|
// ACTION: Remove explicit type specification
|
||||||
|
// ACTION: Create type parameter 'A' in function 'foo'
|
||||||
// ERROR: Unresolved reference: A
|
// ERROR: Unresolved reference: A
|
||||||
package p
|
package p
|
||||||
|
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
open class Foo(x: <caret>X)
|
||||||
|
|
||||||
|
class Bar : Foo(1)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo(1)
|
||||||
|
Foo("2")
|
||||||
|
|
||||||
|
object : Foo("2") {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
open class Foo<X>(x: X)
|
||||||
|
|
||||||
|
class Bar : Foo<Any?>(1)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo(1)
|
||||||
|
Foo("2")
|
||||||
|
|
||||||
|
object : Foo<Any?>("2") {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
// ERROR: Type mismatch: inferred type is A<Int> but A<Any?> was expected
|
||||||
|
class A<T>
|
||||||
|
|
||||||
|
open class Foo(x: A<<caret>X>)
|
||||||
|
|
||||||
|
class Bar : Foo(A())
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo(A())
|
||||||
|
Foo(A<Int>())
|
||||||
|
|
||||||
|
object : Foo(A<Int>()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
// ERROR: Type mismatch: inferred type is A<Int> but A<Any?> was expected
|
||||||
|
class A<T>
|
||||||
|
|
||||||
|
open class Foo<X>(x: A<X>)
|
||||||
|
|
||||||
|
class Bar : Foo<Any?>(A())
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo<Any?>(A())
|
||||||
|
Foo(A<Int>())
|
||||||
|
|
||||||
|
object : Foo<Any?>(A<Int>()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
// ERROR: Type mismatch: inferred type is A<I> but A<List<[ERROR : _]>> was expected
|
||||||
|
class A<T : List<T>>
|
||||||
|
|
||||||
|
interface I : List<I>
|
||||||
|
|
||||||
|
open class Foo(x: A<<caret>X>)
|
||||||
|
|
||||||
|
class Bar : Foo(A())
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo(A())
|
||||||
|
Foo(A<I>())
|
||||||
|
|
||||||
|
object : Foo(A<I>()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
// ERROR: Type mismatch: inferred type is A<I> but A<List<[ERROR : _]>> was expected
|
||||||
|
class A<T : List<T>>
|
||||||
|
|
||||||
|
interface I : List<I>
|
||||||
|
|
||||||
|
open class Foo<X : List<X>>(x: A<X>)
|
||||||
|
|
||||||
|
class Bar : Foo<List<_>>(A())
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo<List<_>>(A())
|
||||||
|
Foo(A<I>())
|
||||||
|
|
||||||
|
object : Foo<List<_>>(A<I>()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
class A<T : List<Int>>
|
||||||
|
|
||||||
|
open class Foo(x: A<<caret>X>)
|
||||||
|
|
||||||
|
class Bar : Foo(A())
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo(A())
|
||||||
|
Foo(A<List<Int>>())
|
||||||
|
|
||||||
|
object : Foo(A<List<Int>>()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// "Create type parameter 'X' in class 'Foo'" "true"
|
||||||
|
class A<T : List<Int>>
|
||||||
|
|
||||||
|
open class Foo<X : List<Int>>(x: A<X>)
|
||||||
|
|
||||||
|
class Bar : Foo<List<Int>>(A())
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo<List<Int>>(A())
|
||||||
|
Foo(A<List<Int>>())
|
||||||
|
|
||||||
|
object : Foo<List<Int>>(A<List<Int>>()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
fun foo(x: <caret>X) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1)
|
||||||
|
foo("2")
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
fun <X> foo(x: X) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1)
|
||||||
|
foo("2")
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
class A<T>
|
||||||
|
|
||||||
|
fun foo(x: A<<caret>X>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(A())
|
||||||
|
foo(A<Int>())
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
class A<T>
|
||||||
|
|
||||||
|
fun <X> foo(x: A<X>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo<Any?>(A())
|
||||||
|
foo(A<Int>())
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
class A<T : List<T>>
|
||||||
|
|
||||||
|
interface I : List<I>
|
||||||
|
|
||||||
|
fun foo(x: A<<caret>X>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(A())
|
||||||
|
foo(A<I>())
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
// ERROR: Unresolved reference: _
|
||||||
|
class A<T : List<T>>
|
||||||
|
|
||||||
|
interface I : List<I>
|
||||||
|
|
||||||
|
fun <X : List<X>> foo(x: A<X>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo<List<_>>(A())
|
||||||
|
foo(A<I>())
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
class A<T : List<Int>>
|
||||||
|
|
||||||
|
fun foo(x: A<<caret>X>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(A())
|
||||||
|
foo(A<List<Int>>())
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create type parameter 'X' in function 'foo'" "true"
|
||||||
|
class A<T : List<Int>>
|
||||||
|
|
||||||
|
fun <X : List<Int>> foo(x: A<X>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo<List<Int>>(A())
|
||||||
|
foo(A<List<Int>>())
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// "Create type parameter 'X'" "false"
|
||||||
|
// ACTION: Create annotation 'X'
|
||||||
|
// ACTION: Create class 'X'
|
||||||
|
// ACTION: Create enum 'X'
|
||||||
|
// ACTION: Create interface 'X'
|
||||||
|
// ACTION: Create type alias 'X'
|
||||||
|
// ERROR: Unresolved reference: X
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun foo(x: A.<caret>X) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// "Create type parameter 'X'" "false"
|
||||||
|
// ACTION: Create class 'X'
|
||||||
|
// ACTION: Create enum 'X'
|
||||||
|
// ACTION: Create interface 'X'
|
||||||
|
// ACTION: Create object 'X'
|
||||||
|
// ERROR: Unresolved reference: X
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun foo(x: <caret>X.Y) {
|
||||||
|
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create type parameter 'X'" "false"
|
||||||
|
// ACTION: Create class 'X'
|
||||||
|
// ACTION: Create interface 'X'
|
||||||
|
// ACTION: Create type alias 'X'
|
||||||
|
// ERROR: Unresolved reference: X
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun foo(x: <caret>X<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
+1
@@ -5,6 +5,7 @@
|
|||||||
// ACTION: Create interface 'NoSuchType'
|
// ACTION: Create interface 'NoSuchType'
|
||||||
// ACTION: Create type alias 'NoSuchType'
|
// ACTION: Create type alias 'NoSuchType'
|
||||||
// ACTION: Remove explicit lambda parameter types (may break code)
|
// ACTION: Remove explicit lambda parameter types (may break code)
|
||||||
|
// ACTION: Create type parameter 'NoSuchType' in function 'foo'
|
||||||
// ERROR: Type mismatch: inferred type is ([ERROR : NoSuchType]) -> Int but Int was expected
|
// ERROR: Type mismatch: inferred type is ([ERROR : NoSuchType]) -> Int but Int was expected
|
||||||
// ERROR: Unresolved reference: NoSuchType
|
// ERROR: Unresolved reference: NoSuchType
|
||||||
|
|
||||||
|
|||||||
@@ -3050,6 +3050,81 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class CreateTypeParameter extends AbstractQuickFixTest {
|
||||||
|
public void testAllFilesPresentInCreateTypeParameter() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createTypeParameter"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classNoExplication.kt")
|
||||||
|
public void testClassNoExplication() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/classNoExplication.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classWithExplication.kt")
|
||||||
|
public void testClassWithExplication() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/classWithExplication.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classWithExplicationAndRecursiveUpperBound.kt")
|
||||||
|
public void testClassWithExplicationAndRecursiveUpperBound() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/classWithExplicationAndRecursiveUpperBound.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classWithExplicationAndUpperBound.kt")
|
||||||
|
public void testClassWithExplicationAndUpperBound() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/classWithExplicationAndUpperBound.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionNoExplication.kt")
|
||||||
|
public void testFunctionNoExplication() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/functionNoExplication.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionWithExplication.kt")
|
||||||
|
public void testFunctionWithExplication() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/functionWithExplication.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionWithExplicationAndRecursiveUpperBound.kt")
|
||||||
|
public void testFunctionWithExplicationAndRecursiveUpperBound() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/functionWithExplicationAndRecursiveUpperBound.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionWithExplicationAndUpperBound.kt")
|
||||||
|
public void testFunctionWithExplicationAndUpperBound() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/functionWithExplicationAndUpperBound.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("qualifiedType.kt")
|
||||||
|
public void testQualifiedType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/qualifiedType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeQualifier.kt")
|
||||||
|
public void testTypeQualifier() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/typeQualifier.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withTypeArguments.kt")
|
||||||
|
public void testWithTypeArguments() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeParameter/withTypeArguments.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createVariable")
|
@TestMetadata("idea/testData/quickfix/createFromUsage/createVariable")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user