Intentions: Move class member to companion object
#KT-9697 In Progress
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
companion object {
|
||||
<spot>fun foo() = 1</spot>
|
||||
}
|
||||
}
|
||||
|
||||
fun bar() = A.foo()
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
<spot>fun foo() = 1</spot>
|
||||
}
|
||||
|
||||
fun bar() = A().foo()
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention moves class member to the corresponding companion object.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1164,6 +1164,11 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||
displayName="Convert object literal to lambda"
|
||||
groupName="Kotlin"
|
||||
|
||||
+305
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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.codeInsight.CodeInsightUtilCore
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethodCallExpression
|
||||
import com.intellij.psi.PsiReferenceExpression
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.OuterInstanceReferenceUsageInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.collectOuterInstanceReferences
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.reportConflictIfAny
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.traverseOuterInstanceReferences
|
||||
import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
|
||||
class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java,
|
||||
"Move to companion object") {
|
||||
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
|
||||
if (element !is KtNamedFunction && element !is KtProperty && element !is KtClassOrObject) return null
|
||||
if (element is KtEnumEntry) return null
|
||||
if (element is KtNamedFunction && element.bodyExpression == null) return null
|
||||
if (element is KtNamedFunction && element.valueParameterList == null) return null
|
||||
if ((element is KtNamedFunction || element is KtProperty) && element.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return null
|
||||
if (element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null
|
||||
val containingClass = element.containingClassOrObject as? KtClass ?: return null
|
||||
if (containingClass.isLocal() || containingClass.isInner()) return null
|
||||
return element.nameIdentifier?.textRange
|
||||
}
|
||||
|
||||
class JavaUsageInfo(refExpression: PsiReferenceExpression) : UsageInfo(refExpression)
|
||||
|
||||
class ImplicitReceiverUsageInfo(refExpression: KtSimpleNameExpression, val callExpression: KtExpression) : UsageInfo(refExpression)
|
||||
class ExplicitReceiverUsageInfo(refExpression: KtSimpleNameExpression, val receiverExpression: KtExpression) : UsageInfo(refExpression)
|
||||
|
||||
private fun getNameSuggestionsForOuterInstance(element: KtNamedDeclaration): List<String> {
|
||||
val containingClass = element.containingClassOrObject as KtClass
|
||||
val containingClassDescriptor = containingClass.resolveToDescriptor() as ClassDescriptorWithResolutionScopes
|
||||
val companionDescriptor = containingClassDescriptor.companionObjectDescriptor
|
||||
val companionMemberScope = (companionDescriptor ?: containingClassDescriptor).scopeForMemberDeclarationResolution
|
||||
val validator = CollectingNameValidator(element.getValueParameters().mapNotNull { it.name }) {
|
||||
companionMemberScope.getContributedVariables(Name.guess(it), NoLookupLocation.FROM_IDE).isEmpty()
|
||||
}
|
||||
return KotlinNameSuggester.suggestNamesByType(containingClassDescriptor.defaultType, validator, "receiver")
|
||||
}
|
||||
|
||||
private fun runTemplateForInstanceParam(
|
||||
declaration: KtNamedDeclaration,
|
||||
nameSuggestions: List<String>,
|
||||
editor: Editor?
|
||||
) {
|
||||
if (nameSuggestions.isNotEmpty() && editor != null) {
|
||||
val restoredElement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(declaration)
|
||||
val restoredParam = restoredElement.getValueParameters().first()
|
||||
|
||||
val paramRefs = ReferencesSearch.search(restoredParam, LocalSearchScope(restoredElement)).toList()
|
||||
|
||||
editor.caretModel.moveToOffset(restoredElement.startOffset)
|
||||
|
||||
val templateBuilder = TemplateBuilderImpl(restoredElement)
|
||||
templateBuilder.replaceElement(restoredParam.nameIdentifier!!, "ParamName", ChooseStringExpression(nameSuggestions), true)
|
||||
paramRefs.forEach { templateBuilder.replaceElement(it, "ParamName", "ParamRef", false) }
|
||||
templateBuilder.run(editor, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveReceiverToArgumentList(refElement: PsiElement) {
|
||||
when (refElement) {
|
||||
is PsiReferenceExpression -> {
|
||||
val qualifier = refElement.qualifier
|
||||
val call = refElement.parent as? PsiMethodCallExpression
|
||||
if (call != null && qualifier != null) {
|
||||
val argumentList = call.argumentList
|
||||
argumentList.addBefore(qualifier, argumentList.expressions.firstOrNull())
|
||||
}
|
||||
}
|
||||
|
||||
is KtSimpleNameExpression -> {
|
||||
val call = refElement.parent as? KtCallExpression
|
||||
val receiver = call?.getQualifiedExpressionForSelector()?.receiverExpression
|
||||
if (call != null && receiver != null) {
|
||||
val psiFactory = KtPsiFactory(refElement)
|
||||
val argumentList = call.valueArgumentList
|
||||
?: call.addAfter(psiFactory.createCallArguments("()"), call.typeArgumentList ?: refElement) as KtValueArgumentList
|
||||
argumentList.addArgumentBefore(psiFactory.createArgument(receiver),
|
||||
argumentList.arguments.firstOrNull())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doMove(element: KtNamedDeclaration,
|
||||
externalUsages: SmartList<UsageInfo>,
|
||||
outerInstanceUsages: SmartList<UsageInfo>,
|
||||
editor: Editor?) {
|
||||
val project = element.project
|
||||
val containingClass = element.containingClassOrObject as KtClass
|
||||
|
||||
val javaCodeStyleManager = JavaCodeStyleManager.getInstance(project)
|
||||
|
||||
val companionObject = containingClass.getOrCreateCompanionObject()
|
||||
val companionLightClass = companionObject.toLightClass()!!
|
||||
|
||||
val ktPsiFactory = KtPsiFactory(project)
|
||||
val javaPsiFactory = JavaPsiFacade.getInstance(project).elementFactory
|
||||
val javaCompanionRef = javaPsiFactory.createReferenceExpression(companionLightClass)
|
||||
val ktCompanionRef = ktPsiFactory.createExpression(companionObject.fqName!!.asString())
|
||||
|
||||
val elementsToShorten = SmartList<KtElement>()
|
||||
|
||||
val nameSuggestions: List<String>
|
||||
if (outerInstanceUsages.isNotEmpty() && element is KtNamedFunction) {
|
||||
val parameterList = element.valueParameterList!!
|
||||
val parameters = parameterList.parameters
|
||||
|
||||
val newParamType = (containingClass.resolveToDescriptor() as ClassDescriptor).defaultType
|
||||
|
||||
nameSuggestions = getNameSuggestionsForOuterInstance(element)
|
||||
|
||||
val newParam = parameterList.addParameterBefore(
|
||||
ktPsiFactory.createParameter("${nameSuggestions.first()}: ${IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(newParamType)}"),
|
||||
parameters.firstOrNull()
|
||||
)
|
||||
|
||||
val newOuterInstanceRef = ktPsiFactory.createExpression(newParam.name!!)
|
||||
for (usage in outerInstanceUsages) {
|
||||
when (usage) {
|
||||
is OuterInstanceReferenceUsageInfo.ExplicitThis -> {
|
||||
usage.expression?.replace(newOuterInstanceRef)
|
||||
}
|
||||
|
||||
is OuterInstanceReferenceUsageInfo.ImplicitReceiver -> {
|
||||
usage.callElement?.let { it.replace(ktPsiFactory.createExpressionByPattern("$0.$1", newOuterInstanceRef, it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nameSuggestions = emptyList()
|
||||
}
|
||||
|
||||
element.removeModifier(KtTokens.OPEN_KEYWORD)
|
||||
element.removeModifier(KtTokens.FINAL_KEYWORD)
|
||||
|
||||
val newDeclaration = Mover.Default(element, companionObject)
|
||||
|
||||
for (usage in externalUsages) {
|
||||
val usageElement = usage.element ?: continue
|
||||
|
||||
if (nameSuggestions.isNotEmpty()) {
|
||||
moveReceiverToArgumentList(usageElement)
|
||||
}
|
||||
|
||||
when (usage) {
|
||||
is JavaUsageInfo -> {
|
||||
(usageElement as? PsiReferenceExpression)
|
||||
?.qualifierExpression
|
||||
?.replace(javaCompanionRef)
|
||||
?.let { javaCodeStyleManager.shortenClassReferences(it) }
|
||||
}
|
||||
|
||||
is ExplicitReceiverUsageInfo -> {
|
||||
elementsToShorten += usage.receiverExpression.replaced(ktCompanionRef)
|
||||
}
|
||||
|
||||
is ImplicitReceiverUsageInfo -> {
|
||||
usage.callExpression
|
||||
.let { it.replaced(ktPsiFactory.createExpressionByPattern("$0.$1", ktCompanionRef, it)) }
|
||||
.let { elementsToShorten += (it as KtQualifiedExpression).receiverExpression }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShortenReferences.DEFAULT.process(elementsToShorten)
|
||||
|
||||
runTemplateForInstanceParam(newDeclaration, nameSuggestions, editor)
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
|
||||
val project = element.project
|
||||
|
||||
if (element is KtClassOrObject) {
|
||||
val nameSuggestions = if (traverseOuterInstanceReferences(element, true)) getNameSuggestionsForOuterInstance(element) else emptyList()
|
||||
val outerInstanceName = nameSuggestions.firstOrNull()
|
||||
var movedClass: KtClassOrObject? = null
|
||||
val mover = object: Mover {
|
||||
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
|
||||
return Mover.Default(originalElement, targetContainer).apply { movedClass = this as KtClassOrObject }
|
||||
}
|
||||
}
|
||||
val moveDescriptor = MoveDeclarationsDescriptor(listOf(element),
|
||||
KotlinMoveTargetForCompanion(element.containingClassOrObject!! as KtClass),
|
||||
MoveDeclarationsDelegate.NestedClass(null, outerInstanceName),
|
||||
moveCallback = MoveCallback { runTemplateForInstanceParam(movedClass!!, nameSuggestions, editor) })
|
||||
MoveKotlinDeclarationsProcessor(project, moveDescriptor, mover).run()
|
||||
return
|
||||
}
|
||||
|
||||
if (HierarchySearchRequest(element, element.useScope, false).searchOverriders().any()) {
|
||||
val description = RefactoringUIUtil.getDescription(element, false).capitalize()
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, "$description is overridden by declaration(s) in a subclass", text, null)
|
||||
return
|
||||
}
|
||||
|
||||
val externalUsages = SmartList<UsageInfo>()
|
||||
val outerInstanceUsages = SmartList<UsageInfo>()
|
||||
val conflicts = MultiMap<PsiElement, String>()
|
||||
|
||||
val outerInstanceReferences = collectOuterInstanceReferences(element)
|
||||
if (outerInstanceReferences.isNotEmpty()) {
|
||||
if (element is KtProperty) {
|
||||
conflicts.putValue(element, "Usages of outer class instance inside of property '${element.name}' won't be processed")
|
||||
}
|
||||
else {
|
||||
outerInstanceReferences.filterNotTo(outerInstanceUsages) { it.reportConflictIfAny(conflicts) }
|
||||
}
|
||||
}
|
||||
|
||||
project.runSynchronouslyWithProgress("Searching for ${element.name}", true) {
|
||||
ReferencesSearch.search(element).mapNotNullTo(externalUsages) { ref ->
|
||||
when (ref) {
|
||||
is PsiReferenceExpression -> JavaUsageInfo(ref)
|
||||
is KtSimpleNameReference -> {
|
||||
val refExpr = ref.expression
|
||||
if (element.isAncestor(refExpr)) return@mapNotNullTo null
|
||||
val context = refExpr.analyze(BodyResolveMode.PARTIAL)
|
||||
val resolvedCall = refExpr.getResolvedCall(context) ?: return@mapNotNullTo null
|
||||
|
||||
val callExpression = resolvedCall.call.callElement as? KtExpression ?: return@mapNotNullTo null
|
||||
|
||||
val extensionReceiver = resolvedCall.extensionReceiver
|
||||
if (extensionReceiver != null && extensionReceiver !is ImplicitReceiver) {
|
||||
conflicts.putValue(callExpression,
|
||||
"Calls with explicit extension receiver won't be processed: ${callExpression.text}")
|
||||
return@mapNotNullTo null
|
||||
}
|
||||
|
||||
val dispatchReceiver = resolvedCall.dispatchReceiver ?: return@mapNotNullTo null
|
||||
if (dispatchReceiver is ExpressionReceiver) {
|
||||
ExplicitReceiverUsageInfo(refExpr, dispatchReceiver.expression)
|
||||
}
|
||||
else {
|
||||
ImplicitReceiverUsageInfo(refExpr, callExpression)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.checkConflictsInteractively(conflicts) {
|
||||
doMove(element, externalUsages, outerInstanceUsages, editor)
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -19,7 +19,10 @@ package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||
@@ -56,6 +59,18 @@ class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMo
|
||||
override fun verify(file: PsiFile): String? = null
|
||||
}
|
||||
|
||||
class KotlinMoveTargetForCompanion(val targetClass: KtClass): KotlinMoveTarget {
|
||||
override val targetContainerFqName = targetClass.getCompanionObjects().firstOrNull()?.fqName
|
||||
?: targetClass.fqName!!.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
|
||||
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetClass.getOrCreateCompanionObject()
|
||||
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetClass.getCompanionObjects().firstOrNull()
|
||||
|
||||
// No additional verification is needed
|
||||
override fun verify(file: PsiFile): String? = null
|
||||
}
|
||||
|
||||
class KotlinMoveTargetForDeferredFile(
|
||||
override val targetContainerFqName: FqName,
|
||||
override val directory: PsiDirectory?,
|
||||
|
||||
+27
-34
@@ -31,12 +31,15 @@ import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||
|
||||
sealed class MoveDeclarationsDelegate {
|
||||
abstract fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo
|
||||
abstract fun findUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo>
|
||||
abstract fun collectConflicts(usages: MutableList<UsageInfo>, conflicts: MultiMap<PsiElement, String>)
|
||||
abstract fun collectConflicts(
|
||||
descriptor: MoveDeclarationsDescriptor,
|
||||
usages: MutableList<UsageInfo>,
|
||||
conflicts: MultiMap<PsiElement, String>
|
||||
)
|
||||
abstract fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration)
|
||||
abstract fun preprocessUsages(project: Project, usages: List<UsageInfo>)
|
||||
|
||||
@@ -48,7 +51,11 @@ sealed class MoveDeclarationsDelegate {
|
||||
|
||||
override fun findUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> = emptyList()
|
||||
|
||||
override fun collectConflicts(usages: MutableList<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
|
||||
override fun collectConflicts(
|
||||
descriptor: MoveDeclarationsDescriptor,
|
||||
usages: MutableList<UsageInfo>,
|
||||
conflicts: MultiMap<PsiElement, String>
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
@@ -81,44 +88,30 @@ sealed class MoveDeclarationsDelegate {
|
||||
return collectOuterInstanceReferences(classToMove)
|
||||
}
|
||||
|
||||
override fun collectConflicts(usages: MutableList<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
|
||||
override fun collectConflicts(
|
||||
descriptor: MoveDeclarationsDescriptor,
|
||||
usages: MutableList<UsageInfo>,
|
||||
conflicts: MultiMap<PsiElement, String>
|
||||
) {
|
||||
val usageIterator = usages.iterator()
|
||||
while (usageIterator.hasNext()) {
|
||||
val usage = usageIterator.next();
|
||||
val element = usage.element ?: continue
|
||||
|
||||
if (usage is ImplicitCompanionAsDispatchReceiverUsageInfo) {
|
||||
conflicts.putValue(element, "Implicit companion object will be inaccessible: ${element.text}")
|
||||
usageIterator.remove()
|
||||
continue
|
||||
}
|
||||
|
||||
if (usage !is OuterInstanceReferenceUsageInfo) continue
|
||||
|
||||
if (usage.isIndirectOuter) {
|
||||
conflicts.putValue(element, "Indirect outer instances won't be extracted: ${element.text}")
|
||||
usageIterator.remove()
|
||||
}
|
||||
|
||||
if (usage !is OuterInstanceReferenceUsageInfo.ImplicitReceiver) continue
|
||||
|
||||
val fullCall = usage.callElement?.let { it.getQualifiedExpressionForSelector() ?: it } ?: continue
|
||||
when {
|
||||
fullCall is KtQualifiedExpression -> {
|
||||
conflicts.putValue(
|
||||
fullCall,
|
||||
"Qualified call won't be processed: ${fullCall.text}"
|
||||
)
|
||||
usageIterator.remove()
|
||||
val isConflict = when (usage) {
|
||||
is ImplicitCompanionAsDispatchReceiverUsageInfo -> {
|
||||
if (descriptor.moveTarget !is KotlinMoveTargetForCompanion) {
|
||||
conflicts.putValue(element, "Implicit companion object will be inaccessible: ${element.text}")
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
usage.isDoubleReceiver -> {
|
||||
conflicts.putValue(
|
||||
fullCall,
|
||||
"Call with two implicit receivers won't be processed: ${fullCall.text}"
|
||||
)
|
||||
usageIterator.remove()
|
||||
}
|
||||
is OuterInstanceReferenceUsageInfo -> usage.reportConflictIfAny(conflicts)
|
||||
|
||||
else -> false
|
||||
}
|
||||
if (isConflict) {
|
||||
usageIterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -318,10 +318,10 @@ class MoveKotlinDeclarationsProcessor(
|
||||
collectUsages(kotlinToLightElements, usages)
|
||||
checkVisibilityInUsages(usages)
|
||||
checkVisibilityInDeclarations()
|
||||
descriptor.delegate.collectConflicts(usages, conflicts)
|
||||
descriptor.delegate.collectConflicts(descriptor, usages, conflicts)
|
||||
}
|
||||
|
||||
descriptor.delegate.collectConflicts(usagesToProcessBeforeMove, conflicts)
|
||||
descriptor.delegate.collectConflicts(descriptor, usagesToProcessBeforeMove, conflicts)
|
||||
|
||||
return UsageViewUtil.removeDuplicatedUsages(usages.toTypedArray())
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ import com.intellij.refactoring.util.NonCodeUsageInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.codeInsight.KotlinFileReferencesResolver
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
@@ -453,14 +453,14 @@ sealed class OuterInstanceReferenceUsageInfo(element: PsiElement, val isIndirect
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun traverseOuterInstanceReferences(innerClass: KtClass, stopAtFirst: Boolean, body: (OuterInstanceReferenceUsageInfo) -> Unit = {}): Boolean {
|
||||
if (!innerClass.isInner()) return false
|
||||
fun traverseOuterInstanceReferences(member: KtNamedDeclaration, stopAtFirst: Boolean, body: (OuterInstanceReferenceUsageInfo) -> Unit = {}): Boolean {
|
||||
if (member is KtObjectDeclaration || member is KtClass && !member.isInner()) return false
|
||||
|
||||
val context = innerClass.analyzeFully()
|
||||
val innerClassDescriptor = innerClass.resolveToDescriptorIfAny() as? ClassDescriptor ?: return false
|
||||
val outerClassDescriptor = innerClassDescriptor.containingDeclaration as? ClassDescriptor ?: return false
|
||||
val context = member.analyzeFully()
|
||||
val containingClassOrObject = member.containingClassOrObject ?: return false
|
||||
val outerClassDescriptor = containingClassOrObject.resolveToDescriptor() as ClassDescriptor
|
||||
var found = false
|
||||
innerClass.accept(
|
||||
member.accept(
|
||||
object : PsiRecursiveElementWalkingVisitor() {
|
||||
private fun getOuterInstanceReference(element: PsiElement): OuterInstanceReferenceUsageInfo? {
|
||||
return when (element) {
|
||||
@@ -512,6 +512,31 @@ fun traverseOuterInstanceReferences(innerClass: KtClass, stopAtFirst: Boolean, b
|
||||
return found
|
||||
}
|
||||
|
||||
fun collectOuterInstanceReferences(innerClass: KtClass): List<OuterInstanceReferenceUsageInfo> {
|
||||
return SmartList<OuterInstanceReferenceUsageInfo>().apply { traverseOuterInstanceReferences(innerClass, false) { add(it) } }
|
||||
fun collectOuterInstanceReferences(member: KtNamedDeclaration): List<OuterInstanceReferenceUsageInfo> {
|
||||
return SmartList<OuterInstanceReferenceUsageInfo>().apply { traverseOuterInstanceReferences(member, false) { add(it) } }
|
||||
}
|
||||
|
||||
fun OuterInstanceReferenceUsageInfo.reportConflictIfAny(conflicts: MultiMap<PsiElement, String>): Boolean {
|
||||
val element = element ?: return false
|
||||
|
||||
if (isIndirectOuter) {
|
||||
conflicts.putValue(element, "Indirect outer instances won't be extracted: ${element.text}")
|
||||
return true
|
||||
}
|
||||
|
||||
if (this !is OuterInstanceReferenceUsageInfo.ImplicitReceiver) return false
|
||||
|
||||
val fullCall = callElement?.let { it.getQualifiedExpressionForSelector() ?: it } ?: return false
|
||||
return when {
|
||||
fullCall is KtQualifiedExpression -> {
|
||||
conflicts.putValue(fullCall, "Qualified call won't be processed: ${fullCall.text}")
|
||||
true
|
||||
}
|
||||
|
||||
isDoubleReceiver -> {
|
||||
conflicts.putValue(fullCall, "Call with two implicit receivers won't be processed: ${fullCall.text}")
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
abstract class A {
|
||||
abstract fun <caret>foo()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
abstract class A {
|
||||
abstract val <caret>foo: Int
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
final fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
companion object {
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
open class A {
|
||||
open fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
open class A {
|
||||
companion object {
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
enum class E {
|
||||
A,
|
||||
<caret>B,
|
||||
C
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
class B: A {
|
||||
override fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
interface A {
|
||||
fun <caret>foo()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
class A {
|
||||
inner class B {
|
||||
fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun foo() {
|
||||
class A {
|
||||
fun <caret>bar() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
object A {
|
||||
fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun foo() {
|
||||
fun <caret>bar() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// SHOULD_FAIL_WITH: Function <b><code>foo</code></b> is overridden by declaration(s) in a subclass
|
||||
open class A {
|
||||
open fun <caret>foo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class B: A() {
|
||||
override fun foo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// SHOULD_FAIL_WITH: Property <b><code>foo</code></b> is overridden by declaration(s) in a subclass
|
||||
open class A {
|
||||
open val <caret>foo: Int = 1
|
||||
}
|
||||
|
||||
class B: A() {
|
||||
override val foo: Int = 2
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// SHOULD_FAIL_WITH: Usages of outer class instance inside of property 'y' won't be processed
|
||||
class A {
|
||||
val x = 1
|
||||
val <caret>y = x + 1
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
interface A {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
class B: A {
|
||||
override val <caret>foo: Int = 1
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun <caret>foo() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
fun test(a: A, n: Int) {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
a.OuterY()
|
||||
a.outerFoo(a.outerBar)
|
||||
|
||||
a.OuterY()
|
||||
a.outerFoo(a.outerBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
void foo() {
|
||||
A.Companion.test(new A(), 1);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo() {
|
||||
A.test(A(), 1)
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
fun <caret>test(n: Int) {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
OuterY()
|
||||
outerFoo(outerBar)
|
||||
|
||||
this.OuterY()
|
||||
this.outerFoo(this@A.outerBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
void foo() {
|
||||
new A().test(1);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo() {
|
||||
A().test(1)
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention"
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
|
||||
class B(private val a: A) {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
a.OuterY()
|
||||
a.outerFoo(a.outerBar)
|
||||
|
||||
a.OuterY()
|
||||
a.outerFoo(a.outerBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.Companion.B foo() {
|
||||
return new A.Companion.B(new A());
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.A.Companion.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new B(new A());
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.Companion.B {
|
||||
return A.Companion.B(A())
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.Companion.B
|
||||
|
||||
fun foo2(): B {
|
||||
return B(A())
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
inner class <caret>B {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
OuterY()
|
||||
outerFoo(outerBar)
|
||||
|
||||
this@A.OuterY()
|
||||
this@A.outerFoo(this@A.outerBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B {
|
||||
return A().B()
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B
|
||||
|
||||
fun foo2(): B {
|
||||
return A().B()
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention"
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
|
||||
class B {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.Companion.B foo() {
|
||||
return new A.Companion.B();
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.Companion.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new B();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.Companion.B {
|
||||
return A.Companion.B()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.Companion.B
|
||||
|
||||
fun foo(): B {
|
||||
return B()
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
class <caret>B {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B foo() {
|
||||
return new A.B();
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new B();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B {
|
||||
return A.B()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.B
|
||||
|
||||
fun foo(): B {
|
||||
return B()
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention"
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
var test: Int
|
||||
get() = 1
|
||||
set(value: Int) {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
void foo() {
|
||||
int x = A.Companion.getTest();
|
||||
A.Companion.setTest(1);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo() {
|
||||
val x = A.test
|
||||
A.test = 1
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
var <caret>test: Int
|
||||
get() = 1
|
||||
set(value: Int) {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
void foo() {
|
||||
int x = new A().getTest();
|
||||
new A().setTest(1);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo() {
|
||||
val x = A().test
|
||||
A().test = 1
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.intentions.MoveMemberToCompanionObjectIntention"
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// "Delete redundant extension property" "false"
|
||||
// ACTION: Convert property to function
|
||||
// ACTION: Move to companion object
|
||||
|
||||
class C : Thread() {
|
||||
val Thread.<caret>priority: Int
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// "Delete redundant extension property" "false"
|
||||
// ACTION: Move to companion object
|
||||
|
||||
class C : Thread() {
|
||||
var Thread.<caret>priority: Int
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// "Specify type explicitly" "false"
|
||||
// ACTION: Convert property to function
|
||||
// ACTION: Introduce backing property
|
||||
// ACTION: Move to companion object
|
||||
// ERROR: Unresolved reference: foo
|
||||
|
||||
class A() {
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
@@ -190,6 +191,9 @@ public abstract class AbstractIntentionTest extends KotlinCodeInsightTestCase {
|
||||
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
|
||||
assertEquals("Failure message mismatch.", shouldFailString, StringUtil.join(e.getMessages(), ", "));
|
||||
}
|
||||
catch (CommonRefactoringUtil.RefactoringErrorHintException e) {
|
||||
assertEquals("Failure message mismatch.", shouldFailString, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6530,6 +6530,162 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/moveOutOfCompanion")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class MoveOutOfCompanion extends AbstractIntentionTest {
|
||||
public void testAllFilesPresentInMoveOutOfCompanion() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/moveOutOfCompanion"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("moveAndDropCompanion.kt")
|
||||
public void testMoveAndDropCompanion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/moveAndDropCompanion.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveFunction.kt")
|
||||
public void testMoveFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/moveFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveFunctionWithExternalRefs.kt")
|
||||
public void testMoveFunctionWithExternalRefs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/moveFunctionWithExternalRefs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveProperty.kt")
|
||||
public void testMoveProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/moveProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("movePropertyWithExternalRefs.kt")
|
||||
public void testMovePropertyWithExternalRefs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/movePropertyWithExternalRefs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("notCompanion1.kt")
|
||||
public void testNotCompanion1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/notCompanion1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("notCompanion2.kt")
|
||||
public void testNotCompanion2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveOutOfCompanion/notCompanion2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/moveToCompanion")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class MoveToCompanion extends AbstractIntentionTest {
|
||||
@TestMetadata("abstractFunction.kt")
|
||||
public void testAbstractFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/abstractFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("abstractProperty.kt")
|
||||
public void testAbstractProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/abstractProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInMoveToCompanion() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/moveToCompanion"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("dropFinal.kt")
|
||||
public void testDropFinal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/dropFinal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dropOpen.kt")
|
||||
public void testDropOpen() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/dropOpen.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("enumEntry.kt")
|
||||
public void testEnumEntry() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/enumEntry.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionWithOverride.kt")
|
||||
public void testFunctionWithOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/functionWithOverride.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionWithoutBody.kt")
|
||||
public void testFunctionWithoutBody() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/functionWithoutBody.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inInnerClass.kt")
|
||||
public void testInInnerClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/inInnerClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inLocalClass.kt")
|
||||
public void testInLocalClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/inLocalClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inObject.kt")
|
||||
public void testInObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/inObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localFunction.kt")
|
||||
public void testLocalFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/localFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("overriddenFunction.kt")
|
||||
public void testOverriddenFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/overriddenFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("overriddenProperty.kt")
|
||||
public void testOverriddenProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/overriddenProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyUsingClassInstance.kt")
|
||||
public void testPropertyUsingClassInstance() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/propertyUsingClassInstance.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyWithOverride.kt")
|
||||
public void testPropertyWithOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/propertyWithOverride.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFunction.kt")
|
||||
public void testTopLevelFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/topLevelFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/objectLiteralToLambda")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -101,6 +101,36 @@ public class MultiFileIntentionTestGenerated extends AbstractMultiFileIntentionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveOutOfCompanion/moveClass/moveClass.test")
|
||||
public void testMoveOutOfCompanion_moveClass_MoveClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/moveOutOfCompanion/moveClass/moveClass.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveToCompanion/moveFunction/moveFunction.test")
|
||||
public void testMoveToCompanion_moveFunction_MoveFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/moveToCompanion/moveFunction/moveFunction.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveToCompanion/moveInnerClass/moveInnerClass.test")
|
||||
public void testMoveToCompanion_moveInnerClass_MoveInnerClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/moveToCompanion/moveInnerClass/moveInnerClass.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveToCompanion/moveNonInnerClass/moveNonInnerClass.test")
|
||||
public void testMoveToCompanion_moveNonInnerClass_MoveNonInnerClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/moveToCompanion/moveNonInnerClass/moveNonInnerClass.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("moveToCompanion/moveProperty/moveProperty.test")
|
||||
public void testMoveToCompanion_moveProperty_MoveProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/moveToCompanion/moveProperty/moveProperty.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("objectLiteralToLambda/objectLiteralToLambda.test")
|
||||
public void testObjectLiteralToLambda_ObjectLiteralToLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileIntentions/objectLiteralToLambda/objectLiteralToLambda.test");
|
||||
|
||||
Reference in New Issue
Block a user