Intentions: Move member of companion object to corresponding class
#KT-9697 Fixed
This commit is contained in:
+5
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
<spot>fun foo() = 1</spot>
|
||||
}
|
||||
|
||||
fun bar() = A.foo()
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
companion object {
|
||||
<spot>fun foo() = 1</spot>
|
||||
}
|
||||
}
|
||||
|
||||
fun bar() = A.foo()
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention moves member of companion object to the corresponding class.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1169,6 +1169,11 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.MoveMemberOutOfCompanionObjectIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||
displayName="Convert object literal to lambda"
|
||||
groupName="Kotlin"
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
|
||||
class MoveMemberOutOfCompanionObjectIntention : SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java,
|
||||
"Move out of companion object") {
|
||||
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
|
||||
if (element !is KtNamedFunction && element !is KtProperty && element !is KtClassOrObject) return null
|
||||
val container = element.containingClassOrObject
|
||||
if (!(container is KtObjectDeclaration && container.isCompanion())) return null
|
||||
if (container.containingClassOrObject == null) return null
|
||||
return element.nameIdentifier?.textRange
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
|
||||
val project = element.project
|
||||
|
||||
val companionObject = element.containingClassOrObject!!
|
||||
val targetClass = companionObject.containingClassOrObject!!
|
||||
|
||||
fun deleteCompanionIfEmpty() {
|
||||
if (companionObject.declarations.isEmpty()) {
|
||||
companionObject.delete()
|
||||
}
|
||||
}
|
||||
|
||||
if (element is KtClassOrObject) {
|
||||
val moveDescriptor = MoveDeclarationsDescriptor(listOf(element),
|
||||
KotlinMoveTargetForExistingElement(targetClass),
|
||||
MoveDeclarationsDelegate.NestedClass())
|
||||
MoveKotlinDeclarationsProcessor(project, moveDescriptor).run()
|
||||
deleteCompanionIfEmpty()
|
||||
return
|
||||
}
|
||||
|
||||
val externalRefs = project.runSynchronouslyWithProgress("Searching for ${element.name}", true) {
|
||||
ReferencesSearch.search(element).filter {
|
||||
val refElement = it.element ?: return@filter false
|
||||
!targetClass.isAncestor(refElement) || companionObject.isAncestor(refElement)
|
||||
}
|
||||
} ?: return
|
||||
|
||||
val conflicts = MultiMap<PsiElement, String>()
|
||||
for (ref in externalRefs) {
|
||||
val refElement = ref.element ?: continue
|
||||
conflicts.putValue(refElement, "Class instance required: ${refElement.text}")
|
||||
}
|
||||
|
||||
project.checkConflictsInteractively(conflicts) {
|
||||
Mover.Default(element, targetClass)
|
||||
deleteCompanionIfEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.MoveMemberOutOfCompanionObjectIntention
|
||||
@@ -0,0 +1,11 @@
|
||||
class A {
|
||||
companion object {
|
||||
class <caret>B {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
A.Companion.B()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class A {
|
||||
class B {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
A.B()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class A {
|
||||
companion object {
|
||||
class B {
|
||||
|
||||
}
|
||||
|
||||
fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class A {
|
||||
companion object {
|
||||
class B {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo()
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// WITH_RUNTIME
|
||||
// SHOULD_FAIL_WITH: Class instance required: foo, Class instance required: foo, Class instance required: foo, Class instance required: foo
|
||||
class A {
|
||||
companion object {
|
||||
class B {
|
||||
init {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
A.foo()
|
||||
A.Companion.foo()
|
||||
with(A) {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class A {
|
||||
companion object {
|
||||
class B {
|
||||
|
||||
}
|
||||
|
||||
val <caret>foo: Int = 1
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo + 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
class A {
|
||||
companion object {
|
||||
class B {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo + 1
|
||||
}
|
||||
|
||||
val foo: Int = 1
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
// SHOULD_FAIL_WITH: Class instance required: foo, Class instance required: foo, Class instance required: foo, Class instance required: foo
|
||||
class A {
|
||||
companion object {
|
||||
class B {
|
||||
init {
|
||||
foo + 1
|
||||
}
|
||||
}
|
||||
|
||||
val <caret>foo: Int = 1
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo + 1
|
||||
}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
A.foo + 1
|
||||
A.Companion.foo + 1
|
||||
with(A) {
|
||||
foo + 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
class A {
|
||||
object O {
|
||||
class <caret>B {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
class A {
|
||||
class <caret>B {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package a
|
||||
|
||||
class A {
|
||||
companion object {
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class B {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
A.B()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package b;
|
||||
|
||||
import a.A;
|
||||
|
||||
class J {
|
||||
void foo() {
|
||||
A.B b = new A.B();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package a
|
||||
|
||||
class A {
|
||||
companion object {
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
class <caret>B {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
A.Companion.B()
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package b;
|
||||
|
||||
import a.A;
|
||||
|
||||
class J {
|
||||
void foo() {
|
||||
A.Companion.B b = new A.Companion.B();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "a/A.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.intentions.MoveMemberOutOfCompanionObjectIntention",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public abstract class AbstractIntentionTest extends KotlinCodeInsightTestCase {
|
||||
assertEquals("Intention text mismatch.", intentionTextString, intentionAction.getText());
|
||||
}
|
||||
|
||||
String shouldFailString = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// SHOULD_FAIL_WITH: ");
|
||||
String shouldFailString = StringUtil.join(InTextDirectivesUtils.findListWithPrefixes(fileText, "// SHOULD_FAIL_WITH: "), ", ");
|
||||
|
||||
try {
|
||||
if (isApplicableExpected) {
|
||||
@@ -171,7 +171,7 @@ public abstract class AbstractIntentionTest extends KotlinCodeInsightTestCase {
|
||||
}
|
||||
);
|
||||
// Don't bother checking if it should have failed.
|
||||
if (shouldFailString == null) {
|
||||
if (shouldFailString.isEmpty()) {
|
||||
for (Map.Entry<String, PsiFile> entry: pathToFile.entrySet()) {
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
myFile = entry.getValue();
|
||||
@@ -186,7 +186,7 @@ public abstract class AbstractIntentionTest extends KotlinCodeInsightTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
assertNull("Expected test to fail.", shouldFailString);
|
||||
assertEquals("Expected test to fail.", "", shouldFailString);
|
||||
}
|
||||
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
|
||||
assertEquals("Failure message mismatch.", shouldFailString, StringUtil.join(e.getMessages(), ", "));
|
||||
|
||||
Reference in New Issue
Block a user