mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
[jvm-lang] java: port _Create getter/setter from usage_ actions
- extract PropertyRenderer for reusing; - make them work with type parameter guesser.
This commit is contained in:
@@ -468,7 +468,6 @@ public class HighlightMethodUtil {
|
||||
else {
|
||||
TextRange range = getFixRange(methodCall);
|
||||
registerUsageFixes(methodCall, highlightInfo, range);
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreatePropertyFromUsageFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createStaticImportMethodFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createQualifyStaticMethodCallFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.addMethodQualifierFix(methodCall));
|
||||
@@ -498,6 +497,7 @@ public class HighlightMethodUtil {
|
||||
else {
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreateMethodFromUsageFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreateAbstractMethodFromUsageFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreatePropertyFromUsageFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, range, QUICK_FIX_FACTORY.createCreateGetterSetterPropertyFromUsageFix(methodCall));
|
||||
}
|
||||
}
|
||||
@@ -849,7 +849,6 @@ public class HighlightMethodUtil {
|
||||
registerUsageFixes(methodCall, highlightInfo, fixRange);
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateConstructorFromSuperFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreateConstructorFromThisFix(methodCall));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createCreatePropertyFromUsageFix(methodCall));
|
||||
CandidateInfo[] methodCandidates = resolveHelper.getReferencedMethodCandidates(methodCall, false);
|
||||
CastMethodArgumentFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
|
||||
PermuteArgumentsFix.registerFix(highlightInfo, methodCall, methodCandidates, fixRange);
|
||||
|
||||
@@ -38,3 +38,15 @@ object CreatePropertyActionGroup : JvmActionGroup {
|
||||
return message("create.property.from.usage.text", requireNotNull(data?.entityName))
|
||||
}
|
||||
}
|
||||
|
||||
object CreateReadOnlyPropertyActionGroup : JvmActionGroup {
|
||||
override fun getDisplayText(data: JvmActionGroup.RenderData?): String {
|
||||
return message("create.getter")
|
||||
}
|
||||
}
|
||||
|
||||
object CreateWriteOnlyPropertyActionGroup : JvmActionGroup {
|
||||
override fun getDisplayText(data: JvmActionGroup.RenderData?): String {
|
||||
return message("create.setter")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ class JavaElementActionsFactory(private val renderer: JavaElementRenderer) : Jvm
|
||||
}
|
||||
if (!javaClass.isInterface) {
|
||||
result += CreatePropertyAction(javaClass, request)
|
||||
result += CreateGetterWithFieldAction(javaClass, request)
|
||||
result += CreateSetterWithFieldAction(javaClass, request)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2000-2018 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.QuickFixBundle.message
|
||||
import com.intellij.codeInsight.generation.GenerateMembersUtil.generateSimpleGetterPrototype
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.lang.java.beans.PropertyKind
|
||||
import com.intellij.lang.jvm.actions.CreateMethodRequest
|
||||
import com.intellij.lang.jvm.actions.CreateReadOnlyPropertyActionGroup
|
||||
import com.intellij.lang.jvm.actions.JvmActionGroup
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
/**
|
||||
* This action renders a read-only property (field + getter) in Java class when getter is requested.
|
||||
*/
|
||||
internal class CreateGetterWithFieldAction(target: PsiClass, request: CreateMethodRequest) : CreatePropertyActionBase(target, request) {
|
||||
|
||||
override fun getActionGroup(): JvmActionGroup = CreateReadOnlyPropertyActionGroup
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean {
|
||||
return super.isAvailable(project, editor, file) && propertyInfo.second != PropertyKind.SETTER
|
||||
}
|
||||
|
||||
override fun getText(): String = message("create.getter")
|
||||
|
||||
override fun createRenderer(project: Project) = object : PropertyRenderer(project, target, request, propertyInfo) {
|
||||
|
||||
override fun fillTemplate(builder: TemplateBuilderImpl): RangeExpression {
|
||||
val prototypeField = generatePrototypeField()
|
||||
val prototype = generateSimpleGetterPrototype(prototypeField)
|
||||
val accessor = insertAccessor(prototype)
|
||||
val data = accessor.extractGetterTemplateData()
|
||||
return builder.setupInput(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,26 @@
|
||||
// Copyright 2000-2018 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.ExpectedTypeInfo
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle.message
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageBaseFix.positionCursor
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils.ParameterNameExpression
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.GuessTypeParameters
|
||||
import com.intellij.codeInsight.generation.GenerateMembersUtil.generateSimpleGetterPrototype
|
||||
import com.intellij.codeInsight.generation.GenerateMembersUtil.generateSimpleSetterPrototype
|
||||
import com.intellij.codeInsight.template.TemplateBuilder
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.codeInsight.template.TemplateManager
|
||||
import com.intellij.codeInsight.template.impl.VariableNode
|
||||
import com.intellij.lang.java.beans.PropertyKind
|
||||
import com.intellij.lang.java.beans.PropertyKind.*
|
||||
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.CreatePropertyActionGroup
|
||||
import com.intellij.lang.jvm.actions.JvmActionGroup
|
||||
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.codeStyle.VariableKind
|
||||
import com.intellij.psi.presentation.java.ClassPresentationUtil.getNameForClass
|
||||
import com.intellij.psi.util.PropertyUtilBase.getAccessorName
|
||||
import com.intellij.util.component1
|
||||
import com.intellij.util.component2
|
||||
|
||||
/**
|
||||
* This action renders a property (field + getter + setter) in Java class when getter or a setter is requested.
|
||||
*/
|
||||
internal class CreatePropertyAction(target: PsiClass, request: CreateMethodRequest) : CreatePropertyActionBase(target, request) {
|
||||
|
||||
companion object {
|
||||
private const val SETTER_PARAM_NAME = "SETTER_PARAM_NAME"
|
||||
}
|
||||
|
||||
override fun getActionGroup(): JvmActionGroup = CreatePropertyActionGroup
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean {
|
||||
@@ -61,61 +43,32 @@ internal class CreatePropertyAction(target: PsiClass, request: CreateMethodReque
|
||||
|
||||
override fun getText(): String = message("create.property.from.usage.full.text", propertyInfo.first, getNameForClass(target, false))
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
|
||||
val factory = JavaPsiFacade.getInstance(project).elementFactory
|
||||
val codeStyleManager = JavaCodeStyleManager.getInstance(project)!!
|
||||
override fun createRenderer(project: Project): PropertyRenderer = object : PropertyRenderer(project, target, request, propertyInfo) {
|
||||
|
||||
val (propertyName, propertyKind) = propertyInfo
|
||||
val target = target
|
||||
|
||||
val isStatic = JvmModifier.STATIC in request.modifiers
|
||||
|
||||
val suggestedFieldName = run {
|
||||
val kind = if (isStatic) VariableKind.STATIC_FIELD else VariableKind.FIELD
|
||||
codeStyleManager.propertyNameToVariableName(propertyName, kind)
|
||||
private fun generatePrototypes(): Pair<PsiMethod, PsiMethod> {
|
||||
val prototypeField = generatePrototypeField()
|
||||
val getter = generateSimpleGetterPrototype(prototypeField)
|
||||
val setter = generateSimpleSetterPrototype(prototypeField, target)
|
||||
return getter to setter
|
||||
}
|
||||
|
||||
fun insertPrototypes(): Pair<PsiMethod, PsiMethod> {
|
||||
val prototypeType = if (propertyKind == BOOLEAN_GETTER) PsiType.BOOLEAN else PsiType.VOID
|
||||
val field = factory.createField(suggestedFieldName, prototypeType).setStatic(isStatic)
|
||||
|
||||
val getterPrototype = generateSimpleGetterPrototype(field)
|
||||
val setterPrototype = generateSimpleSetterPrototype(field, target)
|
||||
|
||||
private fun insertPrototypes(): Pair<PsiMethod, PsiMethod> {
|
||||
val (getterPrototype, setterPrototype) = generatePrototypes()
|
||||
return if (propertyKind == SETTER) {
|
||||
// Technology isn't there yet. See related: WEB-26575.
|
||||
// We can't recalculate template segments which start before the current segment,
|
||||
// so we add the setter before the getter.
|
||||
val setter = forcePsiPostprocessAndRestoreElement(target.add(setterPrototype)) as PsiMethod
|
||||
val getter = forcePsiPostprocessAndRestoreElement(target.add(getterPrototype)) as PsiMethod
|
||||
val setter = insertAccessor(setterPrototype)
|
||||
val getter = insertAccessor(getterPrototype)
|
||||
getter to setter
|
||||
}
|
||||
else {
|
||||
val getter = forcePsiPostprocessAndRestoreElement(target.add(getterPrototype)) as PsiMethod
|
||||
val setter = forcePsiPostprocessAndRestoreElement(target.add(setterPrototype)) as PsiMethod
|
||||
val getter = insertAccessor(getterPrototype)
|
||||
val setter = insertAccessor(setterPrototype)
|
||||
getter to setter
|
||||
}
|
||||
}
|
||||
|
||||
val (getter, setter) = insertPrototypes()
|
||||
|
||||
val expectedTypes: List<ExpectedTypeInfo> = when (propertyKind) {
|
||||
PropertyKind.GETTER -> extractExpectedTypes(project, request.returnType)
|
||||
PropertyKind.BOOLEAN_GETTER -> listOf(PsiType.BOOLEAN.toExpectedType())
|
||||
PropertyKind.SETTER -> extractExpectedTypes(project, request.parameters.single().second)
|
||||
}
|
||||
|
||||
fun TemplateBuilder.createTemplateContext(): TemplateContext {
|
||||
val substitutor = request.targetSubstitutor.toPsiSubstitutor(project)
|
||||
val guesserContext = (request as? CreateMethodFromJavaUsageRequest)?.context
|
||||
val guesser = GuessTypeParameters(project, factory, this, substitutor)
|
||||
return TemplateContext(project, factory, target, this, guesser, guesserContext)
|
||||
}
|
||||
|
||||
val targetFile = target.containingFile
|
||||
val targetDocument = requireNotNull(targetFile.viewProvider.document)
|
||||
val targetEditor = positionCursor(project, targetFile, target) ?: return
|
||||
|
||||
/**
|
||||
* Given user want to create a property from a getter reference, such as getFoo.
|
||||
* In this case we insert both dummy getter and dummy setter.
|
||||
@@ -130,41 +83,25 @@ internal class CreatePropertyAction(target: PsiClass, request: CreateMethodReque
|
||||
*
|
||||
* 3. Setter parameter name template is added in any case.
|
||||
*/
|
||||
fun TemplateBuilderImpl.setupTemplate(input: AccessorTemplateData, mirror: AccessorTemplateData): RangeExpression {
|
||||
val templateTypeElement = createTemplateContext().setupTypeElement(input.typeElement, expectedTypes)
|
||||
val typeExpression = RangeExpression(targetDocument, templateTypeElement.textRange)
|
||||
replaceElement(mirror.typeElement, typeExpression, false) // copy type text to mirror
|
||||
override fun fillTemplate(builder: TemplateBuilderImpl): RangeExpression {
|
||||
val (getter, setter) = insertPrototypes()
|
||||
|
||||
val fieldExpression = FieldExpression(project, target, suggestedFieldName) { typeExpression.text }
|
||||
replaceElement(input.fieldRef, FIELD_VARIABLE, fieldExpression, true)
|
||||
replaceElement(mirror.fieldRef, VariableNode(FIELD_VARIABLE, null), false) // copy field name to mirror
|
||||
val getterData = getter.extractGetterTemplateData()
|
||||
val setterData = setter.extractSetterTemplateData()
|
||||
|
||||
input.endElement?.let(::setEndVariableAfter)
|
||||
val getterTemplate = propertyKind != SETTER
|
||||
val inputData = if (getterTemplate) getterData else setterData
|
||||
val mirrorData = if (getterTemplate) setterData else getterData
|
||||
|
||||
val typeExpression = builder.setupInput(inputData)
|
||||
builder.setupMirror(mirrorData, typeExpression)
|
||||
builder.setupSetterParameter(setterData)
|
||||
return typeExpression
|
||||
}
|
||||
|
||||
fun TemplateBuilderImpl.setupSetterParameter(data: SetterTemplateData) {
|
||||
val suggestedNameInfo = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, propertyName, null, null)
|
||||
val setterParameterExpression = ParameterNameExpression(suggestedNameInfo.names)
|
||||
replaceElement(data.parameterName, SETTER_PARAM_NAME, setterParameterExpression, true)
|
||||
replaceElement(data.parameterRef, VariableNode(SETTER_PARAM_NAME, null), false) // copy setter parameter name to mirror
|
||||
private fun TemplateBuilderImpl.setupMirror(mirror: AccessorTemplateData, typeExpression: RangeExpression) {
|
||||
replaceElement(mirror.typeElement, typeExpression, false) // copy type text to mirror
|
||||
replaceElement(mirror.fieldRef, VariableNode(FIELD_VARIABLE, null), false) // copy field name to mirror
|
||||
}
|
||||
|
||||
val getterData = getter.extractGetterTemplateData()
|
||||
val setterData = setter.extractSetterTemplateData()
|
||||
val builder = TemplateBuilderImpl(target)
|
||||
val typeExpression = if (propertyKind == SETTER) {
|
||||
builder.setupTemplate(setterData, getterData)
|
||||
}
|
||||
else {
|
||||
builder.setupTemplate(getterData, setterData)
|
||||
}
|
||||
builder.setupSetterParameter(setterData)
|
||||
|
||||
val template = builder.buildInlineTemplate().apply {
|
||||
isToShortenLongNames = true
|
||||
}
|
||||
val listener = InsertMissingFieldTemplateListener(project, target, typeExpression, isStatic)
|
||||
TemplateManager.getInstance(project).startTemplate(targetEditor, template, listener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.intellij.lang.jvm.actions.JvmActionGroup
|
||||
import com.intellij.lang.jvm.actions.JvmGroupIntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiNameHelper
|
||||
@@ -47,4 +46,10 @@ internal abstract class CreatePropertyActionBase(
|
||||
protected val propertyInfo: Pair<String, PropertyKind> get() = requireNotNull(doGetPropertyInfo()).toNotNull()
|
||||
|
||||
override fun getRenderData() = JvmActionGroup.RenderData { propertyInfo.first }
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
|
||||
createRenderer(project).doRender()
|
||||
}
|
||||
|
||||
abstract fun createRenderer(project: Project): PropertyRenderer
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2000-2018 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.QuickFixBundle.message
|
||||
import com.intellij.codeInsight.generation.GenerateMembersUtil.generateSimpleSetterPrototype
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.lang.java.beans.PropertyKind
|
||||
import com.intellij.lang.jvm.actions.CreateMethodRequest
|
||||
import com.intellij.lang.jvm.actions.CreateWriteOnlyPropertyActionGroup
|
||||
import com.intellij.lang.jvm.actions.JvmActionGroup
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
/**
|
||||
* This action renders a write-only property (field + setter) in Java class when setter is requested.
|
||||
*/
|
||||
internal class CreateSetterWithFieldAction(target: PsiClass, request: CreateMethodRequest) : CreatePropertyActionBase(target, request) {
|
||||
|
||||
override fun getActionGroup(): JvmActionGroup = CreateWriteOnlyPropertyActionGroup
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean {
|
||||
return super.isAvailable(project, editor, file) && propertyInfo.second == PropertyKind.SETTER
|
||||
}
|
||||
|
||||
override fun getText(): String = message("create.setter")
|
||||
|
||||
override fun createRenderer(project: Project) = object : PropertyRenderer(project, target, request, propertyInfo) {
|
||||
|
||||
override fun fillTemplate(builder: TemplateBuilderImpl): RangeExpression {
|
||||
val prototypeField = generatePrototypeField()
|
||||
val prototype = generateSimpleSetterPrototype(prototypeField, target)
|
||||
val accessor = insertAccessor(prototype)
|
||||
val data = accessor.extractSetterTemplateData()
|
||||
val typeExpression = builder.setupInput(data)
|
||||
builder.setupSetterParameter(data)
|
||||
return typeExpression
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2000-2018 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.ExpectedTypeInfo
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageBaseFix.positionCursor
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils.ParameterNameExpression
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.GuessTypeParameters
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.codeInsight.template.TemplateManager
|
||||
import com.intellij.codeInsight.template.impl.VariableNode
|
||||
import com.intellij.lang.java.beans.PropertyKind
|
||||
import com.intellij.lang.java.request.CreateMethodFromJavaUsageRequest
|
||||
import com.intellij.lang.jvm.JvmModifier
|
||||
import com.intellij.lang.jvm.actions.CreateMethodRequest
|
||||
import com.intellij.openapi.editor.Document
|
||||
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.codeStyle.VariableKind
|
||||
|
||||
internal abstract class PropertyRenderer(
|
||||
private val project: Project,
|
||||
private val target: PsiClass,
|
||||
private val request: CreateMethodRequest,
|
||||
nameKind: Pair<String, PropertyKind>
|
||||
) {
|
||||
|
||||
protected val factory = JavaPsiFacade.getInstance(project).elementFactory
|
||||
private val codeStyleManager = JavaCodeStyleManager.getInstance(project)!!
|
||||
private val javaUsage = request as? CreateMethodFromJavaUsageRequest
|
||||
private val isStatic = JvmModifier.STATIC in request.modifiers
|
||||
private val propertyName = nameKind.first
|
||||
protected val propertyKind = nameKind.second
|
||||
|
||||
private val suggestedFieldName = run {
|
||||
val kind = if (isStatic) VariableKind.STATIC_FIELD else VariableKind.FIELD
|
||||
codeStyleManager.propertyNameToVariableName(propertyName, kind)
|
||||
}
|
||||
|
||||
protected fun generatePrototypeField(): PsiField {
|
||||
val prototypeType = if (propertyKind == PropertyKind.BOOLEAN_GETTER) PsiType.BOOLEAN else PsiType.VOID
|
||||
return factory.createField(suggestedFieldName, prototypeType).setStatic(isStatic)
|
||||
}
|
||||
|
||||
private val expectedTypes: List<ExpectedTypeInfo> = when (propertyKind) {
|
||||
PropertyKind.GETTER -> extractExpectedTypes(project, request.returnType).orObject(target)
|
||||
PropertyKind.BOOLEAN_GETTER -> listOf(PsiType.BOOLEAN.toExpectedType())
|
||||
PropertyKind.SETTER -> extractExpectedTypes(project, request.parameters.single().second).orObject(target)
|
||||
}
|
||||
|
||||
private lateinit var targetDocument: Document
|
||||
private lateinit var targetEditor: Editor
|
||||
|
||||
private fun navigate(): Boolean {
|
||||
val targetFile = target.containingFile ?: return false
|
||||
targetDocument = targetFile.viewProvider.document ?: return false
|
||||
targetEditor = positionCursor(project, targetFile, target) ?: return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun doRender() {
|
||||
if (!navigate()) return
|
||||
val builder = TemplateBuilderImpl(target)
|
||||
val typeExpression = fillTemplate(builder)
|
||||
val template = builder.buildInlineTemplate().apply {
|
||||
isToShortenLongNames = true
|
||||
}
|
||||
val listener = InsertMissingFieldTemplateListener(project, target, typeExpression, isStatic)
|
||||
TemplateManager.getInstance(project).startTemplate(targetEditor, template, listener)
|
||||
}
|
||||
|
||||
protected abstract fun fillTemplate(builder: TemplateBuilderImpl): RangeExpression
|
||||
|
||||
protected fun insertAccessor(prototype: PsiMethod): PsiMethod {
|
||||
return forcePsiPostprocessAndRestoreElement(target.add(prototype)) as PsiMethod
|
||||
}
|
||||
|
||||
private fun TemplateBuilderImpl.createTemplateContext(): TemplateContext {
|
||||
val substitutor = request.targetSubstitutor.toPsiSubstitutor(project)
|
||||
val guesser = GuessTypeParameters(project, factory, this, substitutor)
|
||||
return TemplateContext(project, factory, target, this, guesser, javaUsage?.context)
|
||||
}
|
||||
|
||||
protected fun TemplateBuilderImpl.setupInput(input: AccessorTemplateData): RangeExpression {
|
||||
val templateTypeElement = createTemplateContext().setupTypeElement(input.typeElement, expectedTypes)
|
||||
val typeExpression = RangeExpression(targetDocument, templateTypeElement.textRange)
|
||||
|
||||
val fieldExpression = FieldExpression(project, target, suggestedFieldName) { typeExpression.text }
|
||||
replaceElement(input.fieldRef, FIELD_VARIABLE, fieldExpression, true)
|
||||
|
||||
input.endElement?.let(::setEndVariableAfter)
|
||||
return typeExpression
|
||||
}
|
||||
|
||||
protected fun TemplateBuilderImpl.setupSetterParameter(data: SetterTemplateData) {
|
||||
val suggestedNameInfo = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, propertyName, null, null)
|
||||
val setterParameterExpression = ParameterNameExpression(suggestedNameInfo.names)
|
||||
replaceElement(data.parameterName, SETTER_PARAM_NAME, setterParameterExpression, true)
|
||||
replaceElement(data.parameterRef, VariableNode(SETTER_PARAM_NAME, null), false) // copy setter parameter name to mirror
|
||||
}
|
||||
}
|
||||
@@ -86,3 +86,10 @@ internal inline fun extractNames(suggestedNames: SuggestedNameInfo?, defaultName
|
||||
}
|
||||
|
||||
internal fun PsiType.toExpectedType() = createInfo(this, ExpectedTypeInfo.TYPE_STRICTLY, this, TailType.NONE)
|
||||
|
||||
internal fun List<ExpectedTypeInfo>.orObject(context: PsiElement): List<ExpectedTypeInfo> {
|
||||
if (isEmpty() || get(0).type == PsiType.VOID) {
|
||||
return listOf(PsiType.getJavaLangObject(context.manager, context.resolveScope).toExpectedType())
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.lang.java.actions
|
||||
import com.intellij.psi.*
|
||||
|
||||
internal const val FIELD_VARIABLE = "FIELD_NAME_VARIABLE"
|
||||
internal const val SETTER_PARAM_NAME = "SETTER_PARAM_NAME"
|
||||
|
||||
internal interface AccessorTemplateData {
|
||||
val fieldRef: PsiElement
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// "Create Getter" "true"
|
||||
public class Test {
|
||||
Integer field;
|
||||
|
||||
public foo() {
|
||||
getField();
|
||||
}
|
||||
|
||||
public Integer getField() {
|
||||
public Object getField() {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ import com.intellij.openapi.util.Pair as JBPair
|
||||
operator fun <A> JBPair<A, *>.component1(): A = first
|
||||
operator fun <A> JBPair<*, A>.component2(): A = second
|
||||
|
||||
// This function helps to get rid of platform types.
|
||||
fun <A : Any, B : Any> JBPair<A?, B?>.toNotNull(): JBPair<A, B> {
|
||||
requireNotNull(first)
|
||||
requireNotNull(second)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return this as JBPair<A, B>
|
||||
// This function helps to get rid of platform types
|
||||
fun <A : Any, B : Any> JBPair<A?, B?>.toNotNull(): Pair<A, B> {
|
||||
return requireNotNull(first) to requireNotNull(second)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user