Add intention to introduce import alias

#KT-16118 Fixed
 #KT-30007 Fixed
This commit is contained in:
Dmitry Gridin
2019-02-21 10:38:43 +03:00
parent 6bf119b262
commit 147521d6cb
94 changed files with 893 additions and 4 deletions
@@ -78,6 +78,8 @@ fun DeclarationDescriptor.canBeReferencedViaImport(): Boolean {
}
}
fun DeclarationDescriptor.canBeAddedToImport(): Boolean = this !is PackageViewDescriptor && canBeReferencedViaImport()
fun KotlinType.canBeReferencedViaImport(): Boolean {
val descriptor = constructor.declarationDescriptor
return descriptor != null && descriptor.canBeReferencedViaImport()
@@ -1361,6 +1361,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.IntroduceImportAliasIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.RemoveSingleExpressionStringTemplateIntention</className>
<category>Kotlin</category>
@@ -0,0 +1,10 @@
import com.test.api1.data.Movie as Movie1
class Test(){
fun test(){
val m = <spot>Movie1</spot>()
}
fun test2(){
val m = Movie1()
}
}
@@ -0,0 +1,10 @@
import com.test.api1.data.Movie
class Test(){
fun test(){
val m = <spot>Movie</spot>()
}
fun test2(){
val m = Movie()
}
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention creates a import alias for the import.
</body>
</html>
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.imports.canBeAddedToImport
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
@@ -88,7 +88,7 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
val targets = nameExpression.mainReference.resolveToDescriptors(bindingContext)
if (targets.isEmpty()) return null
if (!targets.all { it.canBeReferencedViaImport() }) return null
if (!targets.all { it.canBeAddedToImport() }) return null
return targets.map { it.importableFqName }.singleOrNull()
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.imports.canBeAddedToImport
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceImportAlias.KotlinIntroduceImportAliasHandler
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
class IntroduceImportAliasIntention : SelfTargetingRangeIntention<KtNameReferenceExpression>(
KtNameReferenceExpression::class.java,
"Introduce import alias"
) {
override fun applicabilityRange(element: KtNameReferenceExpression): TextRange? {
if (element.mainReference.getImportAlias() != null) return null
val targets = element.resolveMainReferenceToDescriptors()
if (targets.isEmpty() || targets.any { !it.canBeAddedToImport() }) return null
return element.textRange
}
override fun applyTo(element: KtNameReferenceExpression, editor: Editor?) {
if (editor == null) return
KotlinIntroduceImportAliasHandler.doRefactoring(element.project, editor, element)
}
}
@@ -0,0 +1,142 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.refactoring.introduce.introduceImportAlias
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.RefactoringActionHandler
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.refactoring.rename.KotlinRenameDispatcherHandler
import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename
import org.jetbrains.kotlin.idea.refactoring.selectElement
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinFunctionShortNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinPropertyShortNameIndex
import org.jetbrains.kotlin.idea.util.ImportInsertHelperImpl
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
import org.jetbrains.kotlin.resolve.scopes.utils.findPackage
import org.jetbrains.kotlin.resolve.scopes.utils.findVariable
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
object KotlinIntroduceImportAliasHandler : RefactoringActionHandler {
const val REFACTORING_NAME = "Introduce Import Alias"
fun doRefactoring(project: Project, editor: Editor, element: KtNameReferenceExpression) {
val fqName = element.resolveMainReferenceToDescriptors().firstOrNull()?.importableFqName ?: return
val file = element.containingKtFile
val declarationDescriptors = file.resolveImportReference(fqName)
@Suppress("UNCHECKED_CAST")
val usages = declarationDescriptors
.flatMap { findPsiElements(project, file, it) }
.flatMap {
ReferencesSearch.search(it, file.useScope).findAll() as List<KtSimpleNameReference>
}
val suggestedName = suggestedName(element.mainReference.value, file.getResolutionScope())
ImportInsertHelperImpl.addImport(project, file, fqName, false, Name.identifier(suggestedName))
replaceUsages(usages, suggestedName)
cleanImport(file, fqName)
if (!ApplicationManager.getApplication().isUnitTestMode) {
invokeRename(project, editor, file)
}
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
if (file !is KtFile) return
selectElement(editor, file, listOf(CodeInsightUtils.ElementKind.EXPRESSION)) {
doRefactoring(project, editor, it as KtNameReferenceExpression)
}
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
throw AssertionError("${KotlinIntroduceImportAliasHandler.REFACTORING_NAME} can only be invoked from editor")
}
}
private fun cleanImport(file: KtFile, fqName: FqName) {
file.importDirectives.find { it.alias == null && fqName == it.importedFqName }?.delete()
}
private fun findPsiElements(project: Project, file: KtFile, descriptor: DeclarationDescriptor): Collection<PsiElement> {
descriptor.findPsi()?.let { return listOf(it) }
val fqName = descriptor.importableFqName ?: return emptyList()
val resolveScope = file.resolveScope
return when (descriptor) {
is DeserializedClassDescriptor -> KotlinFullClassNameIndex.getInstance()[fqName.asString(), project, resolveScope]
is DeserializedSimpleFunctionDescriptor -> KotlinFunctionShortNameIndex.getInstance()[fqName.shortName().asString(), project, resolveScope]
is PropertyImportedFromObject -> KotlinPropertyShortNameIndex.getInstance()[fqName.shortName().asString(), project, resolveScope]
else -> emptyList()
}.filter { fqName == it.fqName }
}
private fun suggestedName(oldName: String, scope: LexicalScope): String =
KotlinNameSuggester.suggestNameByName(oldName, fun(name: String): Boolean {
if (oldName == name) return false
val identifier = Name.identifier(name)
return scope.findVariable(identifier, NoLookupLocation.FROM_IDE) == null
&& scope.findFunction(identifier, NoLookupLocation.FROM_IDE) == null
&& scope.findClassifier(identifier, NoLookupLocation.FROM_IDE) == null
&& scope.findPackage(identifier) == null
})
private fun invokeRename(project: Project, editor: Editor, file: KtFile) {
val elementToRename = file.findElementForRename<KtSimpleNameExpression>(editor.caretModel.offset) ?: return
val dataContext = SimpleDataContext.getSimpleContext(
CommonDataKeys.PSI_ELEMENT.name,
elementToRename,
(editor as? EditorEx)?.dataContext
)
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
KotlinRenameDispatcherHandler().invoke(project, editor, file, dataContext)
}
private fun replaceUsages(usages: List<KtSimpleNameReference>, newName: String) {
usages.filter { !it.isImportUsage() }
.reversed() // case: inner element
.map {
val newExpression = it.handleElementRename(newName) as KtNameReferenceExpression
val qualifiedElement = newExpression.getQualifiedElement()
if (qualifiedElement != newExpression) {
val parent = newExpression.parent
if (parent is KtCallExpression || parent is KtUserType) {
newExpression.siblings(forward = false, withItself = false).forEach(PsiElement::delete)
qualifiedElement.replace(parent)
} else qualifiedElement.replace(newExpression)
}
}
}
@@ -386,8 +386,12 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
private fun KtReferenceExpression.resolveTargets(): Collection<DeclarationDescriptor> =
this.getImportableTargets(resolutionFacade.analyze(this, BodyResolveMode.PARTIAL))
private fun addImport(fqName: FqName, allUnder: Boolean): KtImportDirective {
val importPath = ImportPath(fqName, allUnder)
private fun addImport(fqName: FqName, allUnder: Boolean): KtImportDirective = addImport(project, file, fqName, allUnder)
}
companion object {
fun addImport(project: Project, file: KtFile, fqName: FqName, allUnder: Boolean = false, alias: Name? = null): KtImportDirective {
val importPath = ImportPath(fqName, allUnder, alias)
val psiFactory = KtPsiFactory(project)
if (file is KtCodeFragment) {
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
package my.simple.name
class Foo
fun foo() {
val f: my.simple.name<caret>.Foo
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.IntroduceImportAliasIntention
@@ -0,0 +1,15 @@
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Middle {
fun test() {
val i = Outer.Middle.Inner<caret>.SIZE
}
}
@@ -0,0 +1,17 @@
import Outer.Middle.Inner.Companion as Inner1
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Middle {
fun test() {
val i = Inner1.SIZE
}
}
@@ -0,0 +1,17 @@
import Outer.Middle.Inner as F
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Middle {
fun test() {
val i = Outer.Middle.Inner<caret>.SIZE
}
}
@@ -0,0 +1,18 @@
import Outer.Middle.Inner as F
import Outer.Middle.Inner.Companion as Inner1
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Middle {
fun test() {
val i = Inner1.SIZE
}
}
@@ -0,0 +1,2 @@
// WITH_RUNTIME
fun foo(list: List<caret><String>) {}
@@ -0,0 +1,4 @@
import kotlin.collections.List as List1
// WITH_RUNTIME
fun foo(list: List1<String>) {}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun foo() {
val list: List<String>
val secondList = List<caret>(5) { 1 }
}
@@ -0,0 +1,7 @@
import kotlin.collections.List as List1
// WITH_RUNTIME
fun foo() {
val list: List1<String>
val secondList = List1(5) { 1 }
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun foo() {
val max = Int.MAX_VALUE<caret>
val max2 = Int.Companion.MAX_VALUE
}
@@ -0,0 +1,7 @@
import kotlin.Int.Companion.MAX_VALUE as MAX_VALUE1
// WITH_RUNTIME
fun foo() {
val max = MAX_VALUE1
val max2 = MAX_VALUE1
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun foo() {
val max = Int.MAX_VALUE
val max2 = Int.Companion<caret>.MAX_VALUE
}
@@ -0,0 +1,7 @@
import kotlin.Int.Companion as Companion1
// WITH_RUNTIME
fun foo() {
val max = Companion1.MAX_VALUE
val max2 = Companion1.MAX_VALUE
}
@@ -0,0 +1,13 @@
import Outer.Middle as P
class Outer {
class Middle {
class Inner
}
}
class Test() {
fun test() {
val i = Outer.Middle<caret>.Inner()
}
}
@@ -0,0 +1,14 @@
import Outer.Middle as Middle1
import Outer.Middle as P
class Outer {
class Middle {
class Inner
}
}
class Test() {
fun test() {
val i = Middle1.Inner()
}
}
+14
View File
@@ -0,0 +1,14 @@
import Outer.Inner
class Outer {
class Inner
}
class Test(){
fun test(){
val i = Inner<caret>()
}
fun test2(){
val i = Inner()
}
}
@@ -0,0 +1,14 @@
import Outer.Inner as Inner1
class Outer {
class Inner
}
class Test(){
fun test(){
val i = Inner1()
}
fun test2(){
val i = Inner1()
}
}
@@ -0,0 +1,14 @@
class Outer {
class Middle {
class Inner(val outer: Outer) {
constructor() : this(Outer())
}
}
}
class Middle {
fun test() {
val i = Outer.Middle.Inner<caret>(Outer())
val b = Outer.Middle.Inner()
}
}
@@ -0,0 +1,16 @@
import Outer.Middle.Inner as Inner1
class Outer {
class Middle {
class Inner(val outer: Outer) {
constructor() : this(Outer())
}
}
}
class Middle {
fun test() {
val i = Inner1(Outer())
val b = Inner1()
}
}
@@ -0,0 +1,16 @@
class Outer {
class Middle {
class Inner {
companion object {
fun foo() {}
}
}
}
}
class Test() {
fun test() {
val foo = 1
Outer.Middle.Inner.foo<caret>()
}
}
@@ -0,0 +1,18 @@
import Outer.Middle.Inner.Companion.foo as foo1
class Outer {
class Middle {
class Inner {
companion object {
fun foo() {}
}
}
}
}
class Test() {
fun test() {
val foo = 1
foo1()
}
}
@@ -0,0 +1,21 @@
import Outer.Middle as Middle1
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Test() {
fun test() {
val i = Outer.Middle<caret>.Inner.SIZE
}
fun test2() {
val i = Middle1.Inner.SIZE
}
}
@@ -0,0 +1,22 @@
import Outer.Middle as Middle1
import Outer.Middle as Middle2
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Test() {
fun test() {
val i = Middle2.Inner.SIZE
}
fun test2() {
val i = Middle1.Inner.SIZE
}
}
@@ -0,0 +1,23 @@
import Outer.Middle.Inner
import Outer.Middle.Inner.Companion.foo
class Outer {
class Middle {
class Inner {
companion object {
fun foo() {}
fun foo(a: Outer) {}
}
}
}
}
class Test() {
fun test() {
val i = Inner.foo<caret>()
}
fun test2() {
val i = Outer.Middle.Inner.foo(Outer())
}
}
@@ -0,0 +1,23 @@
import Outer.Middle.Inner
import Outer.Middle.Inner.Companion.foo as foo1
class Outer {
class Middle {
class Inner {
companion object {
fun foo() {}
fun foo(a: Outer) {}
}
}
}
}
class Test() {
fun test() {
val i = foo1()
}
fun test2() {
val i = foo1(Outer())
}
}
@@ -0,0 +1,21 @@
import Outer.Middle
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Test() {
fun test() {
val i = Middle<caret>.Inner.SIZE
}
fun test2() {
val i = Outer.Middle.Inner.SIZE
}
}
@@ -0,0 +1,21 @@
import Outer.Middle as Middle1
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Test() {
fun test() {
val i = Middle1.Inner.SIZE
}
fun test2() {
val i = Middle1.Inner.SIZE
}
}
@@ -0,0 +1,16 @@
// IS_APPLICABLE: false
import Outer.Inner as NotTestAlias
class Outer {
class Inner
}
class Test() {
fun test() {
val i = NotTestAlias<caret>()
}
fun test2() {
val i = NotTestAlias()
}
}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
class Test() {
fun test() {
class Foo
val i = Foo<caret>()
}
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
class Test() {
fun test() {
val i = Test()
val b = i<caret>
}
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
package my.simple.name
class Foo
fun foo() {
val foo: my.simple.name<caret>.Foo
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
import Outer.*<caret>
class Outer {
class Inner
}
@@ -0,0 +1,7 @@
import Outer.Middle<caret>
class Outer {
class Middle {
class Inner
}
}
@@ -0,0 +1,7 @@
import Outer.Middle as Middle1
class Outer {
class Middle {
class Inner
}
}
@@ -0,0 +1,8 @@
class Outer {
class Middle<T> {}
}
class B<T> {}
fun foo(b: B<Outer.Middle<caret><String>>) {
}
@@ -0,0 +1,10 @@
import Outer.Middle as Middle1
class Outer {
class Middle<T> {}
}
class B<T> {}
fun foo(b: B<Middle1<String>>) {
}
@@ -0,0 +1,8 @@
class Outer {
class Middle<T> {}
class Middle1 {}
}
fun main() {
val t = Outer.Middle<Outer.Middle<caret><Outer.Middle1>>()
}
@@ -0,0 +1,10 @@
import Outer.Middle as Middle1
class Outer {
class Middle<T> {}
class Middle1 {}
}
fun main() {
val t = Middle1<Middle1<Outer.Middle1>>()
}
@@ -0,0 +1,21 @@
import Outer.Middle
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Test() {
fun test() {
val i = Middle.Inner.SIZE<caret>
}
fun test2() {
val i = Outer.Middle.Inner.SIZE
}
}
@@ -0,0 +1,22 @@
import Outer.Middle
import Outer.Middle.Inner.Companion.SIZE as SIZE1
class Outer {
class Middle {
class Inner {
companion object {
const val SIZE = 1
}
}
}
}
class Test() {
fun test() {
val i = SIZE1
}
fun test2() {
val i = SIZE1
}
}
@@ -1,5 +1,6 @@
// "Add annotation target" "false"
// WITH_RUNTIME
// ACTION: Introduce import alias
// ACTION: Make internal
// ACTION: Make private
// ACTION: Make protected
@@ -1,4 +1,5 @@
// "Add annotation target" "false"
// ACTION: Introduce import alias
// ACTION: Make internal
// ACTION: Make private
// ACTION: Make protected
@@ -1,5 +1,6 @@
// "Add annotation target" "false"
// WITH_RUNTIME
// ACTION: Introduce import alias
// ACTION: Make internal
// ACTION: Make private
// ERROR: '@field:' annotations could be applied only to properties with backing fields
@@ -1,4 +1,5 @@
// "Add annotation target" "false"
// ACTION: Introduce import alias
// ACTION: Make internal
// ACTION: Make private
// ACTION: Specify type explicitly
@@ -1,6 +1,7 @@
// "Add default constructor to expect class" "false"
// ENABLE_MULTIPLATFORM
// ACTION: Create subclass
// ACTION: Introduce import alias
// ACTION: Remove constructor call
// ERROR: This class does not have a constructor
@@ -1,5 +1,6 @@
// "Add default constructor to expect class" "false"
// ACTION: Create subclass
// ACTION: Introduce import alias
// ACTION: Remove constructor call
// ERROR: This class does not have a constructor
@@ -3,6 +3,7 @@
// ERROR: Expression 'Some()' of type 'Some' cannot be invoked as a function. The function 'invoke()' is not found
// ACTION: Create extension function 'Some.invoke'
// ACTION: Create member function 'Some.invoke'
// ACTION: Introduce import alias
package testing
@@ -3,6 +3,7 @@
// ERROR: Destructuring declaration initializer of type Some must have a 'component1()' function
// ACTION: Create extension function 'Some.component1'
// ACTION: Create member function 'Some.component1'
// ACTION: Introduce import alias
package testing
@@ -1,4 +1,5 @@
// "Convert to anonymous object" "false"
// ACTION: Introduce import alias
// ERROR: Interface I does not have constructors
interface I {
fun foo(): String
@@ -1,4 +1,5 @@
// "Create type parameter in class 'X'" "false"
// ACTION: Introduce import alias
// ERROR: 2 type arguments expected for class X<T, U>
class X<T, U>
fun Y(x: X<<caret>String>) {}
@@ -1,4 +1,5 @@
// "Create type parameter in class 'X'" "false"
// ACTION: Introduce import alias
// ERROR: No type arguments expected for class X
class X
@@ -1,5 +1,6 @@
// "Create property 'address2' as constructor parameter" "false"
// ACTION: Create property 'address' as constructor parameter
// ACTION: Introduce import alias
// ACTION: Make 'Person' data class
// ERROR: Destructuring declaration initializer of type Person must have a 'component3()' function
// ERROR: Destructuring declaration initializer of type Person must have a 'component4()' function
@@ -1,5 +1,6 @@
// "Make 'foo' private" "false"
// ACTION: Convert receiver to parameter
// ACTION: Introduce import alias
// ACTION: Make 'Private' protected
// ACTION: Make 'Private' public
// ERROR: 'protected (in My)' member exposes its 'private' receiver type argument Private
@@ -1,5 +1,6 @@
// "Make '<init>' internal" "false"
// DISABLE-ERRORS
// ACTION: Introduce import alias
// ACTION: Make 'My' public
internal class My
@@ -1,5 +1,6 @@
// "Replace with 'New<T, U>'" "false"
// ACTION: Convert to block body
// ACTION: Introduce import alias
// ACTION: Remove explicit type specification
@Deprecated("Use New", replaceWith = ReplaceWith("New<T, U>"))
@@ -1,4 +1,5 @@
// "Replace with 'NewClass'" "false"
// ACTION: Introduce import alias
// ACTION: Introduce local variable
// ACTION: Replace usages of 'typealias Old = OldClass' in whole project
// ACTION: Replace with 'New'
@@ -1,5 +1,6 @@
// "Replace with 'New'" "false"
// ACTION: Convert to block body
// ACTION: Introduce import alias
// ACTION: Introduce local variable
// ACTION: Replace usages of '<init>(): Old /* = OldClass */' in whole project
// ACTION: Replace with 'NewClass(12)'
@@ -1,5 +1,6 @@
// "Replace with 'NewClass'" "false"
// ACTION: Convert to block body
// ACTION: Introduce import alias
// ACTION: Remove explicit type specification
@@ -1,5 +1,6 @@
// "Replace with 'NewClass'" "false"
// ACTION: Convert to block body
// ACTION: Introduce import alias
// ACTION: Introduce local variable
+1
View File
@@ -2,6 +2,7 @@
// COMPILER_ARGUMENTS: -version -Xuse-experimental=Something
// DISABLE-ERRORS
// WITH_RUNTIME
// ACTION: Introduce import alias
// ACTION: Make internal
// ACTION: Make private
+1
View File
@@ -5,6 +5,7 @@
// ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Inner'
// ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'bar'
// ACTION: Add '-Xuse-experimental=MyExperimentalAPI' to module light_idea_test_case compiler arguments
// ACTION: Introduce import alias
// ERROR: This declaration is experimental and its usage must be marked with '@MyExperimentalAPI' or '@UseExperimental(MyExperimentalAPI::class)'
@Experimental
@@ -1,5 +1,6 @@
// "Make '<init>' public" "false"
// "Make '<init>' internal" "false"
// ACTION: Introduce import alias
// ERROR: Cannot access '<init>': it is private in 'SealedClass'
// ERROR: This type is sealed, so it can be inherited by only its own nested classes or objects
@@ -2,5 +2,6 @@
// ERROR: This type is final, so it cannot be inherited from
// ACTION: Add names to call arguments
// ACTION: Do not show hints for current method
// ACTION: Introduce import alias
data class A(val x: Int)
class B: A<caret>(42)
@@ -1,4 +1,5 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
// ERROR: This type is final, so it cannot be inherited from
// ACTION: Create test
// ACTION: Introduce import alias
class foo : <caret>JavaClass() {}
@@ -1,5 +1,6 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
// ACTION: Create test
// ACTION: Inline type parameter
// ACTION: Introduce import alias
// ACTION: Remove final upper bound
class foo<T : <caret>JavaClass>() {}
@@ -1,5 +1,6 @@
// "Add 'lateinit' modifier" "false"
// ACTION: Add initializer
// ACTION: Introduce import alias
// ACTION: Make 'a' abstract
// ACTION: Move to constructor parameters
// ACTION: Move to constructor
+1
View File
@@ -1,4 +1,5 @@
// "Make bar suspend" "false"
// ACTION: Introduce import alias
// ERROR: Suspend function 'foo' should be called only from a coroutine or another suspend function
suspend fun foo() {}
+1
View File
@@ -1,5 +1,6 @@
// "Make bar suspend" "false"
// ACTION: Convert property initializer to getter
// ACTION: Introduce import alias
// ERROR: Suspend function 'foo' should be called only from a coroutine or another suspend function
suspend fun foo() = 42
@@ -1,6 +1,7 @@
// "Move annotation to receiver type" "false"
// ERROR: This annotation is not applicable to target 'declaration' and use site target '@receiver'
// ACTION: Make internal
// ACTION: Introduce import alias
// ACTION: Make private
// ACTION: Add annotation target
@@ -1,6 +1,7 @@
// "Move annotation to receiver type" "false"
// ERROR: This annotation is not applicable to target 'declaration' and use site target '@receiver'
// ACTION: Make internal
// ACTION: Introduce import alias
// ACTION: Make private
// ACTION: Specify type explicitly
// ACTION: Add annotation target
@@ -1,4 +1,5 @@
// "Optimize imports" "false"
// ACTION: Introduce import alias
import p1.SomeAlias<caret>
import p1.AnnAlias
@@ -1,5 +1,6 @@
// "Change type of overriden property 'A.x' to '(Int) -> Int'" "false"
// ACTION: Change type to '(String) -> Int'
// ACTION: Introduce import alias
// ERROR: Type of 'x' is not a subtype of the overridden property 'public abstract val x: (String) -> Int defined in A'
interface A {
val x: (String) -> Int
@@ -1,6 +1,7 @@
// "Change 'B.foo' function return type to 'Int'" "false"
// "Change 'B.foo' function return type to 'Long'" "false"
// "Remove explicitly specified return type" "false"
// ACTION: Introduce import alias
// ERROR: Return type of 'foo' is not a subtype of the return type of the overridden member 'public abstract fun foo(): Int defined in A'
abstract class A {
abstract fun foo() : Int;
@@ -1,4 +1,5 @@
// "Change to constructor invocation" "false"
// ACTION: Introduce import alias
// ERROR: This type has a constructor, and thus must be initialized here
// ERROR: This type is sealed, so it can be inherited by only its own nested classes or objects
sealed class A
@@ -1,4 +1,5 @@
// "Change to constructor invocation" "false"
// ACTION: Introduce import alias
// ERROR: This type has a constructor, and thus must be initialized here
// ERROR: This type is sealed, so it can be inherited by only its own nested classes or objects
@@ -1,5 +1,6 @@
// "Cast expression 'Foo<Number>()' to 'Foo<Int>'" "false"
// ACTION: Change return type of enclosing function 'foo' to 'Foo<Number>'
// ACTION: Introduce import alias
// ERROR: Type mismatch: inferred type is Foo<Number> but Foo<Int> was expected
class Foo<T>
@@ -1,5 +1,6 @@
// "Change type to '(String) -> [ERROR : Ay]'" "false"
// ACTION: Change type of base property 'A.x' to '(Int) -> Int'
// ACTION: Introduce import alias
// ERROR: Type of 'x' is not a subtype of the overridden property 'public abstract val x: (String) -> [ERROR : Ay] defined in A'
// ERROR: Unresolved reference: Ay
interface A {
@@ -4,6 +4,7 @@
// ACTION: Change parameter 'block' type of function 'str' to 'Object'
// ACTION: Create function 'str'
// ACTION: Edit method contract of 'Object'
// ACTION: Introduce import alias
fun fn() {
str(<caret>Object())
}
+1
View File
@@ -1,5 +1,6 @@
// "Replace array of boxed with array of primitive" "false"
// ERROR: Invalid type of annotation member
// ACTION: Introduce import alias
// ACTION: Put parameters on one line
annotation class SuperAnnotation(
val foo: <caret>Array<*>,
@@ -1,5 +1,6 @@
// "Replace array of boxed with array of primitive" "false"
// ACTION: Put parameters on one line
// ACTION: Introduce import alias
// ACTION: Convert to vararg parameter (may break code)
annotation class SuperAnnotation(
val str: <caret>Array<String>
@@ -1,6 +1,7 @@
// "Change to val" "false"
// ACTION: Create extension function 'Delegate.getValue'
// ACTION: Create member function 'Delegate.getValue'
// ACTION: Introduce import alias
// ERROR: Missing 'getValue(Nothing?, KProperty<*>)' method on delegate of type 'Delegate'
import kotlin.reflect.KProperty
@@ -1,6 +1,7 @@
// "Change to val" "false"
// ACTION: Create extension function 'Delegate.getValue', function 'Delegate.setValue'
// ACTION: Create member function 'Delegate.getValue', function 'Delegate.setValue'
// ACTION: Introduce import alias
// ERROR: Missing 'getValue(Nothing?, KProperty<*>)' method on delegate of type 'Delegate'
// ERROR: Missing 'setValue(Nothing?, KProperty<*>, String)' method on delegate of type 'Delegate'
import kotlin.reflect.KProperty
@@ -1,6 +1,7 @@
// "Wrap with '?.let { ... }' call" "false"
// WITH_RUNTIME
// ACTION: Add non-null asserted (!!) call
// ACTION: Introduce import alias
// ACTION: Introduce local variable
// ACTION: Replace with safe (this?.) call
// ERROR: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
@@ -9602,6 +9602,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/importMember/NoTarget.kt");
}
@TestMetadata("NotApplicablePackage.kt")
public void testNotApplicablePackage() throws Exception {
runTest("idea/testData/intentions/importMember/NotApplicablePackage.kt");
}
@TestMetadata("NotForQualifier.kt")
public void testNotForQualifier() throws Exception {
runTest("idea/testData/intentions/importMember/NotForQualifier.kt");
@@ -9943,6 +9948,129 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/introduceImportAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class IntroduceImportAlias extends AbstractIntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
@TestMetadata("addImport.kt")
public void testAddImport() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/addImport.kt");
}
@TestMetadata("addImportHasOtherAlias.kt")
public void testAddImportHasOtherAlias() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/addImportHasOtherAlias.kt");
}
@TestMetadata("addImportWithDefaultClass.kt")
public void testAddImportWithDefaultClass() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/addImportWithDefaultClass.kt");
}
@TestMetadata("addImportWithDefaultClassAndFunction.kt")
public void testAddImportWithDefaultClassAndFunction() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/addImportWithDefaultClassAndFunction.kt");
}
@TestMetadata("addImportWithDefaultClassCompanion.kt")
public void testAddImportWithDefaultClassCompanion() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/addImportWithDefaultClassCompanion.kt");
}
@TestMetadata("addImportWithDefaultClassCompanion2.kt")
public void testAddImportWithDefaultClassCompanion2() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/addImportWithDefaultClassCompanion2.kt");
}
public void testAllFilesPresentInIntroduceImportAlias() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/introduceImportAlias"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("alreadyImportAlias.kt")
public void testAlreadyImportAlias() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/alreadyImportAlias.kt");
}
@TestMetadata("class.kt")
public void testClass() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/class.kt");
}
@TestMetadata("classWithConstructor.kt")
public void testClassWithConstructor() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/classWithConstructor.kt");
}
@TestMetadata("conflictLocalName.kt")
public void testConflictLocalName() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/conflictLocalName.kt");
}
@TestMetadata("conflictPackage.kt")
public void testConflictPackage() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/conflictPackage.kt");
}
@TestMetadata("function.kt")
public void testFunction() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/function.kt");
}
@TestMetadata("middleImport.kt")
public void testMiddleImport() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/middleImport.kt");
}
@TestMetadata("notApplicableAlias.kt")
public void testNotApplicableAlias() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/notApplicableAlias.kt");
}
@TestMetadata("notApplicableLocalClass.kt")
public void testNotApplicableLocalClass() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/notApplicableLocalClass.kt");
}
@TestMetadata("notApplicableLocalVariable.kt")
public void testNotApplicableLocalVariable() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/notApplicableLocalVariable.kt");
}
@TestMetadata("notApplicablePackage.kt")
public void testNotApplicablePackage() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/notApplicablePackage.kt");
}
@TestMetadata("notApplicableStar.kt")
public void testNotApplicableStar() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/notApplicableStar.kt");
}
@TestMetadata("onImport.kt")
public void testOnImport() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/onImport.kt");
}
@TestMetadata("userType.kt")
public void testUserType() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/userType.kt");
}
@TestMetadata("userTypeInner.kt")
public void testUserTypeInner() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/userTypeInner.kt");
}
@TestMetadata("variable.kt")
public void testVariable() throws Exception {
runTest("idea/testData/intentions/introduceImportAlias/variable.kt");
}
}
@TestMetadata("idea/testData/intentions/introduceVariable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)