From 9e4153f60fb3f107dfea9504eb7bbb94d6f96c1e Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Fri, 28 Jul 2017 17:33:17 +0300 Subject: [PATCH] `JvmCommonIntentionActionsFactory` switched to `com.intellij.lang.jvm.*` api and renamed to `JvmElementActionsFactory` old `JvmCommonIntentionActionsFactory` reverted to "UAST"-state and deprecated --- .../JvmCommonIntentionActionsFactory.kt | 83 +++----- .../jvm/actions/JvmElementActionsFactory.kt | 58 ++++++ .../JvmElementActionsFactoryFallback.kt | 25 +++ .../lang/jvm/actions/MemberRequest.kt | 85 ++++++++ .../inheritance/ImplicitSubclassInspection.kt | 39 ++-- .../daemon/impl/quickfix/CreateMethodFix.kt | 13 +- .../impl/ElementActionsFactoryUastFallback.kt | 96 +++++++++ .../impl/JavaCommonIntentionActionsFactory.kt | 125 ------------ .../impl/JavaElementActionsFactoryImpl.kt | 193 ++++++++++++++++++ .../CreateBeanPropertyFixes.java | 9 +- plugins/groovy/src/META-INF/plugin.xml | 4 +- .../refs/JavaFxEventHandlerReference.java | 22 +- resources/src/META-INF/IdeaPlugin.xml | 14 +- 13 files changed, 544 insertions(+), 222 deletions(-) create mode 100644 java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactory.kt create mode 100644 java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactoryFallback.kt create mode 100644 java/java-analysis-api/src/com/intellij/lang/jvm/actions/MemberRequest.kt create mode 100644 java/java-impl/src/com/intellij/codeInsight/intention/impl/ElementActionsFactoryUastFallback.kt delete mode 100644 java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaCommonIntentionActionsFactory.kt create mode 100644 java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactoryImpl.kt diff --git a/java/java-analysis-api/src/com/intellij/codeInsight/intention/JvmCommonIntentionActionsFactory.kt b/java/java-analysis-api/src/com/intellij/codeInsight/intention/JvmCommonIntentionActionsFactory.kt index e8927de8a0f7..ead79ecc219c 100644 --- a/java/java-analysis-api/src/com/intellij/codeInsight/intention/JvmCommonIntentionActionsFactory.kt +++ b/java/java-analysis-api/src/com/intellij/codeInsight/intention/JvmCommonIntentionActionsFactory.kt @@ -17,13 +17,13 @@ package com.intellij.codeInsight.intention import com.intellij.lang.Language import com.intellij.lang.LanguageExtension -import com.intellij.openapi.components.ServiceManager -import com.intellij.psi.* +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiType +import com.intellij.psi.PsiTypeParameter import org.jetbrains.annotations.ApiStatus import org.jetbrains.uast.UClass import org.jetbrains.uast.UDeclaration -import org.jetbrains.uast.UElement -import org.jetbrains.uast.UastContext +import org.jetbrains.uast.UParameter /** * Extension Point provides language-abstracted code modifications for JVM-based languages. @@ -36,24 +36,21 @@ import org.jetbrains.uast.UastContext * @since 2017.2 */ @ApiStatus.Experimental +@Deprecated("to be removed in 2017.3", ReplaceWith("com.intellij.lang.jvm.actions.JvmCommonIntentionActionsFactory")) abstract class JvmCommonIntentionActionsFactory { - open fun createChangeModifierAction(declaration: @JvmCommon PsiModifierListOwner, + open fun createChangeModifierAction(declaration: UDeclaration, @PsiModifier.ModifierConstant modifier: String, - shouldPresent: Boolean): IntentionAction? = - //Fallback if Uast-version of method is overridden - createChangeModifierAction(declaration.asUast(), modifier, shouldPresent) + shouldPresent: Boolean): IntentionAction? = null open fun createAddCallableMemberActions(info: MethodInsertionInfo): List = emptyList() - open fun createAddBeanPropertyActions(psiClass: @JvmCommon PsiClass, + open fun createAddBeanPropertyActions(uClass: UClass, propertyName: String, @PsiModifier.ModifierConstant visibilityModifier: String, propertyType: PsiType, setterRequired: Boolean, - getterRequired: Boolean): List = - //Fallback if Uast-version of method is overridden - createAddBeanPropertyActions(psiClass.asUast(), propertyName, visibilityModifier, propertyType, setterRequired, getterRequired) + getterRequired: Boolean): List = emptyList() companion object : LanguageExtension( "com.intellij.codeInsight.intention.jvmCommonIntentionActionsFactory") { @@ -62,78 +59,52 @@ abstract class JvmCommonIntentionActionsFactory { override fun forLanguage(l: Language): JvmCommonIntentionActionsFactory? = super.forLanguage(l) } - //A fallback to old api - @Deprecated("use or/and override @JvmCommon-version of this method instead") - open fun createChangeModifierAction(declaration: UDeclaration, - @PsiModifier.ModifierConstant modifier: String, - shouldPresent: Boolean): IntentionAction? = null - - @Deprecated("use or/and override @JvmCommon-version of this method instead") - open fun createAddBeanPropertyActions(uClass: UClass, - propertyName: String, - @PsiModifier.ModifierConstant visibilityModifier: String, - propertyType: PsiType, - setterRequired: Boolean, - getterRequired: Boolean): List = emptyList() - - } -@ApiStatus.Experimental +@Deprecated("to be removed in 2017.3", ReplaceWith("com.intellij.lang.jvm.actions.JvmCommonIntentionActionsFactory")) sealed class MethodInsertionInfo( - val targetClass: @JvmCommon PsiClass, + val containingClass: UClass, @PsiModifier.ModifierConstant val modifiers: List = emptyList(), val typeParams: List = emptyList(), - val parameters: List<@JvmCommon PsiParameter> = emptyList() + val parameters: List = emptyList() ) { - - @Deprecated("use `targetClass`", ReplaceWith("targetClass")) - val containingClass: UClass - get() = targetClass.asUast() - companion object { @JvmStatic - fun constructorInfo(targetClass: @JvmCommon PsiClass, parameters: List<@JvmCommon PsiParameter>) = - Constructor(targetClass = targetClass, parameters = parameters) + fun constructorInfo(containingClass: UClass, parameters: List) = + Constructor(containingClass = containingClass, parameters = parameters) @JvmStatic - fun simpleMethodInfo(containingClass: @JvmCommon PsiClass, + fun simpleMethodInfo(containingClass: UClass, methodName: String, @PsiModifier.ModifierConstant modifier: String, returnType: PsiType, - parameters: List<@JvmCommon PsiParameter>) = + parameters: List) = Method(name = methodName, modifiers = listOf(modifier), - targetClass = containingClass, + containingClass = containingClass, returnType = returnType, parameters = parameters) - } + @Deprecated("to be removed in 2017.3", ReplaceWith("com.intellij.lang.jvm.actions.JvmCommonIntentionActionsFactory")) class Method( - targetClass: @JvmCommon PsiClass, + containingClass: UClass, val name: String, modifiers: List = emptyList(), - typeParams: List<@JvmCommon PsiTypeParameter> = emptyList(), + typeParams: List = emptyList(), val returnType: PsiType, - parameters: List<@JvmCommon PsiParameter> = emptyList(), + parameters: List = emptyList(), val isAbstract: Boolean = false - ) : MethodInsertionInfo(targetClass, modifiers, typeParams, parameters) + ) : MethodInsertionInfo(containingClass, modifiers, typeParams, parameters) + @Deprecated("to be removed in 2017.3", ReplaceWith("com.intellij.lang.jvm.actions.JvmCommonIntentionActionsFactory")) class Constructor( - targetClass: @JvmCommon PsiClass, + containingClass: UClass, modifiers: List = emptyList(), - typeParams: List<@JvmCommon PsiTypeParameter> = emptyList(), - parameters: List<@JvmCommon PsiParameter> = emptyList() - ) : MethodInsertionInfo(targetClass, modifiers, typeParams, parameters) + typeParams: List = emptyList(), + parameters: List = emptyList() + ) : MethodInsertionInfo(containingClass, modifiers, typeParams, parameters) -} - -@Deprecated("remove after kotlin plugin will be ported") -private inline fun PsiElement.asUast(): T = when (this) { - is T -> this - else -> this.let { ServiceManager.getService(project, UastContext::class.java).convertElement(this, null, T::class.java) as T? } - ?: throw UnsupportedOperationException("cant convert $this to ${T::class}") } \ No newline at end of file diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactory.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactory.kt new file mode 100644 index 000000000000..12791561e58b --- /dev/null +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactory.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2017 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 com.intellij.lang.jvm.actions + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.Language +import com.intellij.lang.LanguageExtension +import com.intellij.lang.jvm.JvmClass +import com.intellij.lang.jvm.JvmModifiersOwner +import com.intellij.openapi.components.ServiceManager +import org.jetbrains.annotations.ApiStatus + +/** + * Extension Point provides language-abstracted code modifications for JVM-based languages. + * + * Each method should return list of code modifications which could be empty. + * If method returns empty list this means that operation on given elements is not supported or not yet implemented for a language. + * + * Every new added method should return empty list by default and then be overridden in implementations for each language if it is possible. + * + * @since 2017.3 + */ +@ApiStatus.Experimental +abstract class JvmElementActionsFactory { + + open fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List = emptyList() + + open fun createAddConstructorActions(targetClass: JvmClass, request: MemberRequest.Constructor): List = emptyList() + + open fun createAddMethodActions(targetClass: JvmClass, request: MemberRequest.Method): List = emptyList() + + open fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List = emptyList() + + companion object : LanguageExtension( + "com.intellij.lang.jvm.actions.jvmElementActionsFactory") { + + @JvmStatic + override fun forLanguage(l: Language): JvmElementActionsFactory? = + super.forLanguage(l) + ?: ServiceManager.getService(JvmElementActionsFactoryFallback::class.java).forLanguage(l) + } + +} + + diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactoryFallback.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactoryFallback.kt new file mode 100644 index 000000000000..3fd9fff32ab7 --- /dev/null +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/JvmElementActionsFactoryFallback.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2017 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 com.intellij.lang.jvm.actions + +import com.intellij.lang.Language + +@Deprecated("to be removed in 2017.3", ReplaceWith("use com.intellij.lang.jvm.actions.JvmElementActionsFactory")) +interface JvmElementActionsFactoryFallback { + + fun forLanguage(lang: Language): JvmElementActionsFactory? + +} \ No newline at end of file diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/MemberRequest.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/MemberRequest.kt new file mode 100644 index 000000000000..6e916427e6a6 --- /dev/null +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/MemberRequest.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2017 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 com.intellij.lang.jvm.actions + +import com.intellij.lang.jvm.JvmAnnotation +import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.JvmParameter +import com.intellij.lang.jvm.JvmTypeParameter +import com.intellij.lang.jvm.types.JvmType +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Experimental +sealed class MemberRequest { + + companion object { + + @JvmStatic + fun constructorRequest(parameters: List) = + Constructor(parameters = parameters) + + @JvmStatic + fun simpleMethodRequest(methodName: String, + annotations: List, + modifier: List, + returnType: JvmType, + parameters: List) = + Method(name = methodName, + annotations = annotations, + modifiers = modifier, + returnType = returnType, + parameters = parameters) + + @JvmStatic + fun simpleMethodRequest(methodName: String, + modifier: JvmModifier, + returnType: JvmType, + parameters: List) = + simpleMethodRequest(methodName, emptyList(), listOf(modifier), returnType, parameters) + + } + + + class Method( + val name: String, + val annotations: List = emptyList(), + val modifiers: List = emptyList(), + val typeParameters: List = emptyList(), + val returnType: JvmType, + val parameters: List = emptyList() + ) : MemberRequest() + + class Constructor( + val annotations: List = emptyList(), + val modifiers: List = emptyList(), + val typeParameters: List = emptyList(), + val parameters: List = emptyList() + ) : MemberRequest() + + class Property( + val propertyName: String, + val visibilityModifier: JvmModifier, + val propertyType: JvmType, + val setterRequired: Boolean, + val getterRequired: Boolean + ) : MemberRequest() + + class Modifier( + val modifier: JvmModifier, + val shouldPresent: Boolean + ) : MemberRequest() + +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt index 7f86add69759..9062a7c309ba 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt @@ -18,8 +18,12 @@ package com.intellij.codeInspection.inheritance import com.intellij.CommonBundle import com.intellij.codeInsight.daemon.QuickFixBundle import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory import com.intellij.codeInspection.* +import com.intellij.lang.jvm.JvmClass +import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.JvmModifiersOwner +import com.intellij.lang.jvm.actions.JvmElementActionsFactory +import com.intellij.lang.jvm.actions.MemberRequest import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project @@ -43,8 +47,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { val subclassInfos = subclassProviders.mapNotNull { it.getSubclassingInfo(aClass) } - val methodsToOverride = aClass.methods.mapNotNull { - method -> + val methodsToOverride = aClass.methods.mapNotNull { method -> subclassInfos .mapNotNull { it.methodsInfo?.get(method)?.description } .firstOrNull()?.let { description -> @@ -58,7 +61,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { val smartPointerManager = SmartPointerManager.getInstance(aClass.project) - val actionsFactory = JvmCommonIntentionActionsFactory.forLanguage(aClass.language) + val actionsFactory = JvmElementActionsFactory.forLanguage(aClass.language) for ((method, description) in methodsToOverride) { if (method.isFinal || method.isStatic || method.hasModifierProperty(PsiModifier.PRIVATE)) { @@ -91,7 +94,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { return problems.toTypedArray() } - private fun createFixesIfApplicable(actionsFactory: JvmCommonIntentionActionsFactory?, + private fun createFixesIfApplicable(actionsFactory: JvmElementActionsFactory?, aClass: UDeclaration, hintTargetName: String, methodsToAttachToClassFix: List> = emptyList()): Array { @@ -120,7 +123,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { private class MakeExtendableFix(uDeclaration: UDeclaration, hintTargetName: String, - val actionsFactory: JvmCommonIntentionActionsFactory, + val actionsFactory: JvmElementActionsFactory, val siblings: List> = emptyList()) : LocalQuickFixOnPsiElement(uDeclaration) { @@ -164,30 +167,30 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { private fun collectMakeExtendable(declaration: UDeclaration, actionsList: SmartList, checkParent: Boolean = true) { - val isClassMember = !(declaration is UClass) + val isClassMember = !(declaration is JvmClass) declaration.modifierList?.apply { - addIfApplicable(declaration, PsiModifier.FINAL, false, actionsList) - addIfApplicable(declaration, PsiModifier.PRIVATE, false, actionsList) + addIfApplicable(declaration, JvmModifier.FINAL, false, actionsList) + addIfApplicable(declaration, JvmModifier.PRIVATE, false, actionsList) if (isClassMember) { - addIfApplicable(declaration, PsiModifier.STATIC, false, actionsList) + addIfApplicable(declaration, JvmModifier.STATIC, false, actionsList) } } if (checkParent && isClassMember) { (declaration.uastParent as? UClass)?.apply { - addIfApplicable(this, PsiModifier.FINAL, false, actionsList) - addIfApplicable(this, PsiModifier.PRIVATE, false, actionsList) + addIfApplicable(this, JvmModifier.FINAL, false, actionsList) + addIfApplicable(this, JvmModifier.PRIVATE, false, actionsList) } } } - private fun addIfApplicable(declaration: UDeclaration, - name: String, + private fun addIfApplicable(declaration: JvmModifiersOwner, + modifier: JvmModifier, shouldPresent: Boolean, actionsList: SmartList) { - if (declaration.modifierList?.hasModifierProperty(name) != shouldPresent) { - (actionsFactory.createChangeModifierAction(declaration as @com.intellij.psi.JvmCommon PsiModifierListOwner, name, - shouldPresent))?.let { - actionsList.add(it) + if (declaration.hasModifier(modifier) != shouldPresent) { + actionsFactory.createChangeModifierActions(declaration, MemberRequest.Modifier(modifier, + shouldPresent)).let { + actionsList.addAll(it) } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFix.kt b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFix.kt index 798202471e86..8610e07667ad 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFix.kt +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFix.kt @@ -16,10 +16,11 @@ package com.intellij.codeInsight.daemon.impl.quickfix import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory -import com.intellij.codeInsight.intention.MethodInsertionInfo import com.intellij.codeInspection.LocalQuickFixBase import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.actions.JvmElementActionsFactory +import com.intellij.lang.jvm.actions.MemberRequest import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project import com.intellij.psi.* @@ -56,11 +57,11 @@ class CreateMethodFix(containingClass: @JvmCommon PsiClass, private val createMe @JvmStatic fun createVoidMethodIfFixPossible(psiClass: @JvmCommon PsiClass, methodName: String, - @PsiModifier.ModifierConstant modifier: String): CreateMethodFix? { + modifier: JvmModifier): CreateMethodFix? { if (!ModuleUtilCore.projectContainsFile(psiClass.project, psiClass.containingFile.virtualFile, false)) return null - val actionsFactory = JvmCommonIntentionActionsFactory.forLanguage(psiClass.language) ?: return null - val action = actionsFactory.createAddCallableMemberActions( - MethodInsertionInfo.simpleMethodInfo(psiClass, methodName, modifier, PsiType.VOID, emptyList()) + val actionsFactory = JvmElementActionsFactory.forLanguage(psiClass.language) ?: return null + val action = actionsFactory.createAddMethodActions(psiClass, + MemberRequest.simpleMethodRequest(methodName, modifier, PsiType.VOID, emptyList()) ).firstOrNull() ?: return null return CreateMethodFix(psiClass, action) } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ElementActionsFactoryUastFallback.kt b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ElementActionsFactoryUastFallback.kt new file mode 100644 index 000000000000..a52da292df75 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ElementActionsFactoryUastFallback.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2017 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 com.intellij.codeInsight.intention.impl + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.Language +import com.intellij.lang.jvm.JvmClass +import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.JvmModifiersOwner +import com.intellij.lang.jvm.actions.JvmElementActionsFactory +import com.intellij.lang.jvm.actions.JvmElementActionsFactoryFallback +import com.intellij.lang.jvm.actions.MemberRequest +import com.intellij.openapi.components.ServiceManager +import com.intellij.psi.PsiElement +import org.jetbrains.uast.* +import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory as UastJvmCommonIntentionActionsFactory +import com.intellij.codeInsight.intention.MethodInsertionInfo as UastMethodInsertionInfo + +@Deprecated("to be removed in 2017.3", ReplaceWith("use com.intellij.lang.jvm.actions.JvmElementActionsFactory")) +class ElementActionsFactoryUastFallback( + val renderer: JavaElementRenderer, + val materializer: JavaElementMaterializer +) : JvmElementActionsFactoryFallback { + override fun forLanguage(lang: Language): JvmElementActionsFactory? { + val factory = UastJvmCommonIntentionActionsFactory.forLanguage(lang) ?: return null + return object : JvmElementActionsFactory() { + + override fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List = + with(request) { + listOfNotNull( + factory.createChangeModifierAction(target.asUast(), renderer.render(modifier), shouldPresent)) + } + + override fun createAddConstructorActions(targetClass: JvmClass, request: MemberRequest.Constructor): List = + with(request) { + factory.createAddCallableMemberActions( + UastMethodInsertionInfo.Constructor( + targetClass.asUast(), + modifiers.map { renderer.render(it) }, + typeParameters.map { materializer.materialize(it) }, + parameters.map { it.asUast() } + ) + ) + } + + override fun createAddMethodActions(targetClass: JvmClass, request: MemberRequest.Method): List = + with(request) { + factory.createAddCallableMemberActions( + UastMethodInsertionInfo.Method( + targetClass.asUast(), + name, + modifiers.map { renderer.render(it) }, + typeParameters.map { materializer.materialize(it) }, + materializer.materialize(returnType), + parameters.map { it.asUast() }, + modifiers.contains(JvmModifier.ABSTRACT) + ) + ) + } + + override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List = + with(request) { + factory.createAddBeanPropertyActions(targetClass.asUast(), propertyName, + renderer.render(visibilityModifier), + materializer.materialize(propertyType), setterRequired, getterRequired) + + } + + + } + } +} + +@Deprecated("remove after kotlin plugin will be ported") +private inline fun JvmModifiersOwner.asUast(): T = when (this) { + is T -> this + is PsiElement -> this.let { + ServiceManager.getService(project, UastContext::class.java) + .convertElement(this, null, T::class.java) as T? + } + ?: throw UnsupportedOperationException("cant convert $this to ${T::class}") + else -> throw UnsupportedOperationException("cant convert $this to ${T::class}") +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaCommonIntentionActionsFactory.kt b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaCommonIntentionActionsFactory.kt deleted file mode 100644 index ea9cccd1da46..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaCommonIntentionActionsFactory.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2000-2017 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 com.intellij.codeInsight.intention.impl - -import com.intellij.codeInsight.daemon.QuickFixBundle -import com.intellij.codeInsight.daemon.impl.quickfix.AddConstructorFix -import com.intellij.codeInsight.daemon.impl.quickfix.ModifierFix -import com.intellij.codeInsight.intention.AbstractIntentionAction -import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory -import com.intellij.codeInsight.intention.MethodInsertionInfo -import com.intellij.openapi.application.runWriteAction -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project -import com.intellij.psi.* -import com.intellij.psi.codeStyle.JavaCodeStyleManager -import com.intellij.psi.impl.beanProperties.CreateJavaBeanPropertyFix -import com.intellij.psi.util.PsiFormatUtil -import com.intellij.psi.util.PsiFormatUtilBase -import com.intellij.util.VisibilityUtil -import org.jetbrains.annotations.NotNull - -class JavaCommonIntentionActionsFactory : JvmCommonIntentionActionsFactory() { - - override fun createChangeModifierAction(declaration: @JvmCommon PsiModifierListOwner, - modifier: String, - shouldPresent: Boolean): IntentionAction { - return ModifierFix(declaration.modifierList, modifier, shouldPresent, false) - } - - override fun createAddCallableMemberActions(info: MethodInsertionInfo): List { - return when (info) { - is MethodInsertionInfo.Method -> with(info) { - createAddMethodAction(targetClass, name, modifiers.joinToString(" "), returnType, parameters) - ?.let { listOf(it) } ?: emptyList() - } - - is MethodInsertionInfo.Constructor -> - listOf(AddConstructorFix(info.targetClass.javaPsi(), info.parameters.map { it.javaPsi() })) - } - } - - private fun createAddMethodAction(psiClass: @JvmCommon PsiClass, - methodName: String, - @PsiModifier.ModifierConstant @NotNull visibilityModifier: String, - returnType: PsiType, - parameters: List<@JvmCommon PsiParameter>): IntentionAction? { - val paramsString = parameters.mapIndexed { i, t -> "${t.type.canonicalText} ${t.name ?: "arg$i"}" }.joinToString() - val signatureString = - "${VisibilityUtil.getVisibilityString(visibilityModifier)} ${returnType.canonicalText} $methodName($paramsString){}" - val targetClassPointer = SmartPointerManager.getInstance(psiClass.project).createSmartPsiElementPointer(psiClass.javaPsi()) - return object : AbstractIntentionAction() { - - private val text = targetClassPointer.element?.let { psiClass -> - QuickFixBundle.message("create.method.from.usage.text", - PsiFormatUtil.formatMethod(createMethod(psiClass), PsiSubstitutor.EMPTY, - PsiFormatUtilBase.SHOW_NAME or - PsiFormatUtilBase.SHOW_TYPE or - PsiFormatUtilBase.SHOW_PARAMETERS or - PsiFormatUtilBase.SHOW_RAW_TYPE, - PsiFormatUtilBase.SHOW_TYPE or PsiFormatUtilBase.SHOW_RAW_TYPE, 2)) - } ?: "" - - override fun getText(): String = text - - override fun invoke(project: Project, editor: Editor?, file: PsiFile) { - val targetClass = targetClassPointer.element ?: return - runWriteAction { - val addedMethod = targetClass.add(createMethod(targetClass)) - JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedMethod) - } - } - - private fun createMethod(targetClass: PsiClass): PsiMethod { - val elementFactory = JVMElementFactories.getFactory(targetClass.language, targetClass.project) // it could be Groovy - ?: JavaPsiFacade.getElementFactory(targetClass.project) - return elementFactory.createMethodFromText(signatureString, targetClass) - } - } - } - - private inline fun T.javaPsi(): T = - when (this) { - is org.jetbrains.uast.UElement -> this.psi as T - else -> this - } - - override fun createAddBeanPropertyActions(psiClass: @JvmCommon PsiClass, - propertyName: String, - @PsiModifier.ModifierConstant visibilityModifier: String, - propertyType: PsiType, - setterRequired: Boolean, - getterRequired: Boolean): List { - if (getterRequired && setterRequired) - return listOf( - CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired, - true), - CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired, - false)) - if (getterRequired || setterRequired) - return listOf( - CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired, - true), - CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired, - false), - CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, true, true, true)) - - return listOf( - CreateJavaBeanPropertyFix(psiClass.javaPsi(), propertyName, propertyType, getterRequired, setterRequired, true)) - } - -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactoryImpl.kt b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactoryImpl.kt new file mode 100644 index 000000000000..8566aa149f2d --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JavaElementActionsFactoryImpl.kt @@ -0,0 +1,193 @@ +/* + * Copyright 2000-2017 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 com.intellij.codeInsight.intention.impl + +import com.intellij.codeInsight.daemon.QuickFixBundle +import com.intellij.codeInsight.daemon.impl.quickfix.AddConstructorFix +import com.intellij.codeInsight.daemon.impl.quickfix.ModifierFix +import com.intellij.codeInsight.intention.AbstractIntentionAction +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.jvm.* +import com.intellij.lang.jvm.actions.JvmElementActionsFactory +import com.intellij.lang.jvm.actions.MemberRequest +import com.intellij.lang.jvm.types.JvmType +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.* +import com.intellij.psi.codeStyle.JavaCodeStyleManager +import com.intellij.psi.impl.beanProperties.CreateJavaBeanPropertyFix +import com.intellij.psi.util.PsiFormatUtil +import com.intellij.psi.util.PsiFormatUtilBase + +class JavaElementActionsFactoryImpl( + private val materializer: JavaElementMaterializer, + private val renderer: JavaElementRenderer +) : JvmElementActionsFactory() { + + override fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List = with( + request) { + val declaration = target as PsiModifierListOwner + listOf(ModifierFix(declaration.modifierList, renderer.render(modifier), shouldPresent, false)) + } + + override fun createAddConstructorActions(targetClass: JvmClass, request: MemberRequest.Constructor): List = + with(request) { + val targetClass = materializer.materialize(targetClass) + val factory = JVMElementFactories.getFactory(targetClass.language, targetClass.project)!! + listOf(AddConstructorFix(targetClass, request.parameters.mapIndexed { i, it -> + factory.createParameter(it.name ?: "arg$i", materializer.materialize(it.type), targetClass) + })) + } + + override fun createAddMethodActions(targetClass: JvmClass, request: MemberRequest.Method): List = + with(request) { + createAddMethodAction(targetClass, request) + ?.let { listOf(it) } ?: emptyList() + } + + override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List { + with(request) { + val psiClass = materializer.materialize(targetClass) + val propertyType = materializer.materialize(propertyType) + if (getterRequired && setterRequired) + return listOf( + CreateJavaBeanPropertyFix(psiClass, propertyName, propertyType, getterRequired, setterRequired, + true), + CreateJavaBeanPropertyFix(psiClass, propertyName, propertyType, getterRequired, setterRequired, + false)) + if (getterRequired || setterRequired) + return listOf( + CreateJavaBeanPropertyFix(psiClass, propertyName, propertyType, getterRequired, setterRequired, + true), + CreateJavaBeanPropertyFix(psiClass, propertyName, propertyType, getterRequired, setterRequired, + false), + CreateJavaBeanPropertyFix(psiClass, propertyName, propertyType, true, true, true)) + + return listOf( + CreateJavaBeanPropertyFix(psiClass, propertyName, propertyType, getterRequired, setterRequired, true)) + } + } + + + private fun createAddMethodAction(psiClass: JvmClass, request: MemberRequest.Method): IntentionAction? { + with(request) { + val psiClass = materializer.materialize(psiClass) + val signatureString = with(renderer) { + val paramsString = parameters.mapIndexed { i, t -> "${render(t.type)} ${t.name ?: "arg$i"}" }.joinToString() + val modifiersString = (annotations.map { render(it) } + modifiers.map { render(it) }).joinToString(" ") + "${modifiersString} ${render(returnType)} $name($paramsString){}" + } + val targetClassPointer = SmartPointerManager.getInstance(psiClass.project).createSmartPsiElementPointer(psiClass) + return object : AbstractIntentionAction() { + + private val text = targetClassPointer.element?.let { psiClass -> + QuickFixBundle.message("create.method.from.usage.text", + PsiFormatUtil.formatMethod(createMethod(psiClass), PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME or + PsiFormatUtilBase.SHOW_TYPE or + PsiFormatUtilBase.SHOW_PARAMETERS or + PsiFormatUtilBase.SHOW_RAW_TYPE, + PsiFormatUtilBase.SHOW_TYPE or PsiFormatUtilBase.SHOW_RAW_TYPE, 2)) + } ?: "" + + override fun getText(): String = text + + override fun invoke(project: Project, editor: Editor?, file: PsiFile) { + val targetClass = targetClassPointer.element ?: return + runWriteAction { + val addedMethod = targetClass.add(createMethod(targetClass)) + JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedMethod) + } + } + + private fun createMethod(targetClass: PsiClass): PsiMethod { + val elementFactory = JVMElementFactories.getFactory(targetClass.language, targetClass.project) // it could be Groovy + ?: JavaPsiFacade.getElementFactory(targetClass.project) + return elementFactory.createMethodFromText(signatureString, targetClass) + } + } + } + } + +} + +class JavaElementRenderer { + companion object { + @JvmStatic + fun getInstance(): JavaElementRenderer { + return ServiceManager.getService(JavaElementRenderer::class.java) + } + } + + + fun render(visibilityModifiers: List): String = + visibilityModifiers.joinToString(" ") { render(it) } + + fun render(jvmType: JvmType): String = + (jvmType as PsiType).canonicalText + + fun render(jvmAnnotation: JvmAnnotation): String = + "@" + (jvmAnnotation as PsiAnnotation).qualifiedName!! + + @PsiModifier.ModifierConstant + fun render(modifier: JvmModifier): String = when (modifier) { + JvmModifier.PUBLIC -> PsiModifier.PUBLIC + JvmModifier.PROTECTED -> PsiModifier.PROTECTED + JvmModifier.PRIVATE -> PsiModifier.PRIVATE + JvmModifier.PACKAGE_LOCAL -> "" + JvmModifier.STATIC -> PsiModifier.STATIC + JvmModifier.ABSTRACT -> PsiModifier.ABSTRACT + JvmModifier.FINAL -> PsiModifier.FINAL + JvmModifier.DEFAULT -> PsiModifier.DEFAULT + JvmModifier.NATIVE -> PsiModifier.NATIVE + JvmModifier.SYNCHRONIZED -> PsiModifier.NATIVE + JvmModifier.STRICTFP -> PsiModifier.STRICTFP + JvmModifier.TRANSIENT -> PsiModifier.TRANSIENT + JvmModifier.VOLATILE -> PsiModifier.VOLATILE + JvmModifier.TRANSITIVE -> PsiModifier.TRANSITIVE + } + +} + +class JavaElementMaterializer { + + companion object { + @JvmStatic + fun getInstance(): JavaElementMaterializer { + return ServiceManager.getService(JavaElementMaterializer::class.java) + } + } + + + fun materialize(jvmType: JvmType): PsiType { + return jvmType as PsiType //TODO:probably it could be not so easy sometimes + } + + fun materialize(jvmClass: JvmClass): PsiClass { + return jvmClass as PsiClass //TODO:probably it could be not so easy sometimes + } + + fun materialize(jvmParameter: JvmParameter): PsiParameter { + return jvmParameter as PsiParameter //TODO:probably it could be not so easy sometimes + } + + fun materialize(jvmTypeParameter: JvmTypeParameter): PsiTypeParameter { + return jvmTypeParameter as PsiTypeParameter //TODO:probably it could be not so easy sometimes + } + +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateBeanPropertyFixes.java b/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateBeanPropertyFixes.java index 1f1cd47a37ca..e1f66967deff 100644 --- a/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateBeanPropertyFixes.java +++ b/java/java-impl/src/com/intellij/psi/impl/beanProperties/CreateBeanPropertyFixes.java @@ -16,9 +16,11 @@ package com.intellij.psi.impl.beanProperties; import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory; import com.intellij.codeInspection.IntentionWrapper; import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.lang.jvm.JvmModifier; +import com.intellij.lang.jvm.actions.JvmElementActionsFactory; +import com.intellij.lang.jvm.actions.MemberRequest; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -51,10 +53,11 @@ public class CreateBeanPropertyFixes { if (aClass == null) return IntentionAction.EMPTY_ARRAY; type = facade.getElementFactory().createType(aClass); } - JvmCommonIntentionActionsFactory factory = JvmCommonIntentionActionsFactory.forLanguage(psiClass.getLanguage()); + JvmElementActionsFactory factory = JvmElementActionsFactory.forLanguage(psiClass.getLanguage()); if (factory == null) return IntentionAction.EMPTY_ARRAY; return toObjectArray( - factory.createAddBeanPropertyActions(psiClass, propertyName, PsiModifier.PUBLIC, type, createSetter, !createSetter), + factory.createAddPropertyActions(psiClass, + new MemberRequest.Property(propertyName, JvmModifier.PUBLIC, type, createSetter, !createSetter)), IntentionAction.class); } } diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index b872c2fe6ace..059253f33d39 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -337,8 +337,8 @@ - + diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java index b4fce902a350..96245645d04a 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java @@ -16,9 +16,9 @@ package org.jetbrains.plugins.javaFX.fxml.refs; import com.intellij.codeInsight.daemon.QuickFixActionRegistrar; -import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory; -import com.intellij.codeInsight.intention.MethodInsertionInfo; import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; +import com.intellij.lang.jvm.actions.JvmElementActionsFactory; +import com.intellij.lang.jvm.actions.MemberRequest; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; @@ -103,21 +103,21 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase + + + @@ -508,6 +512,13 @@ + + + + + + @@ -2002,7 +2013,8 @@ - +