From d7a9d86415cd0c73a2e12c8cc1ea3419952ee824 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Wed, 8 Nov 2017 20:02:11 +0300 Subject: [PATCH] [jvm-lang] java: extract common template setup logic --- .../lang/java/actions/CreateMethodAction.kt | 72 +++---------------- .../intellij/lang/java/actions/jvmPsiUtil.kt | 6 ++ .../intellij/lang/java/actions/templates.kt | 56 +++++++++++++++ 3 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 java/java-impl/src/com/intellij/lang/java/actions/templates.kt diff --git a/java/java-impl/src/com/intellij/lang/java/actions/CreateMethodAction.kt b/java/java-impl/src/com/intellij/lang/java/actions/CreateMethodAction.kt index 5313f369de67..377642e5b30d 100644 --- a/java/java-impl/src/com/intellij/lang/java/actions/CreateMethodAction.kt +++ b/java/java-impl/src/com/intellij/lang/java/actions/CreateMethodAction.kt @@ -1,25 +1,12 @@ -/* - * 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.lang.java.actions import com.intellij.codeInsight.CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement import com.intellij.codeInsight.daemon.QuickFixBundle.message import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageBaseFix import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageBaseFix.positionCursor -import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils.* +import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils.setupEditor +import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils.setupMethodBody import com.intellij.codeInsight.daemon.impl.quickfix.GuessTypeParameters import com.intellij.codeInsight.intention.impl.BaseIntentionAction import com.intellij.codeInsight.template.Template @@ -29,14 +16,10 @@ import com.intellij.codeInsight.template.TemplateEditingAdapter import com.intellij.lang.java.request.CreateMethodFromJavaUsageRequest import com.intellij.lang.jvm.JvmModifier import com.intellij.lang.jvm.actions.CreateMethodRequest -import com.intellij.lang.jvm.actions.ExpectedTypes import com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Computable import com.intellij.psi.* -import com.intellij.psi.codeStyle.CodeStyleManager -import com.intellij.psi.codeStyle.SuggestedNameInfo import com.intellij.psi.presentation.java.ClassPresentationUtil.getNameForClass import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiUtil @@ -159,40 +142,18 @@ private class JavaMethodRenderer( private fun setupTemplate(method: PsiMethod): TemplateBuilderImpl { val builder = TemplateBuilderImpl(method) - val substitutor = request.targetSubstitutor.toPsiSubstitutor(project) - val guesser = GuessTypeParameters(project, factory, builder, substitutor) - setupTypeElement(guesser, method.returnTypeElement, request.returnType) - builder.setupParameters(guesser, method) + createTemplateContext(builder).run { + setupTypeElement(method.returnTypeElement, request.returnType) + setupParameters(method, request.parameters) + } builder.setEndVariableAfter(method.body ?: method) return builder } - private fun setupTypeElement(guesser: GuessTypeParameters, typeElement: PsiTypeElement?, types: ExpectedTypes) { - typeElement ?: return - val expectedTypes = extractExpectedTypes(project, types).toTypedArray() - guesser.setupTypeElement(typeElement, expectedTypes, javaUsage?.context, targetClass) - } - - private fun TemplateBuilder.setupParameters(guesser: GuessTypeParameters, method: PsiMethod) { - val parameters = request.parameters - if (parameters.isEmpty()) return - val codeStyleManager = CodeStyleManager.getInstance(project)!! - val parameterList = method.parameterList - val isInterface = targetClass.isInterface - //255 is the maximum number of method parameters - for (i in 0 until minOf(parameters.size, 255)) { - val parameterInfo = parameters[i] - val names = extractNames(parameterInfo.first) { "p" + i } - val dummyParameter = factory.createParameter(names.first(), PsiType.INT) - if (isInterface) { - setModifierProperty(dummyParameter, PsiModifier.FINAL, false) - } - val parameter = codeStyleManager.performActionWithFormatterDisabled(Computable { - parameterList.add(dummyParameter) - }) as PsiParameter - setupTypeElement(guesser, parameter.typeElement, parameterInfo.second) - setupParameterName(parameter, names) - } + private fun createTemplateContext(builder: TemplateBuilder): TemplateContext { + val substitutor = request.targetSubstitutor.toPsiSubstitutor(project) + val guesser = GuessTypeParameters(project, factory, builder, substitutor) + return TemplateContext(project, factory, targetClass, builder, guesser, javaUsage?.context) } private fun startTemplate(method: PsiMethod, template: Template) { @@ -203,17 +164,6 @@ private class JavaMethodRenderer( } } -private inline fun extractNames(suggestedNames: SuggestedNameInfo?, defaultName: () -> String): Array { - val names = (suggestedNames ?: SuggestedNameInfo.NULL_INFO).names - return if (names.isEmpty()) arrayOf(defaultName()) else names -} - -private fun TemplateBuilder.setupParameterName(parameter: PsiParameter, names: Array) { - val nameIdentifier = parameter.nameIdentifier ?: return - val expression = ParameterNameExpression(names) - replaceElement(nameIdentifier, expression) -} - private class MyMethodBodyListener(val project: Project, val editor: Editor, val file: PsiFile) : TemplateEditingAdapter() { override fun templateFinished(template: Template, brokenOff: Boolean) { diff --git a/java/java-impl/src/com/intellij/lang/java/actions/jvmPsiUtil.kt b/java/java-impl/src/com/intellij/lang/java/actions/jvmPsiUtil.kt index efce5abd2dfe..239a63f8bcab 100644 --- a/java/java-impl/src/com/intellij/lang/java/actions/jvmPsiUtil.kt +++ b/java/java-impl/src/com/intellij/lang/java/actions/jvmPsiUtil.kt @@ -14,6 +14,7 @@ import com.intellij.lang.jvm.types.JvmSubstitutor import com.intellij.openapi.project.Project import com.intellij.psi.* import com.intellij.psi.PsiModifier.ModifierConstant +import com.intellij.psi.codeStyle.SuggestedNameInfo import com.intellij.psi.impl.compiled.ClsClassImpl @ModifierConstant @@ -78,3 +79,8 @@ private fun ExpectedType.Kind.infoKind(): Int { internal fun JvmSubstitutor.toPsiSubstitutor(project: Project): PsiSubstitutor { return JvmPsiConversionHelper.getInstance(project).convertSubstitutor(this) } + +internal inline fun extractNames(suggestedNames: SuggestedNameInfo?, defaultName: () -> String): Array { + val names = (suggestedNames ?: SuggestedNameInfo.NULL_INFO).names + return if (names.isEmpty()) arrayOf(defaultName()) else names +} diff --git a/java/java-impl/src/com/intellij/lang/java/actions/templates.kt b/java/java-impl/src/com/intellij/lang/java/actions/templates.kt new file mode 100644 index 000000000000..ba80c233a95f --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/actions/templates.kt @@ -0,0 +1,56 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.lang.java.actions + +import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils +import com.intellij.codeInsight.daemon.impl.quickfix.GuessTypeParameters +import com.intellij.codeInsight.template.TemplateBuilder +import com.intellij.lang.jvm.actions.ExpectedParameters +import com.intellij.lang.jvm.actions.ExpectedTypes +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Computable +import com.intellij.psi.* +import com.intellij.psi.codeStyle.CodeStyleManager +import com.intellij.psi.util.PsiUtil + +internal class TemplateContext( + val project: Project, + val factory: PsiElementFactory, + val targetClass: PsiClass, + val builder: TemplateBuilder, + val guesser: GuessTypeParameters, + val guesserContext: PsiElement? +) + +internal fun TemplateContext.setupParameters(method: PsiMethod, parameters: ExpectedParameters) { + if (parameters.isEmpty()) return + val codeStyleManager = CodeStyleManager.getInstance(project)!! + val parameterList = method.parameterList + val isInterface = targetClass.isInterface + + //255 is the maximum number of method parameters + for (i in 0 until minOf(parameters.size, 255)) { + val parameterInfo = parameters[i] + val names = extractNames(parameterInfo.first) { "p" + i } + val dummyParameter = factory.createParameter(names.first(), PsiType.INT) + if (isInterface) { + PsiUtil.setModifierProperty(dummyParameter, PsiModifier.FINAL, false) + } + val parameter = codeStyleManager.performActionWithFormatterDisabled(Computable { + parameterList.add(dummyParameter) + }) as PsiParameter + setupTypeElement(parameter.typeElement, parameterInfo.second) + setupParameterName(parameter, names) + } +} + +internal fun TemplateContext.setupTypeElement(typeElement: PsiTypeElement?, types: ExpectedTypes) { + typeElement ?: return + val expectedTypes = extractExpectedTypes(project, types).toTypedArray() + guesser.setupTypeElement(typeElement, expectedTypes, guesserContext, targetClass) +} + +internal fun TemplateContext.setupParameterName(parameter: PsiParameter, names: Array) { + val nameIdentifier = parameter.nameIdentifier ?: return + val expression = CreateFromUsageUtils.ParameterNameExpression(names) + builder.replaceElement(nameIdentifier, expression) +}