Create from Usage: Implement "Create type alias" quickfix

#KT-12904 Fixed
This commit is contained in:
Alexey Sedunov
2016-07-20 14:34:49 +03:00
parent 17edbac72b
commit 6a2edabbd4
50 changed files with 555 additions and 101 deletions
+1
View File
@@ -10,6 +10,7 @@
###### New features
- [`KT-12903`](https://youtrack.jetbrains.com/issue/KT-12903) Implement "Inline type alias" refactoring
- [`KT-12902`](https://youtrack.jetbrains.com/issue/KT-12902) Implement "Introduce type alias" refactoring
- [`KT-12904`](https://youtrack.jetbrains.com/issue/KT-12904) Implement "Create type alias from usage" quick fix
###### Issues fixed
- [`KT-13383`](https://youtrack.jetbrains.com/issue/KT-13383), [`KT-13379`](https://youtrack.jetbrains.com/issue/KT-13379) Override/Implement Members: Do not make return type non-nullable if base return type is explicitly nullable
@@ -106,9 +106,12 @@ class KtPsiFactory(private val project: Project) {
}
fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
return createTypeAlias(name, typeParameters, "X").apply { getTypeReference()!!.replace(createType(typeElement)) }
}
fun createTypeAlias(name: String, typeParameters: List<String>, body: String): KtTypeAlias {
val typeParametersText = if (typeParameters.isNotEmpty()) typeParameters.joinToString(prefix = "<", postfix = ">") else ""
return createDeclaration<KtTypeAlias>("typealias $name$typeParametersText = X")
.apply { getTypeReference()!!.replace(createType(typeElement)) }
return createDeclaration<KtTypeAlias>("typealias $name$typeParametersText = $body")
}
fun createStar(): PsiElement {
@@ -95,4 +95,7 @@ fun KtExpression.isUnreachableCode(context: BindingContext): Boolean = context[B
fun KtExpression.getReferenceTargets(context: BindingContext): Collection<DeclarationDescriptor> {
val targetDescriptor = if (this is KtReferenceExpression) context[BindingContext.REFERENCE_TARGET, this] else null
return targetDescriptor?.let { listOf(it) } ?: context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this].orEmpty()
}
}
fun KtTypeReference.getAbbreviatedTypeOrType(context: BindingContext) =
context[BindingContext.ABBREVIATED_TYPE, this] ?: context[BindingContext.TYPE, this]
@@ -119,7 +119,7 @@ class NewDeclarationNameValidator(
if (this is KtCallableDeclaration && receiverTypeReference != null) return false
return when(target) {
Target.VARIABLES -> this is KtVariableDeclaration
Target.FUNCTIONS_AND_CLASSES -> this is KtNamedFunction || this is KtClassOrObject
Target.FUNCTIONS_AND_CLASSES -> this is KtNamedFunction || this is KtClassOrObject || this is KtTypeAlias
}
}
}
@@ -47,7 +47,7 @@ abstract class KotlinSingleIntentionActionFactoryWithDelegate<E : KtElement, D :
}
abstract class KotlinIntentionActionFactoryWithDelegate<E : KtElement, D : Any> : KotlinIntentionActionsFactory() {
protected abstract fun getElementOfInterest(diagnostic: Diagnostic): E?
abstract fun getElementOfInterest(diagnostic: Diagnostic): E?
protected abstract fun createFixes(
originalElementPointer: SmartPsiElementPointer<E>,
@@ -55,7 +55,7 @@ abstract class KotlinIntentionActionFactoryWithDelegate<E : KtElement, D : Any>
quickFixDataFactory: () -> D?
): List<QuickFixWithDelegateFactory>
protected abstract fun extractFixData(element: E, diagnostic: Diagnostic): D?
abstract fun extractFixData(element: E, diagnostic: Diagnostic): D?
override final fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val diagnosticMessage = DefaultErrorMessages.render(diagnostic)
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClas
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromConstructorCallActionFactory
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.createVariable.CreateLocalVariableActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
@@ -340,8 +341,11 @@ class QuickFixRegistrar : QuickFixContributor {
UNRESOLVED_REFERENCE.registerFactory(CreateClassFromTypeReferenceActionFactory,
CreateClassFromReferenceExpressionActionFactory,
CreateClassFromCallWithConstructorCalleeActionFactory,
PlatformUnresolvedProvider)
CreateClassFromCallWithConstructorCalleeActionFactory)
UNRESOLVED_REFERENCE.registerFactory(CreateTypeAliasFromTypeReferenceActionFactory)
UNRESOLVED_REFERENCE.registerFactory(PlatformUnresolvedProvider)
PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.registerFactory(InsertDelegationCallQuickfix.InsertThisDelegationCallFactory)
@@ -520,86 +520,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
return assignmentToReplace.replace(declaration) as KtCallableDeclaration
}
val newLine = psiFactory.createNewLine()
fun calcNecessaryEmptyLines(decl: KtDeclaration, after: Boolean): Int {
var lineBreaksPresent: Int = 0
var neighbor: PsiElement? = null
siblingsLoop@
for (sibling in decl.siblings(forward = after, withItself = false)) {
when (sibling) {
is PsiWhiteSpace -> lineBreaksPresent += (sibling.text ?: "").count { it == '\n' }
else -> {
neighbor = sibling
break@siblingsLoop
}
}
}
val neighborType = neighbor?.node?.elementType
val lineBreaksNeeded = when {
neighborType == KtTokens.LBRACE || neighborType == KtTokens.RBRACE -> 1
neighbor is KtDeclaration && (neighbor !is KtProperty || decl !is KtProperty) -> 2
else -> 1
}
return Math.max(lineBreaksNeeded - lineBreaksPresent, 0)
}
val actualContainer = (containingElement as? KtClassOrObject)?.getOrCreateBody() ?: containingElement
fun addNextToOriginalElementContainer(addBefore: Boolean): KtNamedDeclaration {
val sibling = config.originalElement.parentsWithSelf.first { it.parent == actualContainer }
return if (addBefore) {
actualContainer.addBefore(declaration, sibling)
}
else {
actualContainer.addAfter(declaration, sibling)
} as KtNamedDeclaration
}
val declarationInPlace = when {
actualContainer.isAncestor(config.originalElement, true) -> {
val insertToBlock = containingElement is KtBlockExpression
if (insertToBlock) {
val parent = containingElement.parent
if (parent is KtFunctionLiteral) {
if (!parent.isMultiLine()) {
parent.addBefore(newLine, containingElement)
parent.addAfter(newLine, containingElement)
}
}
}
addNextToOriginalElementContainer(insertToBlock || (declaration is KtProperty && actualContainer !is KtFile))
}
containingElement is KtFile -> containingElement.add(declaration) as KtNamedDeclaration
containingElement is PsiClass -> {
if (declaration is KtSecondaryConstructor) {
val wrappingClass = psiFactory.createClass("class ${containingElement.name} {\n}")
addDeclarationToClassOrObject(wrappingClass, declaration)
(jetFileToEdit.add(wrappingClass) as KtClass).declarations.first() as KtNamedDeclaration
}
else {
jetFileToEdit.add(declaration) as KtNamedDeclaration
}
}
containingElement is KtClassOrObject -> {
insertMember(null, containingElement, declaration, containingElement.declarations.lastOrNull())
}
else -> throw AssertionError("Invalid containing element: ${containingElement.text}")
}
val parent = declarationInPlace.parent
calcNecessaryEmptyLines(declarationInPlace, false).let {
if (it > 0) parent.addBefore(psiFactory.createNewLine(it), declarationInPlace)
}
calcNecessaryEmptyLines(declarationInPlace, true).let {
if (it > 0) parent.addAfter(psiFactory.createNewLine(it), declarationInPlace)
}
val declarationInPlace = placeDeclarationInContainer(declaration, containingElement, config.originalElement, jetFileToEdit)
if (declarationInPlace is KtSecondaryConstructor) {
val containingClass = declarationInPlace.containingClassOrObject!!
@@ -615,19 +536,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
}
}
private fun addDeclarationToClassOrObject(classOrObject: KtClassOrObject,
declaration: KtNamedDeclaration): KtNamedDeclaration {
val classBody = classOrObject.getOrCreateBody()
return if (declaration is KtNamedFunction) {
val anchor = PsiTreeUtil.skipSiblingsBackward(
classBody.rBrace ?: classBody.lastChild!!,
PsiWhiteSpace::class.java
)
classBody.addAfter(declaration, anchor) as KtNamedDeclaration
}
else classBody.addAfter(declaration, classBody.lBrace!!) as KtNamedDeclaration
}
private fun getTypeParameterRenames(scope: HierarchicalScope): Map<TypeParameterDescriptor, String> {
val allTypeParametersNotInScope = LinkedHashSet<TypeParameterDescriptor>()
@@ -1047,6 +955,114 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
}
}
// TODO: Simplify and use formatter as much as possible
@Suppress("UNCHECKED_CAST")
internal fun <D : KtNamedDeclaration> placeDeclarationInContainer(
declaration: D,
container: PsiElement,
anchor: PsiElement,
fileToEdit: KtFile = container.containingFile as KtFile
): D {
val psiFactory = KtPsiFactory(container)
val newLine = psiFactory.createNewLine()
fun calcNecessaryEmptyLines(decl: KtDeclaration, after: Boolean): Int {
var lineBreaksPresent: Int = 0
var neighbor: PsiElement? = null
siblingsLoop@
for (sibling in decl.siblings(forward = after, withItself = false)) {
when (sibling) {
is PsiWhiteSpace -> lineBreaksPresent += (sibling.text ?: "").count { it == '\n' }
else -> {
neighbor = sibling
break@siblingsLoop
}
}
}
val neighborType = neighbor?.node?.elementType
val lineBreaksNeeded = when {
neighborType == KtTokens.LBRACE || neighborType == KtTokens.RBRACE -> 1
neighbor is KtDeclaration && (neighbor !is KtProperty || decl !is KtProperty) -> 2
else -> 1
}
return Math.max(lineBreaksNeeded - lineBreaksPresent, 0)
}
val actualContainer = (container as? KtClassOrObject)?.getOrCreateBody() ?: container
fun addDeclarationToClassOrObject(classOrObject: KtClassOrObject,
declaration: KtNamedDeclaration): KtNamedDeclaration {
val classBody = classOrObject.getOrCreateBody()
return if (declaration is KtNamedFunction) {
val neighbor = PsiTreeUtil.skipSiblingsBackward(
classBody.rBrace ?: classBody.lastChild!!,
PsiWhiteSpace::class.java
)
classBody.addAfter(declaration, neighbor) as KtNamedDeclaration
}
else classBody.addAfter(declaration, classBody.lBrace!!) as KtNamedDeclaration
}
fun addNextToOriginalElementContainer(addBefore: Boolean): D {
val sibling = anchor.parentsWithSelf.first { it.parent == actualContainer }
return if (addBefore) {
actualContainer.addBefore(declaration, sibling)
}
else {
actualContainer.addAfter(declaration, sibling)
} as D
}
val declarationInPlace = when {
actualContainer.isAncestor(anchor, true) -> {
val insertToBlock = container is KtBlockExpression
if (insertToBlock) {
val parent = container.parent
if (parent is KtFunctionLiteral) {
if (!parent.isMultiLine()) {
parent.addBefore(newLine, container)
parent.addAfter(newLine, container)
}
}
}
addNextToOriginalElementContainer(insertToBlock
|| (declaration is KtProperty && actualContainer !is KtFile)
|| declaration is KtTypeAlias)
}
container is KtFile -> container.add(declaration) as D
container is PsiClass -> {
if (declaration is KtSecondaryConstructor) {
val wrappingClass = psiFactory.createClass("class ${container.name} {\n}")
addDeclarationToClassOrObject(wrappingClass, declaration)
(fileToEdit.add(wrappingClass) as KtClass).declarations.first() as D
}
else {
fileToEdit.add(declaration) as D
}
}
container is KtClassOrObject -> {
insertMember(null, container, declaration, container.declarations.lastOrNull())
}
else -> throw AssertionError("Invalid containing element: ${container.text}")
}
val parent = declarationInPlace.parent
calcNecessaryEmptyLines(declarationInPlace, false).let {
if (it > 0) parent.addBefore(psiFactory.createNewLine(it), declarationInPlace)
}
calcNecessaryEmptyLines(declarationInPlace, true).let {
if (it > 0) parent.addAfter(psiFactory.createNewLine(it), declarationInPlace)
}
return declarationInPlace
}
internal fun KtNamedDeclaration.getReturnTypeReference(): KtTypeReference? {
return when (this) {
is KtCallableDeclaration -> typeReference
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
import com.intellij.refactoring.psi.SearchUtils
import org.jetbrains.kotlin.cfg.pseudocode.*
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
@@ -46,6 +47,10 @@ internal operator fun KotlinType.contains(inner: KotlinType): Boolean {
return KotlinTypeChecker.DEFAULT.equalTypes(this, inner) || arguments.any { inner in it.type }
}
internal operator fun KotlinType.contains(descriptor: ClassifierDescriptor): Boolean {
return constructor.declarationDescriptor == descriptor || arguments.any { descriptor in it.type }
}
private fun KotlinType.render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): String {
val substitution = typeParameterNameMap
.mapValues {
@@ -0,0 +1,74 @@
/*
* 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.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.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
val classInfo = CreateClassFromTypeReferenceActionFactory.extractFixData(element, diagnostic) ?: return null
val expectedType = getTypeConstraintInfo(element)?.upperBound
if (expectedType != null && expectedType.containsError()) return null
val validator = CollectingNameValidator(
filter = NewDeclarationNameValidator(classInfo.targetParent, null, NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES)
)
val typeParameterNames = KotlinNameSuggester.suggestNamesForTypeParameters(classInfo.typeArguments.size, validator)
return TypeAliasInfo(classInfo.name, classInfo.targetParent, typeParameterNames, expectedType)
}
override fun createFix(originalElement: KtUserType, data: TypeAliasInfo) = CreateTypeAliasFromUsageFix(originalElement, data)
}
@@ -0,0 +1,70 @@
/*
* 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.createTypeAlias
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInsight.template.TemplateBuilderImpl
import com.intellij.codeInsight.template.impl.ConstantNode
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.placeDeclarationInContainer
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.types.KotlinType
class TypeAliasInfo(
val name: String,
val targetParent: PsiElement,
val typeParameterNames: List<String>,
val expectedType: KotlinType?
)
class CreateTypeAliasFromUsageFix<E : KtElement>(
element: E,
val aliasInfo: TypeAliasInfo
) : CreateFromUsageFixBase<E>(element), LowPriorityAction {
override fun getText() = "Create type alias '${aliasInfo.name}'"
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
if (editor == null) return
val typeAliasProto = KtPsiFactory(project).createTypeAlias(aliasInfo.name, aliasInfo.typeParameterNames, "Dummy")
val typeAlias = placeDeclarationInContainer(typeAliasProto, aliasInfo.targetParent, element)
if (!ApplicationManager.getApplication().isUnitTestMode) {
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
val aliasBody = typeAlias.getTypeReference()!!
with(TemplateBuilderImpl(typeAlias)) {
for ((typeParameter, typeParameterName) in (typeAlias.typeParameters zip aliasInfo.typeParameterNames)) {
replaceElement(typeParameter, ConstantNode(typeParameterName))
}
val defaultBodyText = aliasInfo.expectedType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "Any"
replaceElement(aliasBody, ConstantNode(defaultBodyText))
run(editor, true)
}
}
}
}
@@ -1,5 +1,6 @@
// "class org.jetbrains.kotlin.idea.quickfix.ImportFix" "false"
// ACTION: Create interface 'SomeTest'
// ACTION: Create type alias 'SomeTest'
// ERROR: Unresolved reference: SomeTest
package testing
@@ -1,5 +1,6 @@
// "Create class 'A'" "false"
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Create test
// ERROR: Unresolved reference: A
package p
@@ -1,6 +1,7 @@
// "Create annotation 'A'" "false"
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
@@ -5,5 +5,6 @@
// ACTION: Create class 'A'
// ACTION: Create enum 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ERROR: Unresolved reference: A
internal fun foo(): J.<caret>A = throw Throwable("")
@@ -3,6 +3,7 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
@@ -1,6 +1,7 @@
// "Create enum 'A'" "false"
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
@@ -1,6 +1,7 @@
// "Create annotation 'NotExistent'" "false"
// ACTION: Create class 'NotExistent'
// ACTION: Create interface 'NotExistent'
// ACTION: Create type alias 'NotExistent'
// ACTION: Create test
// ERROR: Unresolved reference: NotExistent
class TPB<X : <caret>NotExistent>
@@ -1,6 +1,7 @@
// "Create annotation 'NotExistent'" "false"
// ACTION: Create class 'NotExistent'
// ACTION: Create interface 'NotExistent'
// ACTION: Create type alias 'NotExistent'
// ACTION: Create test
// ERROR: Unresolved reference: NotExistent
class TPB<X> where X : <caret>NotExistent
@@ -1,6 +1,7 @@
// "Create enum 'NotExistent'" "false"
// ACTION: Create class 'NotExistent'
// ACTION: Create interface 'NotExistent'
// ACTION: Create type alias 'NotExistent'
// ACTION: Create test
// ERROR: Unresolved reference: NotExistent
class TPB<X : <caret>NotExistent>
@@ -1,6 +1,7 @@
// "Create enum 'NotExistent'" "false"
// ACTION: Create class 'NotExistent'
// ACTION: Create interface 'NotExistent'
// ACTION: Create type alias 'NotExistent'
// ACTION: Create test
// ERROR: Unresolved reference: NotExistent
class TPB<X> where X : <caret>NotExistent
@@ -1,6 +1,7 @@
// "Create object 'NotExistent'" "false"
// ACTION: Create class 'NotExistent'
// ACTION: Create interface 'NotExistent'
// ACTION: Create type alias 'NotExistent'
// ACTION: Create test
// ERROR: Unresolved reference: NotExistent
class TPB<X : <caret>NotExistent>
@@ -1,6 +1,7 @@
// "Create object 'NotExistent'" "false"
// ACTION: Create class 'NotExistent'
// ACTION: Create interface 'NotExistent'
// ACTION: Create type alias 'NotExistent'
// ACTION: Create test
// ERROR: Unresolved reference: NotExistent
class TPB<X> where X : <caret>NotExistent
@@ -3,6 +3,7 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
@@ -1,6 +1,7 @@
// "Create object 'A'" "false"
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): p.<caret>A = throw Throwable("")
@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
typealias A = Dummy
fun foo(): p.A = throw Throwable("")
@@ -0,0 +1,7 @@
// "Create type alias 'A'" "false"
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
internal fun foo(): Int.<caret>A = throw Throwable("")
@@ -0,0 +1,6 @@
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.X>() {
typealias X = Dummy
}
@@ -0,0 +1,5 @@
// DISABLED: See KT-13596
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.<caret>X>()
@@ -0,0 +1,7 @@
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.X>() {
typealias X = Dummy
}
@@ -0,0 +1,7 @@
// DISABLED: See KT-13596
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.<caret>X>() {
}
@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): <caret>A = throw Throwable("")
@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
typealias A = Dummy
fun foo(): A = throw Throwable("")
@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): <caret>A<*, String> = throw Throwable("")
@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
typealias A<T, U> = Dummy
fun foo(): A<*, String> = throw Throwable("")
@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): <caret>A<Int, String> = throw Throwable("")
@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
typealias A<T, U> = Dummy
fun foo(): A<Int, String> = throw Throwable("")
@@ -0,0 +1,11 @@
// "Create type alias 'A'" "false"
// ACTION: Convert to block body
// ACTION: Create class 'A'
// ACTION: Create enum 'A'
// ACTION: Create interface 'A'
// ACTION: Create object 'A'
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
fun foo(): <caret>A.B = throw Throwable("")
@@ -0,0 +1,11 @@
// "Create type alias 'X'" "false"
// ACTION: Create class 'X'
// ACTION: Create interface 'X'
// ERROR: Unresolved reference: X
package p
open class A<T : List<T>>
fun foo(a: A<<caret>X<Int>>) {
}
@@ -0,0 +1,11 @@
// "Create type alias 'X'" "false"
// ACTION: Create class 'X'
// ACTION: Create interface 'X'
// ERROR: Unresolved reference: X
package p
open class A<T, U : Map<T, U>>
fun foo(a: A<List<String>, <caret>X<Int>>) {
}
@@ -0,0 +1,9 @@
// "Create type alias 'X'" "true"
// ERROR: Unresolved reference: Dummy
package p
open class A<T, U : List<T>>
fun foo(a: A<List<String>, <caret>X<Int>>) {
}
@@ -0,0 +1,11 @@
// "Create type alias 'X'" "true"
// ERROR: Unresolved reference: Dummy
package p
open class A<T, U : List<T>>
typealias X<T> = Dummy
fun foo(a: A<List<String>, X<Int>>) {
}
@@ -0,0 +1,9 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T {
}
fun foo(): T.<caret>A = throw Throwable("")
@@ -0,0 +1,10 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T {
typealias A = Dummy
}
fun foo(): T.A = throw Throwable("")
@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T
fun foo(): T.<caret>A = throw Throwable("")
@@ -0,0 +1,9 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T {
typealias A = Dummy
}
fun foo(): T.A = throw Throwable("")
@@ -3,6 +3,7 @@
// ACTION: Create class 'X'
// ACTION: Create enum 'X'
// ACTION: Create interface 'X'
// ACTION: Create type alias 'X'
// ERROR: Unresolved reference: X
// ERROR: Unresolved reference: X
class A {
@@ -3,6 +3,7 @@
// ACTION: Create class 'NoSuchType'
// ACTION: Create enum 'NoSuchType'
// ACTION: Create interface 'NoSuchType'
// ACTION: Create type alias 'NoSuchType'
// ACTION: Remove explicit lambda parameter types (may break code)
// ERROR: Type mismatch: inferred type is ([ERROR : NoSuchType]) -> Int but Int was expected
// ERROR: Unresolved reference: NoSuchType
@@ -1108,6 +1108,16 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
}
}
@TestMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CreateTypeAlias extends AbstractQuickFixMultiFileTest {
public void testAllFilesPresentInCreateTypeAlias() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createTypeAlias"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), true);
}
}
@TestMetadata("idea/testData/quickfix/createFromUsage/createVariable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2966,6 +2966,90 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
}
}
@TestMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CreateTypeAlias extends AbstractQuickFixTest {
public void testAllFilesPresentInCreateTypeAlias() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createTypeAlias"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeReference extends AbstractQuickFixTest {
public void testAllFilesPresentInTypeReference() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("currentPackageReceiver.kt")
public void testCurrentPackageReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/currentPackageReceiver.kt");
doTest(fileName);
}
@TestMetadata("libTypeReceiver.kt")
public void testLibTypeReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/libTypeReceiver.kt");
doTest(fileName);
}
@TestMetadata("notQualifierNoTypeArgs.kt")
public void testNotQualifierNoTypeArgs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/notQualifierNoTypeArgs.kt");
doTest(fileName);
}
@TestMetadata("notQualifierWithStarProjection.kt")
public void testNotQualifierWithStarProjection() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/notQualifierWithStarProjection.kt");
doTest(fileName);
}
@TestMetadata("notQualifierWithTypeArgs.kt")
public void testNotQualifierWithTypeArgs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/notQualifierWithTypeArgs.kt");
doTest(fileName);
}
@TestMetadata("qualifierNoTypeArgs.kt")
public void testQualifierNoTypeArgs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/qualifierNoTypeArgs.kt");
doTest(fileName);
}
@TestMetadata("recursiveTypeBound1.kt")
public void testRecursiveTypeBound1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/recursiveTypeBound1.kt");
doTest(fileName);
}
@TestMetadata("recursiveTypeBound2.kt")
public void testRecursiveTypeBound2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/recursiveTypeBound2.kt");
doTest(fileName);
}
@TestMetadata("typeParameterDependency.kt")
public void testTypeParameterDependency() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/typeParameterDependency.kt");
doTest(fileName);
}
@TestMetadata("userTypeReceiver.kt")
public void testUserTypeReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/userTypeReceiver.kt");
doTest(fileName);
}
@TestMetadata("userTypeReceiverNoBody.kt")
public void testUserTypeReceiverNoBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createTypeAlias/typeReference/userTypeReceiverNoBody.kt");
doTest(fileName);
}
}
}
@TestMetadata("idea/testData/quickfix/createFromUsage/createVariable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)