Pull Up: Move property initializers

This commit is contained in:
Alexey Sedunov
2015-07-20 14:31:59 +03:00
parent 390f352e75
commit 1a09741c0a
20 changed files with 587 additions and 20 deletions
@@ -392,4 +392,6 @@ public fun JetFunctionLiteralArgument.getFunctionLiteralArgumentName(bindingCont
return (resolvedCall?.getArgumentMapping(this) as? ArgumentMatch)?.valueParameter?.getName()
}
public fun JetExpression.asAssignment(): JetBinaryExpression? =
if (JetPsiUtil.isAssignment(this)) this as JetBinaryExpression else null
@@ -16,22 +16,21 @@
package org.jetbrains.kotlin.idea.refactoring.pullUp
import com.intellij.lang.Language
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightField
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.memberPullUp.PullUpData
import com.intellij.refactoring.memberPullUp.PullUpHelper
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightClass
import com.intellij.refactoring.util.RefactoringUtil
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.JetLanguage
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.imports.importableFqName
@@ -39,23 +38,23 @@ import org.jetbrains.kotlin.idea.refactoring.safeDelete.removeOverrideModifier
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiverOrThis
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import java.util.ArrayList
import java.util.LinkedHashSet
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.keysToMap
import java.util.*
class KotlinPullUpHelper(
private val javaData: PullUpData,
@@ -67,6 +66,212 @@ class KotlinPullUpHelper(
private var JetElement.newTypeText: String? by CopyableUserDataProperty(Key.create("NEW_TYPE_TEXT"))
}
private fun JetExpression.isMovable(): Boolean {
return accept(
object: JetVisitor<Boolean, Nothing?>() {
override fun visitJetElement(element: JetElement, arg: Nothing?): Boolean {
return element.allChildren.all { (it as? JetElement)?.accept(this, arg) ?: true }
}
override fun visitJetFile(file: JetFile, data: Nothing?) = false
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, arg: Nothing?): Boolean {
val resolvedCall = expression.getResolvedCall(data.resolutionFacade.analyze(expression)) ?: return true
val receiver = (resolvedCall.getExplicitReceiverValue() as? ExpressionReceiver)?.getExpression()
if (receiver != null && receiver !is JetThisExpression && receiver !is JetSuperExpression) return true
var descriptor: DeclarationDescriptor = resolvedCall.getResultingDescriptor()
if (descriptor is ConstructorDescriptor) {
descriptor = descriptor.getContainingDeclaration()
}
// todo: local functions
if (descriptor is ValueParameterDescriptor) return true
if (descriptor is ClassDescriptor && !descriptor.isInner()) return true
if (descriptor is MemberDescriptor) {
if (descriptor.getSource().getPsi() in propertiesToMoveInitializers) return true
descriptor = descriptor.getContainingDeclaration()
}
return descriptor is PackageFragmentDescriptor
|| (descriptor is ClassDescriptor && DescriptorUtils.isSubclass(data.targetClassDescriptor, descriptor))
}
},
null
)
}
private fun getCommonInitializer(
currentInitializer: JetExpression?,
scope: JetBlockExpression?,
propertyDescriptor: PropertyDescriptor,
elementsToRemove: MutableSet<JetElement>): JetExpression? {
if (scope == null) return currentInitializer
var initializerCandidate: JetExpression? = null
for (statement in scope.getStatements()) {
statement.asAssignment()?.let body@ {
val lhs = JetPsiUtil.safeDeparenthesize(it.getLeft() ?: return@body)
val receiver = (lhs as? JetQualifiedExpression)?.getReceiverExpression()
if (receiver != null && receiver !is JetThisExpression) return@body
val resolvedCall = lhs.getResolvedCall(data.resolutionFacade.analyze(it)) ?: return@body
if (resolvedCall.getResultingDescriptor() != propertyDescriptor) return@body
if (initializerCandidate == null) {
if (currentInitializer == null) {
if (!statement.isMovable()) return null
initializerCandidate = statement
elementsToRemove.add(statement)
}
else {
if (!JetPsiUnifier.DEFAULT.unify(statement, currentInitializer).matched) return null
initializerCandidate = currentInitializer
elementsToRemove.add(statement)
}
}
else if (!JetPsiUnifier.DEFAULT.unify(statement, initializerCandidate).matched) return null
}
}
return initializerCandidate
}
private data class InitializerInfo(
val initializer: JetExpression?,
val usedProperties: Set<JetProperty>,
val usedParameters: Set<JetParameter>,
val elementsToRemove: Set<JetElement>
)
private fun getInitializerInfo(property: JetProperty,
propertyDescriptor: PropertyDescriptor,
targetConstructor: JetElement): InitializerInfo? {
val sourceConstructors = targetToSourceConstructors[targetConstructor] ?: return null
val elementsToRemove = LinkedHashSet<JetElement>()
val commonInitializer = sourceConstructors.fold(null as JetExpression?) { commonInitializer, constructor ->
val body = (constructor as? JetSecondaryConstructor)?.getBodyExpression()
getCommonInitializer(commonInitializer, body, propertyDescriptor, elementsToRemove)
}
if (commonInitializer == null) {
elementsToRemove.clear()
}
val usedProperties = LinkedHashSet<JetProperty>()
val usedParameters = LinkedHashSet<JetParameter>()
val visitor = object : JetTreeVisitorVoid() {
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
val context = data.resolutionFacade.analyze(expression)
val resolvedCall = expression.getResolvedCall(context) ?: return
val receiver = (resolvedCall.getExplicitReceiverValue() as? ExpressionReceiver)?.getExpression()
if (receiver != null && receiver !is JetThisExpression) return
val target = (resolvedCall.getResultingDescriptor() as? DeclarationDescriptorWithSource)?.getSource()?.getPsi()
when (target) {
is JetParameter -> usedParameters.add(target)
is JetProperty -> usedProperties.add(target)
}
}
}
commonInitializer?.accept(visitor)
if (targetConstructor == data.targetClass.getPrimaryConstructor() ?: data.targetClass) {
property.getInitializer()?.accept(visitor)
}
return InitializerInfo(commonInitializer, usedProperties, usedParameters, elementsToRemove)
}
private val propertiesToMoveInitializers = with(data) {
membersToMove
.filterIsInstance<JetProperty>()
.filter {
val descriptor = memberDescriptors[it] as? PropertyDescriptor
descriptor != null && data.sourceClassContext[BindingContext.BACKING_FIELD_REQUIRED, descriptor] ?: false
}
}
private val targetToSourceConstructors = LinkedHashMap<JetElement, MutableList<JetElement>>().let { result ->
if (!data.targetClass.isInterface()) {
result[data.targetClass.getPrimaryConstructor() ?: data.targetClass] = ArrayList<JetElement>()
data.sourceClass.accept(
object : JetTreeVisitorVoid() {
private fun processConstructorReference(expression: JetReferenceExpression, callingConstructorElement: JetElement) {
val descriptor = data.resolutionFacade.analyze(expression)[BindingContext.REFERENCE_TARGET, expression]
val constructorElement = (descriptor as? DeclarationDescriptorWithSource)?.getSource()?.getPsi() ?: return
if (constructorElement == data.targetClass
|| (constructorElement as? JetConstructor<*>)?.getContainingClassOrObject() == data.targetClass) {
result.getOrPut(constructorElement as JetElement, { ArrayList() }).add(callingConstructorElement)
}
}
override fun visitDelegationToSuperCallSpecifier(specifier: JetDelegatorToSuperCall) {
val constructorRef = specifier.getCalleeExpression().getConstructorReferenceExpression() ?: return
val containingClass = specifier.getStrictParentOfType<JetClassOrObject>() ?: return
val callingConstructorElement = containingClass.getPrimaryConstructor() ?: containingClass
processConstructorReference(constructorRef, callingConstructorElement)
}
override fun visitSecondaryConstructor(constructor: JetSecondaryConstructor) {
val constructorRef = constructor.getDelegationCall().getCalleeExpression() ?: return
processConstructorReference(constructorRef, constructor)
}
}
)
}
result
}
private val targetConstructorToPropertyInitializerInfoMap = LinkedHashMap<JetElement, Map<JetProperty, InitializerInfo>>().let { result ->
for (targetConstructor in targetToSourceConstructors.keySet()) {
val propertyToInitializerInfo = LinkedHashMap<JetProperty, InitializerInfo>()
for (property in propertiesToMoveInitializers) {
val propertyDescriptor = data.memberDescriptors[property] as? PropertyDescriptor ?: continue
propertyToInitializerInfo[property] = getInitializerInfo(property, propertyDescriptor, targetConstructor) ?: continue
}
val unmovableProperties = RefactoringUtil.transitiveClosure(
object : RefactoringUtil.Graph<JetProperty> {
override fun getVertices() = propertyToInitializerInfo.keySet()
override fun getTargets(source: JetProperty) = propertyToInitializerInfo[source]?.usedProperties
},
{ !propertyToInitializerInfo.containsKey(it) }
)
propertyToInitializerInfo.keySet().removeAll(unmovableProperties)
result[targetConstructor] = propertyToInitializerInfo
}
result
}
private var dummyField: PsiField? = null
private fun addMovedMember(newMember: JetNamedDeclaration) {
if (newMember is JetProperty) {
// Add dummy light field since PullUpProcessor won't invoke moveFieldInitializations() if no PsiFields are present
if (dummyField == null) {
val factory = JavaPsiFacade.getElementFactory(newMember.getProject())
val dummyField = object: LightField(
newMember.getManager(),
factory.createField("dummy", PsiType.BOOLEAN),
factory.createClass("Dummy")
) {
// Prevent processing by JavaPullUpHelper
override fun getLanguage() = JetLanguage.INSTANCE
}
javaData.getMovedMembers().add(dummyField)
}
}
when (newMember) {
is JetProperty, is JetNamedFunction -> {
newMember.getRepresentativeLightMethod()?.let { javaData.getMovedMembers().add(it) }
}
is JetClassOrObject -> {
newMember.toLightClass()?.let { javaData.getMovedMembers().add(it) }
}
}
}
private fun willBeUsedInSourceClass(member: PsiElement): Boolean {
return !ReferencesSearch
.search(member, LocalSearchScope(data.sourceClass), false)
@@ -351,8 +556,6 @@ class KotlinPullUpHelper(
&& (movedMember.hasModifier(JetTokens.ABSTRACT_KEYWORD))) {
data.targetClass.addModifierWithSpace(JetTokens.ABSTRACT_KEYWORD)
}
movedMember.getRepresentativeLightMethod()?.let { javaData.getMovedMembers().add(it) }
}
is JetClassOrObject -> {
@@ -361,13 +564,14 @@ class KotlinPullUpHelper(
}
movedMember = addMemberToTarget(memberCopy) as JetClassOrObject
member.delete()
movedMember.toLightClass()?.let { javaData.getMovedMembers().add(it) }
}
else -> return
}
processMarkedElements(movedMember)
addMovedMember(movedMember)
}
finally {
clearMarking(markedElements)
@@ -379,7 +583,92 @@ class KotlinPullUpHelper(
}
override fun moveFieldInitializations(movedFields: LinkedHashSet<PsiField>) {
val psiFactory = JetPsiFactory(data.sourceClass)
fun JetClassOrObject.getOrCreateClassInitializer(): JetClassInitializer {
getOrCreateBody().getDeclarations().lastOrNull { it is JetClassInitializer }?.let { return it as JetClassInitializer }
return addDeclaration(psiFactory.createAnonymousInitializer()) as JetClassInitializer
}
fun JetElement.getConstructorBodyBlock(): JetBlockExpression? {
return when (this) {
is JetClassOrObject -> {
getOrCreateClassInitializer().getBody()
}
is JetPrimaryConstructor -> {
getContainingClassOrObject().getOrCreateClassInitializer().getBody()
}
is JetSecondaryConstructor -> {
getBodyExpression() ?: add(psiFactory.createEmptyBody())
}
else -> null
} as? JetBlockExpression
}
fun JetClassOrObject.getDelegatorToSuperCall(): JetDelegatorToSuperCall? {
return getDelegationSpecifiers().singleOrNull { it is JetDelegatorToSuperCall } as? JetDelegatorToSuperCall
}
fun addUsedParameters(constructorElement: JetElement, info: InitializerInfo) {
if (!info.usedParameters.isNotEmpty()) return
val constructor: JetConstructor<*> = when (constructorElement) {
is JetConstructor<*> -> constructorElement
is JetClass -> constructorElement.createPrimaryConstructorIfAbsent()
else -> return
}
with(constructor.getValueParameterList()!!) {
info.usedParameters.forEach { addParameter(it) }
}
targetToSourceConstructors[constructorElement]!!.forEach {
val superCall: JetCallElement? = when (it) {
is JetClassOrObject -> it.getDelegatorToSuperCall()
is JetPrimaryConstructor -> it.getContainingClassOrObject().getDelegatorToSuperCall()
is JetSecondaryConstructor -> {
if (it.hasImplicitDelegationCall()) {
it.replaceImplicitDelegationCallWithExplicit(false)
}
else {
it.getDelegationCall()
}
}
else -> null
}
superCall?.getValueArgumentList()?.let { args ->
info.usedParameters.forEach {
args.addArgument(psiFactory.createArgument(psiFactory.createExpression(it.getName() ?: "_")))
}
}
}
}
for ((constructorElement, propertyToInitializerInfo) in targetConstructorToPropertyInitializerInfoMap.entrySet()) {
val properties = propertyToInitializerInfo.keySet().toArrayList().sortBy(
object : Comparator<JetProperty> {
override fun compare(property1: JetProperty, property2: JetProperty): Int {
val info1 = propertyToInitializerInfo[property1]!!
val info2 = propertyToInitializerInfo[property2]!!
return when {
property2 in info1.usedProperties -> -1
property1 in info2.usedProperties -> 1
else -> 0
}
}
}
)
for (oldProperty in properties) {
val info = propertyToInitializerInfo[oldProperty]!!
addUsedParameters(constructorElement, info)
info.initializer?.let {
val body = constructorElement.getConstructorBodyBlock()
body?.addAfter(it, body.getStatements().lastOrNull() ?: body.getLBrace()!!)
}
info.elementsToRemove.forEach { it.delete() }
}
}
}
override fun updateUsage(element: PsiElement) {
@@ -3,7 +3,7 @@ interface I
interface Z<T>
abstract class A<T: I, U: I, V> {
abstract class A<T: I, U: I, V>(x: X, y: Y) {
// INFO: {"checked": "true"}
val foo1: T
// INFO: {"checked": "true"}
@@ -33,7 +33,7 @@ abstract class A<T: I, U: I, V> {
}
class C<W: I> {
inner class B<X: I, Y>(x: X, y: Y): A<X, I, Z<Y>>() {
inner class B<X: I, Y>(x: X, y: Y): A<X, I, Z<Y>>(x, y) {
// INFO: {"checked": "true", "toAbstract": "true"}
override val foo5 = x
@@ -0,0 +1,10 @@
open class A
class <caret>B: A {
// INFO: {"checked": "true"}
val n: Int
constructor(a: Int) {
n = a + 1
}
}
@@ -0,0 +1,14 @@
open class A(a: Int) {
// INFO: {"checked": "true"}
val n: Int
init {
n = a + 1
}
}
class B: A {
constructor(a: Int) : super(a) {
}
}
@@ -0,0 +1,14 @@
open class A
class <caret>B: A {
// INFO: {"checked": "true"}
val n: Int
constructor(a: Int) {
n = 1 + 2
}
constructor() {
n = 1 + 2
}
}
@@ -0,0 +1,17 @@
open class A {
// INFO: {"checked": "true"}
val n: Int
init {
n = 1 + 2
}
}
class B: A {
constructor(a: Int) {
}
constructor() {
}
}
@@ -0,0 +1,14 @@
open class A
class <caret>B: A {
// INFO: {"checked": "true"}
val n: Int
constructor(a: Int) {
n = a + 1
}
constructor(a: Int, b: Int) {
n = a*b
}
}
@@ -0,0 +1,15 @@
open class A {
// INFO: {"checked": "true"}
val n: Int
}
class B: A {
constructor(a: Int) {
n = a + 1
}
constructor(a: Int, b: Int) {
n = a*b
}
}
@@ -0,0 +1,11 @@
open class A
class <caret>B: A {
// INFO: {"checked": "true"}
var n: Int
constructor(a: Int) {
n = a + 1
n = a plus 1
}
}
@@ -0,0 +1,15 @@
open class A(a: Int) {
// INFO: {"checked": "true"}
var n: Int
init {
n = a + 1
}
}
class B: A {
constructor(a: Int) : super(a) {
n = a plus 1
}
}
@@ -0,0 +1,10 @@
interface T
class <caret>A: T {
// INFO: {"checked": "true"}
val n: Int
constructor(a: Int) {
n = a + 1
}
}
@@ -0,0 +1,13 @@
interface T {
// INFO: {"checked": "true"}
val n: Int
}
class A: T {
// INFO: {"checked": "true"}
override val n: Int
constructor(a: Int) {
n = a + 1
}
}
@@ -0,0 +1,6 @@
open class A
class <caret>B(a: Int): A() {
// INFO: {"checked": "true"}
val n: Int = a + 1
}
@@ -0,0 +1,7 @@
open class A(a: Int) {
// INFO: {"checked": "true"}
val n: Int = a + 1
}
class B(a: Int): A(a) {
}
@@ -0,0 +1,20 @@
open class A
class <caret>B: A {
// INFO: {"checked": "true"}
val n: Int
// INFO: {"checked": "true"}
val x: Int = 3
// INFO: {"checked": "true"}
val y: Int = 4
// INFO: {"checked": "true"}
val a: Int = 1
// INFO: {"checked": "true"}
val b: Int = x + y
constructor(p: Int) {
n = a + b - p
}
}
@@ -0,0 +1,22 @@
open class A(p: Int) {
// INFO: {"checked": "true"}
val n: Int
// INFO: {"checked": "true"}
val x: Int = 3
// INFO: {"checked": "true"}
val y: Int = 4
// INFO: {"checked": "true"}
val a: Int = 1
// INFO: {"checked": "true"}
val b: Int = x + y
init {
n = a + b - p
}
}
class B: A {
constructor(p: Int) : super(p) {
}
}
@@ -0,0 +1,20 @@
open class A
class <caret>B: A {
// INFO: {"checked": "true"}
val n: Int
// INFO: {"checked": "true"}
val x: Int = 3
// INFO: {"checked": "false"}
val y: Int = 4
// INFO: {"checked": "true"}
val a: Int = 1
// INFO: {"checked": "true"}
val b: Int = x + y
constructor(p: Int) {
n = a + b - p
}
}
@@ -0,0 +1,20 @@
open class A {
// INFO: {"checked": "true"}
val n: Int
// INFO: {"checked": "true"}
val x: Int = 3
// INFO: {"checked": "true"}
val a: Int = 1
// INFO: {"checked": "true"}
val b: Int = x + y
}
class B: A {
// INFO: {"checked": "false"}
val y: Int = 4
constructor(p: Int) {
n = a + b - p
}
}
@@ -89,12 +89,36 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
doTest(fileName);
}
@TestMetadata("initializerInConstructor.kt")
public void testInitializerInConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/initializerInConstructor.kt");
doTest(fileName);
}
@TestMetadata("initializerInMultipleConstructorsEq.kt")
public void testInitializerInMultipleConstructorsEq() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/initializerInMultipleConstructorsEq.kt");
doTest(fileName);
}
@TestMetadata("initializerInMultipleConstructorsNonEq.kt")
public void testInitializerInMultipleConstructorsNonEq() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/initializerInMultipleConstructorsNonEq.kt");
doTest(fileName);
}
@TestMetadata("innerClassToInterface.kt")
public void testInnerClassToInterface() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/innerClassToInterface.kt");
doTest(fileName);
}
@TestMetadata("multipleInitializersInConstructorsEq.kt")
public void testMultipleInitializersInConstructorsEq() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/multipleInitializersInConstructorsEq.kt");
doTest(fileName);
}
@TestMetadata("noCaret.kt")
public void testNoCaret() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/noCaret.kt");
@@ -107,6 +131,12 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
doTest(fileName);
}
@TestMetadata("noInitializationInInterface.kt")
public void testNoInitializationInInterface() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/noInitializationInInterface.kt");
doTest(fileName);
}
@TestMetadata("noSuperClass.kt")
public void testNoSuperClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/noSuperClass.kt");
@@ -119,6 +149,24 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
doTest(fileName);
}
@TestMetadata("parametersInPrimaryInitializer.kt")
public void testParametersInPrimaryInitializer() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/parametersInPrimaryInitializer.kt");
doTest(fileName);
}
@TestMetadata("propertyDependenceSatisfied.kt")
public void testPropertyDependenceSatisfied() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/propertyDependenceSatisfied.kt");
doTest(fileName);
}
@TestMetadata("propertyDependenceUnsatisfied.kt")
public void testPropertyDependenceUnsatisfied() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/propertyDependenceUnsatisfied.kt");
doTest(fileName);
}
@TestMetadata("publicToInterface.kt")
public void testPublicToInterface() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/publicToInterface.kt");