diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedFunction.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedFunction.java index f8dc08d1a36..c5b3a5221c8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedFunction.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedFunction.java @@ -77,6 +77,13 @@ public class JetNamedFunction extends JetTypeParameterListOwnerStub( val element: T, - private val scope: SearchScope, + private val scope: SearchScope = element.getUseScope(), val location: UsagesSearchLocation = UsagesSearchLocation.DEFAULT, val restrictByTargetScope: Boolean = true ) { diff --git a/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/after.kt.template new file mode 100644 index 00000000000..4d33e1d3807 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/after.kt.template @@ -0,0 +1,7 @@ +class A(val n: Int) { + val foo: Int get() = n + 1 +} + +fun test() { + val k = A(1).foo +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/before.kt.template new file mode 100644 index 00000000000..146003c6b6a --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/before.kt.template @@ -0,0 +1,7 @@ +class A(val n: Int) { + fun foo(): Int = n + 1 +} + +fun test() { + val k = A(1).foo() +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/description.html b/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/description.html new file mode 100644 index 00000000000..90bad99cee1 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertFunctionToPropertyIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts function to property. + + \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/after.kt.template new file mode 100644 index 00000000000..146003c6b6a --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/after.kt.template @@ -0,0 +1,7 @@ +class A(val n: Int) { + fun foo(): Int = n + 1 +} + +fun test() { + val k = A(1).foo() +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/before.kt.template new file mode 100644 index 00000000000..4d33e1d3807 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/before.kt.template @@ -0,0 +1,7 @@ +class A(val n: Int) { + val foo: Int get() = n + 1 +} + +fun test() { + val k = A(1).foo +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/description.html b/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/description.html new file mode 100644 index 00000000000..d1f4dbc9874 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertPropertyToFunctionIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts property to function + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 31564220e78..5ab0ab9b1e0 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -793,6 +793,16 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention + Kotlin + + + + org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention + Kotlin + + ( + "convert.function.to.property.intention", javaClass() +) { + class object { + private var JetNamedFunction.typeFqNameToAdd: String? by UserDataProperty(Key.create("TYPE_FQ_NAME_TO_ADD")) + } + + private inner class Convertor( + project: Project, + descriptor: CallableDescriptor, + context: BindingContext): CallableRefactoring(project, descriptor, context, getText()) { + private val elementsToShorten = ArrayList() + + private fun convertJetFunction(originalFunction: JetNamedFunction, psiFactory: JetPsiFactory) { + val function = originalFunction.copy() as JetNamedFunction + + val propertySample = psiFactory.createProperty("val foo: Int get() = 1") + + val needsExplicitType = function.getTypeReference() == null + if (needsExplicitType) { + originalFunction.typeFqNameToAdd?.let { function.setTypeReference(psiFactory.createType(it)) } + } + + function.getFunToken().replace(propertySample.getValOrVarNode().getPsi()) + function.getValueParameterList()?.delete() + val insertAfter = (function.getEqualsToken() ?: function.getBodyExpression()) + ?.siblings(forward = false, withItself = false) + ?.firstOrNull { it !is PsiWhiteSpace } + if (insertAfter != null) { + function.addAfter(psiFactory.createParameterList("()"), insertAfter) + function.addAfter(propertySample.getGetter().getNamePlaceholder(), insertAfter) + function.addAfter(psiFactory.createNewLine(), insertAfter) + } + + val property = originalFunction.replace(psiFactory.createProperty(function.getText())) as JetProperty + if (needsExplicitType) { + elementsToShorten.add(property.getTypeReference()) + } + } + + override fun performRefactoring(descriptorsForChange: Collection) { + val conflicts = MultiMap() + val getterName = PropertyCodegen.getterName(callableDescriptor.getName()) + val callables = getAffectedCallables(project, descriptorsForChange) + val kotlinCalls = ArrayList() + val foreignRefs = ArrayList() + for (callable in callables) { + if (callable !is PsiNamedElement) continue + + if (!checkModifiable(callable)) { + reportDeclarationConflict(conflicts, callable) { "Can't modify $it" } + } + + if (callable is JetNamedFunction) { + if (callable.getTypeReference() == null) { + val type = (callable.resolveToDescriptor() as FunctionDescriptor).getReturnType() + val typeToInsert = when { + type == null || type.isError() -> null + type.getConstructor().isDenotable() -> type + else -> type.supertypes().firstOrNull { it.getConstructor().isDenotable() } + } ?: KotlinBuiltIns.getInstance().getNullableAnyType() + callable.typeFqNameToAdd = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeToInsert) + } + + callableDescriptor.getContainingScope(bindingContext) + ?.getProperties(callableDescriptor.getName()) + ?.firstOrNull() + ?.let { DescriptorToDeclarationUtil.getDeclaration(project, it) } + ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } + } + + if (callable is PsiMethod) { + callable.getContainingClass() + ?.findMethodsByName(getterName, true) + ?.firstOrNull { it.getParameterList().getParametersCount() == 0 && it.namedUnwrappedElement !in callables } + ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } + } + + val usages = DefaultSearchHelper().newRequest(UsagesSearchTarget(callable)).search() + for (usage in usages) { + if (usage is JetSimpleNameReference) { + val callElement = usage.expression.getParentOfTypeAndBranch { getCalleeExpression() } + if (callElement != null) { + if (callElement.getTypeArguments().isNotEmpty()) { + conflicts.putValue( + callElement, + "Type arguments will be lost after conversion: ${StringUtil.htmlEmphasize(callElement.getText())}" + ) + } + + if (callElement.getValueArguments().isNotEmpty()) { + conflicts.putValue( + callElement, + "Call with arguments will be skipped: ${StringUtil.htmlEmphasize(callElement.getText())}" + ) + continue + } + + kotlinCalls.add(callElement) + continue + } + } + else { + foreignRefs.add(usage) + } + } + } + + project.checkConflictsInteractively(conflicts) { + project.executeWriteCommand(getText()) { + val psiFactory = JetPsiFactory(project) + + callables.forEach { + when (it) { + is JetNamedFunction -> convertJetFunction(it, psiFactory) + is PsiMethod -> it.setName(getterName) + } + } + kotlinCalls.forEach { it.replace(it.getCalleeExpression()) } + foreignRefs.forEach { it.handleElementRename(getterName) } + + ShortenReferences.process(elementsToShorten) + } + } + } + } + + override fun startInWriteAction(): Boolean = false + + override fun isApplicableTo(element: JetNamedFunction): Boolean { + throw IllegalStateException("isApplicableTo(JetExpressionImpl, Editor) should be called instead") + } + + override fun isApplicableTo(element: JetNamedFunction, editor: Editor): Boolean { + val elementAtCaret = element.getContainingFile().findElementAt(editor.getCaretModel().getOffset()) + if (!(element.getNameIdentifier()?.isAncestor(elementAtCaret) ?: false)) return false + + if (element.getValueParameters().isNotEmpty() || element.isLocal()) return false + + val name = element.getName() + when { + name == "invoke", + name == "iterator", + OperatorConventions.UNARY_OPERATION_NAMES.inverse().containsKey(Name.identifier(name)) -> return false + } + + val descriptor = element.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? FunctionDescriptor ?: return false + val returnType = descriptor.getReturnType() + return !(KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) + } + + override fun applyTo(element: JetNamedFunction, editor: Editor) { + val context = element.analyze() + val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? CallableDescriptor ?: return + Convertor(element.getProject(), descriptor, context).run() + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertPropertyToFunctionIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertPropertyToFunctionIntention.kt new file mode 100644 index 00000000000..738b25bc4d2 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertPropertyToFunctionIntention.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2010-2015 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 org.jetbrains.kotlin.psi.JetProperty +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.refactoring.CallableRefactoring +import org.jetbrains.kotlin.psi.JetPsiFactory +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.psi.psiUtil.siblings +import com.intellij.util.containers.MultiMap +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.refactoring.getAffectedCallables +import java.util.ArrayList +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiNamedElement +import com.intellij.refactoring.util.RefactoringUIUtil +import org.jetbrains.kotlin.idea.search.usagesSearch.DefaultSearchHelper +import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchTarget +import org.jetbrains.kotlin.idea.search.usagesSearch.search +import org.jetbrains.kotlin.idea.references.JetSimpleNameReference +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.resolve.calls.callUtil.getCall +import org.jetbrains.kotlin.psi.JetSimpleNameExpression +import org.jetbrains.kotlin.idea.references.JetReference +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiField +import com.intellij.psi.PsiReferenceExpression +import com.intellij.psi.PsiElementFactory +import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand +import org.jetbrains.kotlin.psi.JetCallableReferenceExpression +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import com.intellij.psi.PsiJavaReference +import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.kotlin.psi.JetExpressionImpl +import org.jetbrains.kotlin.codegen.PropertyCodegen +import org.jetbrains.kotlin.asJava.namedUnwrappedElement +import org.jetbrains.kotlin.idea.refactoring.reportDeclarationConflict +import org.jetbrains.kotlin.idea.refactoring.getContainingScope +import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil + +public class ConvertPropertyToFunctionIntention : JetSelfTargetingIntention( + "convert.property.to.function.intention", javaClass() +) { + private inner class Convertor( + project: Project, + descriptor: CallableDescriptor, + context: BindingContext): CallableRefactoring(project, descriptor, context, getText()) { + private fun convertJetProperty(originalProperty: JetProperty, psiFactory: JetPsiFactory) { + val property = originalProperty.copy() as JetProperty; + val getter = property.getGetter(); + + val sampleFunction = psiFactory.createFunction("fun foo() {\n\n}"); + + property.getValOrVarNode().getPsi().replace(sampleFunction.getFunToken()); + property.addAfter(psiFactory.createParameterList("()"), property.getNameIdentifier()); + if (property.getInitializer() == null) { + if (getter != null) { + val dropGetterTo = (getter.getEqualsToken() ?: getter.getBodyExpression()) + ?.siblings(forward = false, withItself = false) + ?.firstOrNull { it !is PsiWhiteSpace } + getter.deleteChildRange(getter.getFirstChild(), dropGetterTo) + + val dropPropertyFrom = getter + .siblings(forward = false, withItself = false) + .first { it !is PsiWhiteSpace } + .getNextSibling() + property.deleteChildRange(dropPropertyFrom, getter.getPrevSibling()) + } + } + originalProperty.replace(psiFactory.createFunction(property.getText())) + } + + override fun performRefactoring(descriptorsForChange: Collection) { + val propertyName = callableDescriptor.getName().asString() + val getterName = PropertyCodegen.getterName(callableDescriptor.getName()) + val conflicts = MultiMap() + val callables = getAffectedCallables(project, descriptorsForChange) + val kotlinRefs = ArrayList() + val foreignRefsToRename = ArrayList() + val javaRefsToReplaceWithCall = ArrayList() + for (callable in callables) { + if (callable !is PsiNamedElement) continue + + if (!checkModifiable(callable)) { + val renderedCallable = RefactoringUIUtil.getDescription(callable, true).capitalize() + conflicts.putValue(callable, "Can't modify $renderedCallable") + } + + if (callable is JetProperty) { + callableDescriptor.getContainingScope(bindingContext) + ?.getFunctions(callableDescriptor.getName()) + ?.firstOrNull { it.getValueParameters().isEmpty() } + ?.let { DescriptorToDeclarationUtil.getDeclaration(project, it) } + ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } + } + else if (callable is PsiMethod) { + callable.getContainingClass() + ?.findMethodsByName(propertyName, true) + ?.firstOrNull { it.getParameterList().getParametersCount() == 0 && it.namedUnwrappedElement !in callables } + ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } + } + + val usages = DefaultSearchHelper().newRequest(UsagesSearchTarget(callable)).search() + for (usage in usages) { + if (usage is JetReference) { + if (usage is JetSimpleNameReference) { + val expression = usage.expression + if (expression.getCall(expression.analyze()) != null + && expression.getStrictParentOfType() == null) { + kotlinRefs.add(expression) + } + } + else { + val refElement = usage.getElement() + conflicts.putValue( + refElement, + "Unrecognized reference will be skipped: ${StringUtil.htmlEmphasize(refElement.getText())}" + ) + } + continue + } + + val refElement = usage.getElement() + + if (refElement.getText().endsWith(getterName)) { + foreignRefsToRename.add(usage) + continue + } + + if (usage is PsiJavaReference) { + if (usage.resolve() is PsiField && usage is PsiReferenceExpression) { + javaRefsToReplaceWithCall.add(usage) + } + continue + } + + conflicts.putValue( + refElement, + "Can't replace foreign reference with call expression: ${StringUtil.htmlEmphasize(refElement.getText())}" + ) + } + } + + project.checkConflictsInteractively(conflicts) { + project.executeWriteCommand(getText()) { + val kotlinPsiFactory = JetPsiFactory(project) + val javaPsiFactory = PsiElementFactory.SERVICE.getInstance(project) + + callables.forEach { + when (it) { + is JetProperty -> convertJetProperty(it, kotlinPsiFactory) + is PsiMethod -> it.setName(propertyName) + } + } + kotlinRefs.forEach { it.replace(kotlinPsiFactory.createExpression("${it.getText()}()")) } + foreignRefsToRename.forEach { it.handleElementRename(propertyName) } + javaRefsToReplaceWithCall.forEach { it.replace(javaPsiFactory.createExpressionFromText("${it.getText()}()", null)) } + } + } + } + } + + override fun startInWriteAction(): Boolean = false + + override fun isApplicableTo(element: JetProperty): Boolean { + throw IllegalStateException("isApplicableTo(JetExpressionImpl, Editor) should be called instead") + } + + override fun isApplicableTo(element: JetProperty, editor: Editor): Boolean { + val elementAtCaret = element.getContainingFile().findElementAt(editor.getCaretModel().getOffset()) + if (!(element.getNameIdentifier()?.isAncestor(elementAtCaret) ?: false)) return false + + return element.getDelegate() == null && !element.isVar() && !element.isLocal() + } + + override fun applyTo(element: JetProperty, editor: Editor) { + val context = element.analyze() + val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? CallableDescriptor ?: return + Convertor(element.getProject(), descriptor, context).run() + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/CallableRefactoring.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/CallableRefactoring.kt index 42d8c0d77ed..8b40e19156b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/CallableRefactoring.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/CallableRefactoring.kt @@ -36,20 +36,21 @@ import org.jetbrains.kotlin.idea.JetBundle import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.psi.JetDeclaration import java.util.HashSet -import com.intellij.usageView.UsageInfo -import org.jetbrains.kotlin.psi.JetNamedFunction -import org.jetbrains.kotlin.asJava.LightClassUtil import com.intellij.psi.search.searches.OverridingMethodsSearch -import org.jetbrains.kotlin.asJava.KotlinLightMethod -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.JetFunctionDefinitionUsage -import com.intellij.refactoring.changeSignature.OverriderUsageInfo import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.namedUnwrappedElement +import org.jetbrains.kotlin.psi.JetCallableDeclaration +import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.psi.JetDeclarationWithBody +import org.jetbrains.kotlin.psi.JetExpression +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.JetDeclaration public abstract class CallableRefactoring( val project: Project, @@ -167,4 +168,31 @@ public abstract class CallableRefactoring( } } } +} + +fun getAffectedCallables(project: Project, descriptorsForChange: Collection): List { + val baseCallables = descriptorsForChange.map { DescriptorToDeclarationUtil.getDeclaration(project, it) }.filterNotNull() + return baseCallables + baseCallables.flatMap { it.toLightMethods() }.flatMapTo(HashSet()) { psiMethod -> + val overrides = OverridingMethodsSearch.search(psiMethod).findAll() + overrides.map { method -> method.namedUnwrappedElement ?: method} + } +} + +fun DeclarationDescriptor.getContainingScope(bindingContext: BindingContext): JetScope? { + val containingDescriptor = getContainingDeclaration() ?: return null + return when (containingDescriptor) { + is ClassDescriptorWithResolutionScopes -> containingDescriptor.getScopeForInitializerResolution() + is FunctionDescriptor -> { + (DescriptorToSourceUtils.descriptorToDeclaration(containingDescriptor) as? JetDeclarationWithBody)?.let { + it.getBodyScope(bindingContext) + } + } + is PackageFragmentDescriptor -> containingDescriptor.getMemberScope() + else -> null + } +} + +fun JetDeclarationWithBody.getBodyScope(bindingContext: BindingContext): JetScope? { + val expression = getBodyExpression()?.getChildren()?.firstOrNull { it is JetExpression } as JetExpression? + return expression?.let { bindingContext[BindingContext.RESOLUTION_SCOPE, it] } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java index cbde0824d92..195a9d33a41 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -35,7 +35,6 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.refactoring.RefactoringPackage; import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*; @@ -210,9 +209,9 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro if (oldDescriptor instanceof ConstructorDescriptor && containingDeclaration instanceof ClassDescriptorWithResolutionScopes) parametersScope = ((ClassDescriptorWithResolutionScopes) containingDeclaration).getScopeForInitializerResolution(); else if (function instanceof JetFunction) - parametersScope = getFunctionBodyScope((JetFunction) function, bindingContext); + parametersScope = RefactoringPackage.getBodyScope((JetFunction) function, bindingContext); - JetScope functionScope = getFunctionScope(bindingContext, containingDeclaration); + JetScope functionScope = RefactoringPackage.getContainingScope(oldDescriptor, bindingContext); if (!ChangeSignaturePackage.getIsConstructor(changeInfo) && functionScope != null && !info.getNewName().isEmpty()) { for (FunctionDescriptor conflict : functionScope.getFunctions(Name.identifier(info.getNewName()))) { @@ -260,36 +259,6 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro return result; } - @Nullable - private static JetScope getFunctionScope(BindingContext bindingContext, DeclarationDescriptor containingDeclaration) { - if (containingDeclaration instanceof ClassDescriptorWithResolutionScopes) - return ((ClassDescriptorWithResolutionScopes) containingDeclaration).getScopeForInitializerResolution(); - else if (containingDeclaration instanceof FunctionDescriptorImpl) { - PsiElement container = DescriptorToSourceUtils.descriptorToDeclaration(containingDeclaration); - - if (container instanceof JetFunction) - return getFunctionBodyScope((JetFunction) container, bindingContext); - } - else if (containingDeclaration instanceof PackageFragmentDescriptor) - return ((PackageFragmentDescriptor) containingDeclaration).getMemberScope(); - - return null; - } - - @Nullable - static JetScope getFunctionBodyScope(JetFunction element, BindingContext bindingContext) { - JetExpression body = element.getBodyExpression(); - - if (body != null) { - for (PsiElement child : body.getChildren()) { - if (child instanceof JetExpression) - return bindingContext.get(BindingContext.RESOLUTION_SCOPE, (JetExpression)child); - } - } - - return null; - } - private static List getFunctionParameterTypes(FunctionDescriptor descriptor) { return ContainerUtil.map(descriptor.getValueParameters(), new Function() { @Override diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt index ebcac3c8936..ab693909d4f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt @@ -74,6 +74,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import com.intellij.psi.PsiPackage import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.psi.psiUtil.parents +import com.intellij.refactoring.util.RefactoringUIUtil fun PsiElement.getAndRemoveCopyableUserData(key: Key): T? { val data = getCopyableUserData(key) @@ -181,6 +182,14 @@ public fun Project.checkConflictsInteractively(conflicts: MultiMap, + declaration: PsiElement, + message: (renderedDeclaration: String) -> String +) { + conflicts.putValue(declaration, message(RefactoringUIUtil.getDescription(declaration, true).capitalize())) +} + public fun getPsiElementPopup( editor: Editor, elements: List, diff --git a/idea/testData/intentions/convertFunctionToProperty/.intention b/idea/testData/intentions/convertFunctionToProperty/.intention new file mode 100644 index 00000000000..1bc88af5721 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt b/idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt new file mode 100644 index 00000000000..4178865268f --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt @@ -0,0 +1,15 @@ +trait T { + fun bar() +} + +class A(val n: Int) { + fun foo() = object : T { + override fun bar() { + + } + } +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt.after b/idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt.after new file mode 100644 index 00000000000..88412592408 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt.after @@ -0,0 +1,16 @@ +trait T { + fun bar() +} + +class A(val n: Int) { + val foo: T + get() = object : T { + override fun bar() { + + } + } +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt b/idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt new file mode 100644 index 00000000000..deecffee45a --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt @@ -0,0 +1,9 @@ +fun test() { + class X + + class A(val n: Int) { + fun foo() = X() + } + + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt.after b/idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt.after new file mode 100644 index 00000000000..7e2bb142f61 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt.after @@ -0,0 +1,10 @@ +fun test() { + class X + + class A(val n: Int) { + val foo: X + get() = X() + } + + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt b/idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt new file mode 100644 index 00000000000..95ffc77672d --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt @@ -0,0 +1,7 @@ +class A(val n: Int) { + fun foo() = n > 1 +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt.after b/idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt.after new file mode 100644 index 00000000000..56d590eb608 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt.after @@ -0,0 +1,8 @@ +class A(val n: Int) { + val foo: Boolean + get() = n > 1 +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/blockBody.kt b/idea/testData/intentions/convertFunctionToProperty/blockBody.kt new file mode 100644 index 00000000000..42842af7082 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/blockBody.kt @@ -0,0 +1,9 @@ +class A(val n: Int) { + fun foo(): Boolean { + return n > 1 + } +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/blockBody.kt.after b/idea/testData/intentions/convertFunctionToProperty/blockBody.kt.after new file mode 100644 index 00000000000..af3dd19af67 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/blockBody.kt.after @@ -0,0 +1,10 @@ +class A(val n: Int) { + val foo: Boolean + get() { + return n > 1 + } +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/existingPropertyConflict.kt b/idea/testData/intentions/convertFunctionToProperty/existingPropertyConflict.kt new file mode 100644 index 00000000000..7babbb98b87 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/existingPropertyConflict.kt @@ -0,0 +1,7 @@ +// SHOULD_FAIL_WITH: Property foo already exists +class A(val n: Int) { + fun foo(): Boolean = n > 1 +} + +val A.foo: Int + get() = 1 \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.1.java b/idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.1.java new file mode 100644 index 00000000000..4a81339f34c --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.1.java @@ -0,0 +1,12 @@ +import test.A; + +class J extends A { + boolean getFoo() { + return true; + } + + @Override + int foo() { + return 2; + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.kt b/idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.kt new file mode 100644 index 00000000000..7681b02d24b --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.kt @@ -0,0 +1,6 @@ +// SHOULD_FAIL_WITH: Method J.getFoo() already exists +package test + +open class A { + open fun foo(): Int = 1 +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/expressionBody.kt b/idea/testData/intentions/convertFunctionToProperty/expressionBody.kt new file mode 100644 index 00000000000..53e36bdd898 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/expressionBody.kt @@ -0,0 +1,7 @@ +class A(val n: Int) { + fun foo(): Boolean = n > 1 +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/expressionBody.kt.after b/idea/testData/intentions/convertFunctionToProperty/expressionBody.kt.after new file mode 100644 index 00000000000..56d590eb608 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/expressionBody.kt.after @@ -0,0 +1,8 @@ +class A(val n: Int) { + val foo: Boolean + get() = n > 1 +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/extraArgumentsConflict.kt b/idea/testData/intentions/convertFunctionToProperty/extraArgumentsConflict.kt new file mode 100644 index 00000000000..423d0a6a1d2 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/extraArgumentsConflict.kt @@ -0,0 +1,9 @@ +// ERROR: Too many arguments for internal final fun foo(): kotlin.Boolean defined in A +// SHOULD_FAIL_WITH: Call with arguments will be skipped: foo(2) +class A(val n: Int) { + fun foo(): Boolean = n > 1 +} + +fun test() { + val t = A(1).foo(2) +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/funWithParameters.kt b/idea/testData/intentions/convertFunctionToProperty/funWithParameters.kt new file mode 100644 index 00000000000..c7372b68f96 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/funWithParameters.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +class A(val n: Int) { + fun foo(k: Int): Boolean = n - k > 1 +} + +fun test() { + val t = A(1).foo(2) +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/invoke.kt b/idea/testData/intentions/convertFunctionToProperty/invoke.kt new file mode 100644 index 00000000000..7c5cad4f6b8 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/invoke.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +class A(val n: Int) { + fun invoke(): Int = 1 +} + +fun test(a: A) { + val n = a() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/iterator.kt b/idea/testData/intentions/convertFunctionToProperty/iterator.kt new file mode 100644 index 00000000000..e13485954fe --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/iterator.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +class A(val n: Int) { + fun iterator(): Iterator = throw Exception("") +} + +fun test() { + for (a in A(10)) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/javaUsages.1.java b/idea/testData/intentions/convertFunctionToProperty/javaUsages.1.java new file mode 100644 index 00000000000..9512eecc61a --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/javaUsages.1.java @@ -0,0 +1,7 @@ +import static test.TestPackage.foo; + +class J { + void test() { + boolean b = foo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/javaUsages.1.java.after b/idea/testData/intentions/convertFunctionToProperty/javaUsages.1.java.after new file mode 100644 index 00000000000..3f3fbb5e085 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/javaUsages.1.java.after @@ -0,0 +1,7 @@ +import static test.TestPackage.getFoo; + +class J { + void test() { + boolean b = getFoo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/javaUsages.kt b/idea/testData/intentions/convertFunctionToProperty/javaUsages.kt new file mode 100644 index 00000000000..c6156e3c2ba --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/javaUsages.kt @@ -0,0 +1,3 @@ +package test + +fun foo(): Boolean = true \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/javaUsages.kt.after b/idea/testData/intentions/convertFunctionToProperty/javaUsages.kt.after new file mode 100644 index 00000000000..fd61f65ed76 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/javaUsages.kt.after @@ -0,0 +1,4 @@ +package test + +val foo: Boolean + get() = true \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/localFun.kt b/idea/testData/intentions/convertFunctionToProperty/localFun.kt new file mode 100644 index 00000000000..b0b404e5e2a --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/localFun.kt @@ -0,0 +1,6 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + fun foo(): Boolean = n > 1 + + val t = foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/nothingFun.kt b/idea/testData/intentions/convertFunctionToProperty/nothingFun.kt new file mode 100644 index 00000000000..14a59b12a11 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/nothingFun.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +class A(val n: Int) { + fun foo() = throw Exception("foo") +} + +fun test() { + A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/otherRefs.kt b/idea/testData/intentions/convertFunctionToProperty/otherRefs.kt new file mode 100644 index 00000000000..69f1430942c --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/otherRefs.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +package p + +import p.foo + +class A(val n: Int) + +fun A.foo(): Boolean = n > 1 + +fun test() { + val t = A::foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/otherRefs.kt.after b/idea/testData/intentions/convertFunctionToProperty/otherRefs.kt.after new file mode 100644 index 00000000000..2808393aa6f --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/otherRefs.kt.after @@ -0,0 +1,13 @@ +// WITH_RUNTIME +package p + +import p.foo + +class A(val n: Int) + +val A.foo: Boolean + get() = n > 1 + +fun test() { + val t = A::foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/overrides.1.java b/idea/testData/intentions/convertFunctionToProperty/overrides.1.java new file mode 100644 index 00000000000..93392d4ed19 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/overrides.1.java @@ -0,0 +1,19 @@ +import test.*; + +class JA extends A { + public JA() { + super(1); + } + + @Override + boolean foo() { + return true; + } +} + +class JTest { + void test() { + boolean x = new A(1).foo(); + boolean y = new JA().foo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/overrides.1.java.after b/idea/testData/intentions/convertFunctionToProperty/overrides.1.java.after new file mode 100644 index 00000000000..19afcd39834 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/overrides.1.java.after @@ -0,0 +1,19 @@ +import test.*; + +class JA extends A { + public JA() { + super(1); + } + + @Override + boolean getFoo() { + return true; + } +} + +class JTest { + void test() { + boolean x = new A(1).getFoo(); + boolean y = new JA().getFoo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/overrides.kt b/idea/testData/intentions/convertFunctionToProperty/overrides.kt new file mode 100644 index 00000000000..30c8fa8db5d --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/overrides.kt @@ -0,0 +1,18 @@ +package test + +trait T { + fun foo(): Boolean +} + +open class A(val n: Int): T { + override fun foo(): Boolean = n > 1 +} + +class B: A(1) { + override fun foo(): Boolean = true +} + +fun test() { + val a = A(1).foo() + val b = B().foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/overrides.kt.after b/idea/testData/intentions/convertFunctionToProperty/overrides.kt.after new file mode 100644 index 00000000000..5754ead2370 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/overrides.kt.after @@ -0,0 +1,20 @@ +package test + +trait T { + val foo: Boolean +} + +open class A(val n: Int): T { + override val foo: Boolean + get() = n > 1 +} + +class B: A(1) { + override val foo: Boolean + get() = true +} + +fun test() { + val a = A(1).foo + val b = B().foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/typeArgumentsConflict.kt b/idea/testData/intentions/convertFunctionToProperty/typeArgumentsConflict.kt new file mode 100644 index 00000000000..cf42391def9 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/typeArgumentsConflict.kt @@ -0,0 +1,8 @@ +// SHOULD_FAIL_WITH: Type arguments will be lost after conversion: foo<Double>() +class A(val n: Int) { + fun foo(): Boolean = n > 1 +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/unaryOp.kt b/idea/testData/intentions/convertFunctionToProperty/unaryOp.kt new file mode 100644 index 00000000000..90a3c694538 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/unaryOp.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +class A(val n: Int) { + fun minus(): A = A(-n) +} + +fun test() { + val t = -A(1) +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt b/idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt new file mode 100644 index 00000000000..8943cc7b812 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt @@ -0,0 +1,15 @@ +// WITH_RUNTIME + +annotation class X(val s: String) + +class A(val n: Int) { + val t = 1 + internal X("1") fun T.foo(): Boolean = toInt() - n > 1 + val u = 2 +} + +fun test() { + val t = with(A(1)) { + 2.5.foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt.after b/idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt.after new file mode 100644 index 00000000000..bdcc5214ac3 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt.after @@ -0,0 +1,16 @@ +// WITH_RUNTIME + +annotation class X(val s: String) + +class A(val n: Int) { + val t = 1 + internal X("1") val T.foo: Boolean + get() = toInt() - n > 1 + val u = 2 +} + +fun test() { + val t = with(A(1)) { + 2.5.foo + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertFunctionToProperty/unitFun.kt b/idea/testData/intentions/convertFunctionToProperty/unitFun.kt new file mode 100644 index 00000000000..794b03acf08 --- /dev/null +++ b/idea/testData/intentions/convertFunctionToProperty/unitFun.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +class A(val n: Int) { + fun foo() { + println(n) + } +} + +fun test() { + A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/.intention b/idea/testData/intentions/convertPropertyToFunction/.intention new file mode 100644 index 00000000000..0726cff420e --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.1.groovy b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.1.groovy new file mode 100644 index 00000000000..f8d1c9f7f0a --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.1.groovy @@ -0,0 +1,5 @@ +class G { + void test() { + test.TestPackage.getBar(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.1.groovy.after b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.1.groovy.after new file mode 100644 index 00000000000..69f9904fdb2 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.1.groovy.after @@ -0,0 +1,5 @@ +class G { + void test() { + test.TestPackage.bar(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt new file mode 100644 index 00000000000..0602c88484c --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt @@ -0,0 +1,4 @@ +package test + +val bar: Int + get() = 1 \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt.after b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt.after new file mode 100644 index 00000000000..dd01be8884b --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt.after @@ -0,0 +1,3 @@ +package test + +fun bar(): Int = 1 \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/blockBody.kt b/idea/testData/intentions/convertPropertyToFunction/blockBody.kt new file mode 100644 index 00000000000..bdb31cd84ac --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/blockBody.kt @@ -0,0 +1,10 @@ +class A(val n: Int) { + val foo: Boolean + get() { + return n > 1 + } +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/blockBody.kt.after b/idea/testData/intentions/convertPropertyToFunction/blockBody.kt.after new file mode 100644 index 00000000000..79f0db1c604 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/blockBody.kt.after @@ -0,0 +1,9 @@ +class A(val n: Int) { + fun foo(): Boolean { + return n > 1 + } +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/delegatingProperty.kt b/idea/testData/intentions/convertPropertyToFunction/delegatingProperty.kt new file mode 100644 index 00000000000..c6610c862a4 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/delegatingProperty.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +import kotlin.properties.Delegates + +class A(val n: Int) { + val foo: Boolean by Delegates.lazy { n > 1 } +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/existingFunConflict.kt b/idea/testData/intentions/convertPropertyToFunction/existingFunConflict.kt new file mode 100644 index 00000000000..000d0661beb --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/existingFunConflict.kt @@ -0,0 +1,6 @@ +// SHOULD_FAIL_WITH: Function foo already exists +class A(val n: Int) { + val foo: Boolean = n > 1 +} + +fun A.foo() = 1 \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.1.java b/idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.1.java new file mode 100644 index 00000000000..26803e4a5ec --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.1.java @@ -0,0 +1,12 @@ +import test.A; + +class J extends A { + boolean foo() { + return true; + } + + @Override + int getFoo() { + return 2; + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.kt b/idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.kt new file mode 100644 index 00000000000..e864e13a5ca --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.kt @@ -0,0 +1,6 @@ +// SHOULD_FAIL_WITH: Method J.foo() already exists +package test + +open class A { + open val foo: Int = 1 +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/expressionBody.kt b/idea/testData/intentions/convertPropertyToFunction/expressionBody.kt new file mode 100644 index 00000000000..22568b9f660 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/expressionBody.kt @@ -0,0 +1,8 @@ +class A(val n: Int) { + val foo: Boolean + get() = n > 1 +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/expressionBody.kt.after b/idea/testData/intentions/convertPropertyToFunction/expressionBody.kt.after new file mode 100644 index 00000000000..d66ba045b03 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/expressionBody.kt.after @@ -0,0 +1,7 @@ +class A(val n: Int) { + fun foo(): Boolean = n > 1 +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/initializer.kt b/idea/testData/intentions/convertPropertyToFunction/initializer.kt new file mode 100644 index 00000000000..0e2232b11ee --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/initializer.kt @@ -0,0 +1,7 @@ +class A(val n: Int) { + val foo: Boolean = n > 1 +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/initializer.kt.after b/idea/testData/intentions/convertPropertyToFunction/initializer.kt.after new file mode 100644 index 00000000000..d66ba045b03 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/initializer.kt.after @@ -0,0 +1,7 @@ +class A(val n: Int) { + fun foo(): Boolean = n > 1 +} + +fun test() { + val t = A(1).foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.1.java b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.1.java new file mode 100644 index 00000000000..13eb4e04b39 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.1.java @@ -0,0 +1,9 @@ +import test.O; +import static test.O.foo; + +class J { + void test() { + int n = O.foo; + int m = foo; + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.1.java.after b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.1.java.after new file mode 100644 index 00000000000..8d11a8555b2 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.1.java.after @@ -0,0 +1,9 @@ +import test.O; +import static test.O.foo; + +class J { + void test() { + int n = O.foo(); + int m = foo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt new file mode 100644 index 00000000000..1fd122a9b30 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt @@ -0,0 +1,5 @@ +package test + +object O { + val foo: Int = 1 +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt.after b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt.after new file mode 100644 index 00000000000..337652388ca --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt.after @@ -0,0 +1,5 @@ +package test + +object O { + fun foo(): Int = 1 +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsages.1.java b/idea/testData/intentions/convertPropertyToFunction/javaUsages.1.java new file mode 100644 index 00000000000..3f3fbb5e085 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsages.1.java @@ -0,0 +1,7 @@ +import static test.TestPackage.getFoo; + +class J { + void test() { + boolean b = getFoo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsages.1.java.after b/idea/testData/intentions/convertPropertyToFunction/javaUsages.1.java.after new file mode 100644 index 00000000000..9512eecc61a --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsages.1.java.after @@ -0,0 +1,7 @@ +import static test.TestPackage.foo; + +class J { + void test() { + boolean b = foo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsages.kt b/idea/testData/intentions/convertPropertyToFunction/javaUsages.kt new file mode 100644 index 00000000000..d678c3710cb --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsages.kt @@ -0,0 +1,4 @@ +package test + +val foo: Boolean + get() = true \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/javaUsages.kt.after b/idea/testData/intentions/convertPropertyToFunction/javaUsages.kt.after new file mode 100644 index 00000000000..e3ea93fedd8 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/javaUsages.kt.after @@ -0,0 +1,3 @@ +package test + +fun foo(): Boolean = true \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/otherRefs.kt b/idea/testData/intentions/convertPropertyToFunction/otherRefs.kt new file mode 100644 index 00000000000..cbbee9736c9 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/otherRefs.kt @@ -0,0 +1,13 @@ +// WITH_RUNTIME +package p + +import p.foo + +class A(val n: Int) + +val A.foo: Boolean + get() = n > 1 + +fun test() { + val t = A::foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/otherRefs.kt.after b/idea/testData/intentions/convertPropertyToFunction/otherRefs.kt.after new file mode 100644 index 00000000000..bdd3a5a44b2 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/otherRefs.kt.after @@ -0,0 +1,12 @@ +// WITH_RUNTIME +package p + +import p.foo + +class A(val n: Int) + +fun A.foo(): Boolean = n > 1 + +fun test() { + val t = A::foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/overrides.1.java b/idea/testData/intentions/convertPropertyToFunction/overrides.1.java new file mode 100644 index 00000000000..19afcd39834 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/overrides.1.java @@ -0,0 +1,19 @@ +import test.*; + +class JA extends A { + public JA() { + super(1); + } + + @Override + boolean getFoo() { + return true; + } +} + +class JTest { + void test() { + boolean x = new A(1).getFoo(); + boolean y = new JA().getFoo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/overrides.1.java.after b/idea/testData/intentions/convertPropertyToFunction/overrides.1.java.after new file mode 100644 index 00000000000..93392d4ed19 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/overrides.1.java.after @@ -0,0 +1,19 @@ +import test.*; + +class JA extends A { + public JA() { + super(1); + } + + @Override + boolean foo() { + return true; + } +} + +class JTest { + void test() { + boolean x = new A(1).foo(); + boolean y = new JA().foo(); + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/overrides.kt b/idea/testData/intentions/convertPropertyToFunction/overrides.kt new file mode 100644 index 00000000000..4e0692609dd --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/overrides.kt @@ -0,0 +1,20 @@ +package test + +trait T { + val foo: Boolean +} + +open class A(val n: Int): T { + override val foo: Boolean + get() = n > 1 +} + +class B: A(1) { + override val foo: Boolean + get() = true +} + +fun test() { + val a = A(1).foo + val b = B().foo +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/overrides.kt.after b/idea/testData/intentions/convertPropertyToFunction/overrides.kt.after new file mode 100644 index 00000000000..37d9d07824c --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/overrides.kt.after @@ -0,0 +1,18 @@ +package test + +trait T { + fun foo(): Boolean +} + +open class A(val n: Int): T { + override fun foo(): Boolean = n > 1 +} + +class B: A(1) { + override fun foo(): Boolean = true +} + +fun test() { + val a = A(1).foo() + val b = B().foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.1.groovy b/idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.1.groovy new file mode 100644 index 00000000000..f2bed79753a --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.1.groovy @@ -0,0 +1,5 @@ +class G { + void test() { + test.TestPackage.bar; + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.kt b/idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.kt new file mode 100644 index 00000000000..6b6e368cb16 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.kt @@ -0,0 +1,5 @@ +// SHOULD_FAIL_WITH: Can't replace foreign reference with call expression: test.TestPackage.bar +package test + +val bar: Int + get() = 1 \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt b/idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt new file mode 100644 index 00000000000..4fff0dab6af --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt @@ -0,0 +1,14 @@ +// WITH_RUNTIME + +annotation class X(val s: String) + +class A(val n: Int) { + internal X("1") val T.foo: Boolean + get() = toInt() - n > 1 +} + +fun test() { + val t = with(A(1)) { + 2.5.foo + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt.after b/idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt.after new file mode 100644 index 00000000000..9783d9c2629 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt.after @@ -0,0 +1,13 @@ +// WITH_RUNTIME + +annotation class X(val s: String) + +class A(val n: Int) { + internal X("1") fun T.foo(): Boolean = toInt() - n > 1 +} + +fun test() { + val t = with(A(1)) { + 2.5.foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPropertyToFunction/var.kt b/idea/testData/intentions/convertPropertyToFunction/var.kt new file mode 100644 index 00000000000..9eb65b4c703 --- /dev/null +++ b/idea/testData/intentions/convertPropertyToFunction/var.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false +class A(var n: Int) { + var foo: Int + get() = n + 1 + set(value: Int) { n = value - 1 } +} + +fun test() { + val t = A(1).foo +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt b/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt index df7eeae1aa4..4a856e817c2 100644 --- a/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt +++ b/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt @@ -1,4 +1,5 @@ // "Specify type explicitly" "false" +// ACTION: Convert property to function // ERROR: Public or protected member should have specified type // ERROR: Unresolved reference: foo diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractIntentionTest.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractIntentionTest.java index 2e1ddf0ec57..3e746e3dad6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractIntentionTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractIntentionTest.java @@ -18,23 +18,34 @@ package org.jetbrains.kotlin.idea.intentions; import com.google.common.collect.Lists; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.ide.startup.impl.StartupManagerImpl; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.testFramework.LightCodeInsightTestCase; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.util.PathUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Convertor; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.DirectiveBasedActionUtils; +import org.jetbrains.kotlin.idea.KotlinCodeInsightTestCase; import org.jetbrains.kotlin.idea.PluginTestCaseBase; +import org.jetbrains.kotlin.idea.util.application.ApplicationPackage; import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.test.ConfigLibraryUtil; import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.junit.Assert; import java.io.File; +import java.util.ArrayList; import java.util.List; +import java.util.Map; -public abstract class AbstractIntentionTest extends LightCodeInsightTestCase { +public abstract class AbstractIntentionTest extends KotlinCodeInsightTestCase { private static IntentionAction createIntention(File testDataFile) throws Exception { List candidateFiles = Lists.newArrayList(); @@ -60,12 +71,45 @@ public abstract class AbstractIntentionTest extends LightCodeInsightTestCase { return (IntentionAction) Class.forName(className).newInstance(); } + private static final String[] EXTENSIONS = { ".kt", ".java", ".groovy" }; + protected void doTest(@NotNull String path) throws Exception { - IntentionAction intentionAction = createIntention(new File(path)); + File mainFile = new File(path); + String mainFileName = FileUtil.getNameWithoutExtension(mainFile); + IntentionAction intentionAction = createIntention(mainFile); + List sourceFilePaths = new ArrayList(); + File parentDir = mainFile.getParentFile(); + extraFileLoop: + //noinspection ForLoopThatDoesntUseLoopVariable + for (int i = 1; true; i++) { + for (String extension : EXTENSIONS) { + File extraFile = new File(parentDir, mainFileName + "." + i + extension); + if (extraFile.exists()) { + sourceFilePaths.add(extraFile.getPath()); + continue extraFileLoop; + } + } + break; + } + sourceFilePaths.add(path); - configureByFile(path); + Map pathToFile = ContainerUtil.newMapFromKeys( + sourceFilePaths.iterator(), + new Convertor() { + @Override + public PsiFile convert(String path) { + try { + configureByFile(path); + } + catch (Exception e) { + throw new RuntimeException(e); + } + return myFile; + } + } + ); - String fileText = FileUtil.loadFile(new File(path), true); + String fileText = FileUtil.loadFile(mainFile, true); String minJavaVersion = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MIN_JAVA_VERSION: "); if (minJavaVersion != null && !SystemInfo.isJavaVersionAtLeast(minJavaVersion)) return; @@ -79,16 +123,16 @@ public abstract class AbstractIntentionTest extends LightCodeInsightTestCase { DirectiveBasedActionUtils.checkForUnexpectedErrors((JetFile) getFile()); - doTestFor(path, intentionAction, fileText); + doTestFor(pathToFile, intentionAction, fileText); } finally { if (isWithRuntime) { - ConfigLibraryUtil.unConfigureKotlinRuntime(getModule(), getProjectJDK()); + ConfigLibraryUtil.unConfigureKotlinRuntime(getModule(), getTestProjectJdk()); } } } - private void doTestFor(String path, IntentionAction intentionAction, String fileText) { + private void doTestFor(Map pathToFile, final IntentionAction intentionAction, String fileText) throws Exception { String isApplicableString = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// IS_APPLICABLE: "); boolean isApplicableExpected = isApplicableString == null || isApplicableString.equals("true"); @@ -106,11 +150,26 @@ public abstract class AbstractIntentionTest extends LightCodeInsightTestCase { try { if (isApplicableExpected) { - intentionAction.invoke(getProject(), getEditor(), getFile()); + ApplicationPackage.executeWriteCommand( + getProject(), + intentionAction.getText(), + new Function0() { + @Override + public Object invoke() { + intentionAction.invoke(getProject(), getEditor(), getFile()); + return null; + } + } + ); // Don't bother checking if it should have failed. if (shouldFailString == null) { - String canonicalPathToExpectedFile = PathUtil.getCanonicalPath(path + ".after"); - checkResultByFile(canonicalPathToExpectedFile); + for (Map.Entry entry: pathToFile.entrySet()) { + //noinspection AssignmentToStaticFieldFromInstanceMethod + myFile = entry.getValue(); + String canonicalPathToExpectedFile = PathUtil.getCanonicalPath(entry.getKey() + ".after"); + + checkResultByFile(canonicalPathToExpectedFile); + } } } assertNull("Expected test to fail.", shouldFailString); @@ -118,6 +177,15 @@ public abstract class AbstractIntentionTest extends LightCodeInsightTestCase { catch (IntentionTestException e) { assertEquals("Failure message mismatch.", shouldFailString, e.getMessage()); } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + assertEquals("Failure message mismatch.", shouldFailString, StringUtil.join(e.getMessages(), ", ")); + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + ((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities(); } @NotNull diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 15c66da3686..14f90fc40ea 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -30,7 +30,7 @@ import java.util.regex.Pattern; @SuppressWarnings("all") @TestMetadata("idea/testData/intentions") @TestDataPath("$PROJECT_ROOT") -@InnerTestClasses({IntentionTestGenerated.AddBraces.class, IntentionTestGenerated.AttributeCallReplacements.class, IntentionTestGenerated.Branched.class, IntentionTestGenerated.ConvertAssertToIf.class, IntentionTestGenerated.ConvertIfToAssert.class, IntentionTestGenerated.ConvertNegatedBooleanSequence.class, IntentionTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, IntentionTestGenerated.ConvertToBlockBody.class, IntentionTestGenerated.ConvertToConcatenatedStringIntention.class, IntentionTestGenerated.ConvertToExpressionBody.class, IntentionTestGenerated.ConvertToForEachFunctionCall.class, IntentionTestGenerated.ConvertToForEachLoop.class, IntentionTestGenerated.ConvertToStringTemplateIntention.class, IntentionTestGenerated.Declarations.class, IntentionTestGenerated.InsertCurlyBracesToTemplate.class, IntentionTestGenerated.InsertExplicitTypeArguments.class, IntentionTestGenerated.InvertIfCondition.class, IntentionTestGenerated.MakeTypeExplicitInLambda.class, IntentionTestGenerated.MakeTypeImplicitInLambda.class, IntentionTestGenerated.MoveLambdaInsideParentheses.class, IntentionTestGenerated.MoveLambdaOutsideParentheses.class, IntentionTestGenerated.OperatorToFunction.class, IntentionTestGenerated.ReconstructedType.class, IntentionTestGenerated.RemoveBraces.class, IntentionTestGenerated.RemoveCurlyBracesFromTemplate.class, IntentionTestGenerated.RemoveExplicitTypeArguments.class, IntentionTestGenerated.RemoveUnnecessaryParentheses.class, IntentionTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, IntentionTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, IntentionTestGenerated.ReplaceWithDotQualifiedMethodCall.class, IntentionTestGenerated.ReplaceWithInfixFunctionCall.class, IntentionTestGenerated.ReplaceWithOperatorAssign.class, IntentionTestGenerated.ReplaceWithTraditionalAssignment.class, IntentionTestGenerated.SimplifyBooleanWithConstants.class, IntentionTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, IntentionTestGenerated.SpecifyType.class, IntentionTestGenerated.SplitIf.class, IntentionTestGenerated.SwapBinaryExpression.class}) +@InnerTestClasses({IntentionTestGenerated.AddBraces.class, IntentionTestGenerated.AttributeCallReplacements.class, IntentionTestGenerated.Branched.class, IntentionTestGenerated.ConvertAssertToIf.class, IntentionTestGenerated.ConvertFunctionToProperty.class, IntentionTestGenerated.ConvertIfToAssert.class, IntentionTestGenerated.ConvertNegatedBooleanSequence.class, IntentionTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, IntentionTestGenerated.ConvertPropertyToFunction.class, IntentionTestGenerated.ConvertToBlockBody.class, IntentionTestGenerated.ConvertToConcatenatedStringIntention.class, IntentionTestGenerated.ConvertToExpressionBody.class, IntentionTestGenerated.ConvertToForEachFunctionCall.class, IntentionTestGenerated.ConvertToForEachLoop.class, IntentionTestGenerated.ConvertToStringTemplateIntention.class, IntentionTestGenerated.Declarations.class, IntentionTestGenerated.InsertCurlyBracesToTemplate.class, IntentionTestGenerated.InsertExplicitTypeArguments.class, IntentionTestGenerated.InvertIfCondition.class, IntentionTestGenerated.MakeTypeExplicitInLambda.class, IntentionTestGenerated.MakeTypeImplicitInLambda.class, IntentionTestGenerated.MoveLambdaInsideParentheses.class, IntentionTestGenerated.MoveLambdaOutsideParentheses.class, IntentionTestGenerated.OperatorToFunction.class, IntentionTestGenerated.ReconstructedType.class, IntentionTestGenerated.RemoveBraces.class, IntentionTestGenerated.RemoveCurlyBracesFromTemplate.class, IntentionTestGenerated.RemoveExplicitTypeArguments.class, IntentionTestGenerated.RemoveUnnecessaryParentheses.class, IntentionTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, IntentionTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, IntentionTestGenerated.ReplaceWithDotQualifiedMethodCall.class, IntentionTestGenerated.ReplaceWithInfixFunctionCall.class, IntentionTestGenerated.ReplaceWithOperatorAssign.class, IntentionTestGenerated.ReplaceWithTraditionalAssignment.class, IntentionTestGenerated.SimplifyBooleanWithConstants.class, IntentionTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, IntentionTestGenerated.SpecifyType.class, IntentionTestGenerated.SplitIf.class, IntentionTestGenerated.SwapBinaryExpression.class}) @RunWith(JUnit3RunnerWithInners.class) public class IntentionTestGenerated extends AbstractIntentionTest { public void testAllFilesPresentInIntentions() throws Exception { @@ -2551,6 +2551,135 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/convertFunctionToProperty") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertFunctionToProperty extends AbstractIntentionTest { + @TestMetadata("addExplicitAnonymousType.kt") + public void testAddExplicitAnonymousType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/addExplicitAnonymousType.kt"); + doTest(fileName); + } + + @TestMetadata("addExplicitLocalType.kt") + public void testAddExplicitLocalType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/addExplicitLocalType.kt"); + doTest(fileName); + } + + @TestMetadata("addExplicitType.kt") + public void testAddExplicitType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/addExplicitType.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInConvertFunctionToProperty() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertFunctionToProperty"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("blockBody.kt") + public void testBlockBody() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/blockBody.kt"); + doTest(fileName); + } + + @TestMetadata("existingPropertyConflict.kt") + public void testExistingPropertyConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/existingPropertyConflict.kt"); + doTest(fileName); + } + + @TestMetadata("existingPropertyJavaConflict.kt") + public void testExistingPropertyJavaConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/existingPropertyJavaConflict.kt"); + doTest(fileName); + } + + @TestMetadata("expressionBody.kt") + public void testExpressionBody() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/expressionBody.kt"); + doTest(fileName); + } + + @TestMetadata("extraArgumentsConflict.kt") + public void testExtraArgumentsConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/extraArgumentsConflict.kt"); + doTest(fileName); + } + + @TestMetadata("funWithParameters.kt") + public void testFunWithParameters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/funWithParameters.kt"); + doTest(fileName); + } + + @TestMetadata("invoke.kt") + public void testInvoke() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/invoke.kt"); + doTest(fileName); + } + + @TestMetadata("iterator.kt") + public void testIterator() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/iterator.kt"); + doTest(fileName); + } + + @TestMetadata("javaUsages.kt") + public void testJavaUsages() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/javaUsages.kt"); + doTest(fileName); + } + + @TestMetadata("localFun.kt") + public void testLocalFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/localFun.kt"); + doTest(fileName); + } + + @TestMetadata("nothingFun.kt") + public void testNothingFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/nothingFun.kt"); + doTest(fileName); + } + + @TestMetadata("otherRefs.kt") + public void testOtherRefs() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/otherRefs.kt"); + doTest(fileName); + } + + @TestMetadata("overrides.kt") + public void testOverrides() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/overrides.kt"); + doTest(fileName); + } + + @TestMetadata("typeArgumentsConflict.kt") + public void testTypeArgumentsConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/typeArgumentsConflict.kt"); + doTest(fileName); + } + + @TestMetadata("unaryOp.kt") + public void testUnaryOp() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/unaryOp.kt"); + doTest(fileName); + } + + @TestMetadata("unchangedElements.kt") + public void testUnchangedElements() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/unchangedElements.kt"); + doTest(fileName); + } + + @TestMetadata("unitFun.kt") + public void testUnitFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionToProperty/unitFun.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/convertIfToAssert") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -2800,6 +2929,99 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/convertPropertyToFunction") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertPropertyToFunction extends AbstractIntentionTest { + @TestMetadata("accessorCallGroovy.kt") + public void testAccessorCallGroovy() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/accessorCallGroovy.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInConvertPropertyToFunction() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertPropertyToFunction"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("blockBody.kt") + public void testBlockBody() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/blockBody.kt"); + doTest(fileName); + } + + @TestMetadata("delegatingProperty.kt") + public void testDelegatingProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/delegatingProperty.kt"); + doTest(fileName); + } + + @TestMetadata("existingFunConflict.kt") + public void testExistingFunConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/existingFunConflict.kt"); + doTest(fileName); + } + + @TestMetadata("existingFunJavaConflict.kt") + public void testExistingFunJavaConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/existingFunJavaConflict.kt"); + doTest(fileName); + } + + @TestMetadata("expressionBody.kt") + public void testExpressionBody() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/expressionBody.kt"); + doTest(fileName); + } + + @TestMetadata("initializer.kt") + public void testInitializer() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/initializer.kt"); + doTest(fileName); + } + + @TestMetadata("javaUsageAsField.kt") + public void testJavaUsageAsField() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/javaUsageAsField.kt"); + doTest(fileName); + } + + @TestMetadata("javaUsages.kt") + public void testJavaUsages() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/javaUsages.kt"); + doTest(fileName); + } + + @TestMetadata("otherRefs.kt") + public void testOtherRefs() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/otherRefs.kt"); + doTest(fileName); + } + + @TestMetadata("overrides.kt") + public void testOverrides() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/overrides.kt"); + doTest(fileName); + } + + @TestMetadata("propertyCallGroovy.kt") + public void testPropertyCallGroovy() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/propertyCallGroovy.kt"); + doTest(fileName); + } + + @TestMetadata("unchangedElements.kt") + public void testUnchangedElements() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/unchangedElements.kt"); + doTest(fileName); + } + + @TestMetadata("var.kt") + public void testVar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertPropertyToFunction/var.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/convertToBlockBody") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)