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-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
|
||||
|
||||
- [`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.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
|
||||
object EditCommaSeparatedListHelper {
|
||||
fun <TItem: KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem): TItem {
|
||||
return addItemBefore(list, allItems, item, null)
|
||||
@JvmOverloads
|
||||
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)
|
||||
if (allItems.isEmpty()) {
|
||||
if (list.firstChild.node.elementType == KtTokens.LPAR) {
|
||||
if (list.firstChild.node.elementType == prefix) {
|
||||
return list.addAfter(item, list.firstChild) as TItem
|
||||
}
|
||||
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?
|
||||
if (allItems.isEmpty()) {
|
||||
assert(anchor == null)
|
||||
@@ -65,7 +69,7 @@ object EditCommaSeparatedListHelper {
|
||||
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) {
|
||||
|
||||
@@ -90,6 +90,8 @@ class KtPsiFactory(private val project: Project) {
|
||||
return (property.getInitializer() as KtCallExpression).typeArgumentList!!
|
||||
}
|
||||
|
||||
fun createTypeArgument(text: String) = createTypeArguments("<$text>").arguments.first()
|
||||
|
||||
fun createType(type: String): KtTypeReference {
|
||||
val typeReference = createTypeIfPossible(type)
|
||||
if (typeReference == null || typeReference.text != type) {
|
||||
@@ -316,6 +318,10 @@ class KtPsiFactory(private val project: Project) {
|
||||
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 {
|
||||
return (createExpression("{ $text -> 0}") as KtLambdaExpression).functionLiteral.valueParameterList!!
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||
|
||||
@@ -43,7 +44,7 @@ public class KtTypeArgumentList extends KtElementImplStub<KotlinPlaceHolderStub<
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KtTypeProjection addArgument(@NotNull KtTypeProjection argument) {
|
||||
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getArguments(), argument);
|
||||
public KtTypeProjection addArgument(@NotNull KtTypeProjection typeArgument) {
|
||||
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getArguments(), typeArgument, KtTokens.LT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||
|
||||
@@ -37,6 +38,11 @@ public class KtTypeParameterList extends KtElementImplStub<KotlinPlaceHolderStub
|
||||
return getStubOrPsiChildrenAsList(KtStubElementTypes.TYPE_PARAMETER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KtTypeParameter addParameter(@NotNull KtTypeParameter typeParameter) {
|
||||
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getParameters(), typeParameter, KtTokens.LT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitTypeParameterList(this, data);
|
||||
|
||||
@@ -271,4 +271,18 @@ fun dropEnclosingParenthesesIfPossible(expression: KtExpression): KtExpression {
|
||||
val parent = expression.parent as? KtParenthesizedExpression ?: return expression
|
||||
if (!KtPsiUtil.areParenthesesUseless(parent)) return 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.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtCallExpression, editor: Editor?) {
|
||||
val argumentList = createTypeArguments(element, element.analyze())!!
|
||||
|
||||
val callee = element.calleeExpression!!
|
||||
val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList
|
||||
|
||||
ShortenReferences.DEFAULT.process(newArgumentList)
|
||||
}
|
||||
override fun applyTo(element: KtCallExpression, editor: Editor?) = applyTo(element)
|
||||
|
||||
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.calleeExpression == null) return false
|
||||
|
||||
@@ -53,7 +48,18 @@ class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallE
|
||||
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 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.CreateClassFromTypeReferenceActionFactory
|
||||
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.CreateParameterByNamedArgumentActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
|
||||
@@ -413,5 +414,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
REIFIED_TYPE_PARAMETER_NO_INLINE.registerFactory(AddInlineToFunctionWithReifiedFix)
|
||||
|
||||
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 org.jetbrains.kotlin.descriptors.*
|
||||
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.quickfix.DelegatingIntentionAction
|
||||
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.noSubstitutions
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
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.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.util.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind as ClassDescriptorKind
|
||||
|
||||
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'"
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
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.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||
import org.jetbrains.kotlin.idea.quickfix.IntentionActionPriority
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactoryWithDelegate
|
||||
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.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
|
||||
|
||||
object CreateTypeAliasFromTypeReferenceActionFactory : KotlinSingleIntentionActionFactoryWithDelegate<KtUserType, TypeAliasInfo>(IntentionActionPriority.LOW) {
|
||||
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? {
|
||||
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
|
||||
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"
|
||||
// ACTION: Create interface 'A'
|
||||
// ACTION: Create type alias 'A'
|
||||
// ACTION: Create type parameter 'A' in class 'Foo'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: A
|
||||
package p
|
||||
|
||||
Vendored
+1
@@ -6,6 +6,7 @@
|
||||
// ACTION: Create type alias 'A'
|
||||
// ACTION: Convert to block body
|
||||
// ACTION: Remove explicit type specification
|
||||
// ACTION: Create type parameter 'A' in function 'foo'
|
||||
// ERROR: Unresolved reference: A
|
||||
package p
|
||||
|
||||
|
||||
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
// ACTION: Create class 'NotExistent'
|
||||
// ACTION: Create interface 'NotExistent'
|
||||
// ACTION: Create type alias 'NotExistent'
|
||||
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: NotExistent
|
||||
class TPB<X : <caret>NotExistent>
|
||||
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
// ACTION: Create class 'NotExistent'
|
||||
// ACTION: Create interface 'NotExistent'
|
||||
// ACTION: Create type alias 'NotExistent'
|
||||
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: NotExistent
|
||||
class TPB<X> where X : <caret>NotExistent
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// ACTION: Create class 'NotExistent'
|
||||
// ACTION: Create interface 'NotExistent'
|
||||
// ACTION: Create type alias 'NotExistent'
|
||||
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: NotExistent
|
||||
class TPB<X : <caret>NotExistent>
|
||||
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
// ACTION: Create class 'NotExistent'
|
||||
// ACTION: Create interface 'NotExistent'
|
||||
// ACTION: Create type alias 'NotExistent'
|
||||
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: NotExistent
|
||||
class TPB<X> where X : <caret>NotExistent
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// ACTION: Create class 'NotExistent'
|
||||
// ACTION: Create interface 'NotExistent'
|
||||
// ACTION: Create type alias 'NotExistent'
|
||||
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: NotExistent
|
||||
class TPB<X : <caret>NotExistent>
|
||||
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
// ACTION: Create class 'NotExistent'
|
||||
// ACTION: Create interface 'NotExistent'
|
||||
// ACTION: Create type alias 'NotExistent'
|
||||
// ACTION: Create type parameter 'NotExistent' in class 'TPB'
|
||||
// ACTION: Create test
|
||||
// ERROR: Unresolved reference: NotExistent
|
||||
class TPB<X> where X : <caret>NotExistent
|
||||
Vendored
+1
@@ -6,6 +6,7 @@
|
||||
// ACTION: Create type alias 'A'
|
||||
// ACTION: Convert to block body
|
||||
// ACTION: Remove explicit type specification
|
||||
// ACTION: Create type parameter 'A' in function 'foo'
|
||||
// ERROR: Unresolved reference: A
|
||||
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 type alias 'NoSuchType'
|
||||
// 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: 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")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user