192: KotlinElementActionsFactory: support for keeping existing parameters on signature change
This commit is contained in:
committed by
Nicolay Mitropolsky
parent
713f73e414
commit
6b91b7cce5
+75
-15
@@ -5,38 +5,50 @@
|
|||||||
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
|
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
|
||||||
|
|
||||||
import com.intellij.codeInsight.daemon.QuickFixBundle
|
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||||
|
import com.intellij.lang.jvm.actions.ChangeParametersRequest
|
||||||
|
import com.intellij.lang.jvm.actions.ExpectedParameter
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import com.intellij.psi.JvmPsiConversionHelper
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
|
||||||
import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
|
import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
|
||||||
import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
|
import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
|
||||||
import org.jetbrains.kotlin.psi.KtParameterList
|
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
internal class ChangeMethodParameters(
|
internal class ChangeMethodParameters(
|
||||||
target: KtNamedFunction,
|
target: KtNamedFunction,
|
||||||
private val request: List<Pair<Name, KotlinType>>,
|
val request: ChangeParametersRequest
|
||||||
private val isValid: () -> Boolean
|
|
||||||
) : KotlinQuickFixAction<KtNamedFunction>(target) {
|
) : KotlinQuickFixAction<KtNamedFunction>(target) {
|
||||||
|
|
||||||
|
|
||||||
override fun getText(): String {
|
override fun getText(): String {
|
||||||
val parametersString = request.joinToString(", ", "(", ")") { (name, type) ->
|
|
||||||
"${name.asString()}: ${IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(type)}"
|
val target = element ?: return "<not available>"
|
||||||
|
|
||||||
|
val helper = JvmPsiConversionHelper.getInstance(target.project)
|
||||||
|
|
||||||
|
val parametersString = request.expectedParameters.joinToString(", ", "(", ")") { ep ->
|
||||||
|
val kotlinType =
|
||||||
|
ep.expectedTypes.firstOrNull()?.theType?.let { helper.convertType(it).resolveToKotlinType(target.getResolutionFacade()) }
|
||||||
|
"${ep.semanticNames.firstOrNull() ?: "parameter"}: ${kotlinType?.let {
|
||||||
|
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(it)
|
||||||
|
} ?: "<error>"}"
|
||||||
}
|
}
|
||||||
|
|
||||||
val shortenParameterString = StringUtil.shortenTextWithEllipsis(parametersString, 30, 5)
|
val shortenParameterString = StringUtil.shortenTextWithEllipsis(parametersString, 30, 5)
|
||||||
@@ -45,12 +57,57 @@ internal class ChangeMethodParameters(
|
|||||||
|
|
||||||
override fun getFamilyName(): String = QuickFixBundle.message("change.method.parameters.family")
|
override fun getFamilyName(): String = QuickFixBundle.message("change.method.parameters.family")
|
||||||
|
|
||||||
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean = element != null && isValid()
|
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean = element != null && request.isValid
|
||||||
|
|
||||||
|
private data class ParameterModification(
|
||||||
|
val name: String,
|
||||||
|
val ktType: KotlinType
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getParametersModifications(
|
||||||
|
target: KtNamedFunction,
|
||||||
|
expectedParameters: List<ExpectedParameter>
|
||||||
|
): List<ParameterModification> {
|
||||||
|
val helper = JvmPsiConversionHelper.getInstance(target.project)
|
||||||
|
|
||||||
|
return expectedParameters.mapIndexed { index, expectedParameter ->
|
||||||
|
val theType = expectedParameter.expectedTypes.firstOrNull()?.theType
|
||||||
|
val kotlinType = theType
|
||||||
|
?.let { helper.convertType(it).resolveToKotlinType(target.getResolutionFacade()) }
|
||||||
|
?: ErrorUtils.createErrorType("unknown type")
|
||||||
|
|
||||||
|
ParameterModification(
|
||||||
|
expectedParameter.semanticNames.firstOrNull() ?: "param$index", kotlinType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
|
if (!request.isValid) return
|
||||||
|
|
||||||
val target = element ?: return
|
val target = element ?: return
|
||||||
val functionDescriptor = target.resolveToDescriptorIfAny(BodyResolveMode.FULL) ?: return
|
val functionDescriptor = target.resolveToDescriptorIfAny(BodyResolveMode.FULL) ?: return
|
||||||
|
|
||||||
|
target.valueParameterList!!.parameters.forEach { target.valueParameterList!!.removeParameter(it) }
|
||||||
|
val parameterActions = getParametersModifications(target, request.expectedParameters)
|
||||||
|
|
||||||
|
val parametersGenerated = parameterActions.let {
|
||||||
|
it zip generateParameterList(project, functionDescriptor, it).parameters
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
for (action in parameterActions) {
|
||||||
|
val parameter = parametersGenerated.getValue(action)
|
||||||
|
target.valueParameterList!!.addParameter(parameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortenReferences.DEFAULT.process(target.valueParameterList!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateParameterList(
|
||||||
|
project: Project,
|
||||||
|
functionDescriptor: FunctionDescriptor,
|
||||||
|
paramsToAdd: List<ParameterModification>
|
||||||
|
): KtParameterList {
|
||||||
val newFunctionDescriptor = SimpleFunctionDescriptorImpl.create(
|
val newFunctionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
functionDescriptor.containingDeclaration,
|
functionDescriptor.containingDeclaration,
|
||||||
functionDescriptor.annotations,
|
functionDescriptor.annotations,
|
||||||
@@ -62,11 +119,11 @@ internal class ChangeMethodParameters(
|
|||||||
functionDescriptor.extensionReceiverParameter?.copy(this),
|
functionDescriptor.extensionReceiverParameter?.copy(this),
|
||||||
functionDescriptor.dispatchReceiverParameter,
|
functionDescriptor.dispatchReceiverParameter,
|
||||||
functionDescriptor.typeParameters,
|
functionDescriptor.typeParameters,
|
||||||
request.withIndex().map { (index, parameter) ->
|
paramsToAdd.mapIndexed { index, parameter ->
|
||||||
ValueParameterDescriptorImpl(
|
ValueParameterDescriptorImpl(
|
||||||
this, null, index, Annotations.EMPTY,
|
this, null, index, Annotations.EMPTY,
|
||||||
Name.identifier(parameter.first.toString()),
|
Name.identifier(parameter.name),
|
||||||
parameter.second, false,
|
parameter.ktType, false,
|
||||||
false, false, null, SourceElement.NO_SOURCE
|
false, false, null, SourceElement.NO_SOURCE
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -92,9 +149,12 @@ internal class ChangeMethodParameters(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val newParameterList = target.valueParameterList!!.replace(newFunction.valueParameterList!!) as KtParameterList
|
return newFunction.valueParameterList!!
|
||||||
ShortenReferences.DEFAULT.process(newParameterList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(ktNamedFunction: KtNamedFunction, request: ChangeParametersRequest): ChangeMethodParameters? =
|
||||||
|
ChangeMethodParameters(ktNamedFunction, request)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+225
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-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/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||||
|
import com.intellij.lang.jvm.actions.ChangeParametersRequest
|
||||||
|
import com.intellij.lang.jvm.actions.ExpectedParameter
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import com.intellij.psi.JvmPsiConversionHelper
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||||
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
|
||||||
|
import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
internal class ChangeMethodParameters(
|
||||||
|
target: KtNamedFunction,
|
||||||
|
val request: ChangeParametersRequest
|
||||||
|
) : KotlinQuickFixAction<KtNamedFunction>(target) {
|
||||||
|
|
||||||
|
|
||||||
|
override fun getText(): String {
|
||||||
|
|
||||||
|
val target = element ?: return "<not available>"
|
||||||
|
|
||||||
|
val helper = JvmPsiConversionHelper.getInstance(target.project)
|
||||||
|
|
||||||
|
val parametersString = request.expectedParameters.joinToString(", ", "(", ")") { ep ->
|
||||||
|
val kotlinType =
|
||||||
|
ep.expectedTypes.firstOrNull()?.theType?.let { helper.convertType(it).resolveToKotlinType(target.getResolutionFacade()) }
|
||||||
|
"${ep.semanticNames.firstOrNull() ?: "parameter"}: ${kotlinType?.let {
|
||||||
|
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(it)
|
||||||
|
} ?: "<error>"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val shortenParameterString = StringUtil.shortenTextWithEllipsis(parametersString, 30, 5)
|
||||||
|
return QuickFixBundle.message("change.method.parameters.text", shortenParameterString)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFamilyName(): String = QuickFixBundle.message("change.method.parameters.family")
|
||||||
|
|
||||||
|
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean = element != null && request.isValid
|
||||||
|
|
||||||
|
private sealed class ParameterModification {
|
||||||
|
data class Keep(val ktParameter: KtParameter) : ParameterModification()
|
||||||
|
data class Remove(val ktParameter: KtParameter) : ParameterModification()
|
||||||
|
data class Add(
|
||||||
|
val name: String,
|
||||||
|
val ktType: KotlinType,
|
||||||
|
val beforeAnchor: KtParameter?
|
||||||
|
) : ParameterModification()
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun getParametersModifications(
|
||||||
|
target: KtNamedFunction,
|
||||||
|
currentParameters: List<KtParameter>,
|
||||||
|
expectedParameters: List<ExpectedParameter>,
|
||||||
|
index: Int = 0,
|
||||||
|
collected: List<ParameterModification> = ArrayList(expectedParameters.size)
|
||||||
|
): List<ParameterModification> {
|
||||||
|
|
||||||
|
val expectedHead = expectedParameters.firstOrNull() ?: return collected + currentParameters.map { ParameterModification.Remove(it) }
|
||||||
|
|
||||||
|
if (expectedHead is ChangeParametersRequest.ExistingParameterWrapper) {
|
||||||
|
val expectedExistingParameter = expectedHead.existingKtParameter
|
||||||
|
if (expectedExistingParameter == null) {
|
||||||
|
LOG.error("can't find the kotlinOrigin for parameter ${expectedHead.existingParameter} at index $index")
|
||||||
|
return collected
|
||||||
|
}
|
||||||
|
|
||||||
|
val existingInTail = currentParameters.indexOf(expectedExistingParameter)
|
||||||
|
if (existingInTail == -1) {
|
||||||
|
throw IllegalArgumentException("can't find existing for parameter ${expectedHead.existingParameter} at index $index")
|
||||||
|
}
|
||||||
|
|
||||||
|
return getParametersModifications(
|
||||||
|
target,
|
||||||
|
currentParameters.subList(existingInTail + 1, currentParameters.size),
|
||||||
|
expectedParameters.subList(1, expectedParameters.size),
|
||||||
|
index,
|
||||||
|
collected
|
||||||
|
+ currentParameters.subList(0, existingInTail).map { ParameterModification.Remove(it) }
|
||||||
|
+ ParameterModification.Keep(expectedExistingParameter)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val helper = JvmPsiConversionHelper.getInstance(target.project)
|
||||||
|
|
||||||
|
val theType = expectedHead.expectedTypes.firstOrNull()?.theType ?: return emptyList()
|
||||||
|
val kotlinType = helper.convertType(theType).resolveToKotlinType(target.getResolutionFacade()) ?: return emptyList()
|
||||||
|
|
||||||
|
return getParametersModifications(
|
||||||
|
target,
|
||||||
|
currentParameters,
|
||||||
|
expectedParameters.subList(1, expectedParameters.size),
|
||||||
|
index + 1,
|
||||||
|
collected + ParameterModification.Add(
|
||||||
|
expectedHead.semanticNames.firstOrNull() ?: "param$index",
|
||||||
|
kotlinType,
|
||||||
|
currentParameters.firstOrNull { anchor ->
|
||||||
|
expectedParameters.any {
|
||||||
|
it is ChangeParametersRequest.ExistingParameterWrapper && it.existingKtParameter == anchor
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ChangeParametersRequest.ExistingParameterWrapper.existingKtParameter
|
||||||
|
get() = (existingParameter as? KtLightElement<*, *>)?.kotlinOrigin as? KtParameter
|
||||||
|
|
||||||
|
|
||||||
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
|
if (!request.isValid) return
|
||||||
|
|
||||||
|
val target = element ?: return
|
||||||
|
val functionDescriptor = target.resolveToDescriptorIfAny(BodyResolveMode.FULL) ?: return
|
||||||
|
|
||||||
|
val parameterActions = getParametersModifications(target, target.valueParameters, request.expectedParameters)
|
||||||
|
|
||||||
|
val parametersGenerated = parameterActions.filterIsInstance<ParameterModification.Add>().let {
|
||||||
|
it zip generateParameterList(project, functionDescriptor, it).parameters
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
for (action in parameterActions) {
|
||||||
|
when (action) {
|
||||||
|
is ParameterModification.Add -> {
|
||||||
|
val parameter = parametersGenerated.getValue(action)
|
||||||
|
val anchor = action.beforeAnchor
|
||||||
|
if (anchor != null) {
|
||||||
|
target.valueParameterList!!.addParameterBefore(parameter, anchor)
|
||||||
|
} else {
|
||||||
|
target.valueParameterList!!.addParameter(parameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is ParameterModification.Keep -> {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
is ParameterModification.Remove -> {
|
||||||
|
target.valueParameterList!!.removeParameter(action.ktParameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortenReferences.DEFAULT.process(target.valueParameterList!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateParameterList(
|
||||||
|
project: Project,
|
||||||
|
functionDescriptor: FunctionDescriptor,
|
||||||
|
paramsToAdd: List<ParameterModification.Add>
|
||||||
|
): KtParameterList {
|
||||||
|
val newFunctionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
|
functionDescriptor.containingDeclaration,
|
||||||
|
functionDescriptor.annotations,
|
||||||
|
functionDescriptor.name,
|
||||||
|
functionDescriptor.kind,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
).apply {
|
||||||
|
initialize(
|
||||||
|
functionDescriptor.extensionReceiverParameter?.copy(this),
|
||||||
|
functionDescriptor.dispatchReceiverParameter,
|
||||||
|
functionDescriptor.typeParameters,
|
||||||
|
paramsToAdd.mapIndexed { index, parameter ->
|
||||||
|
ValueParameterDescriptorImpl(
|
||||||
|
this, null, index, Annotations.EMPTY,
|
||||||
|
Name.identifier(parameter.name),
|
||||||
|
parameter.ktType, false,
|
||||||
|
false, false, null, SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
},
|
||||||
|
functionDescriptor.returnType,
|
||||||
|
functionDescriptor.modality,
|
||||||
|
functionDescriptor.visibility
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val renderer = IdeDescriptorRenderers.SOURCE_CODE.withOptions {
|
||||||
|
defaultParameterValueRenderer = null
|
||||||
|
}
|
||||||
|
|
||||||
|
val newFunction = KtPsiFactory(project).createFunction(renderer.render(newFunctionDescriptor)).apply {
|
||||||
|
valueParameters.forEach { param ->
|
||||||
|
param.annotationEntries.forEach { a ->
|
||||||
|
a.typeReference?.run {
|
||||||
|
val fqName = FqName(this.text)
|
||||||
|
if (fqName in (NULLABLE_ANNOTATIONS + NOT_NULL_ANNOTATIONS)) a.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newFunction.valueParameterList!!
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(ktNamedFunction: KtNamedFunction, request: ChangeParametersRequest): ChangeMethodParameters? =
|
||||||
|
ChangeMethodParameters(ktNamedFunction, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LOG = Logger.getInstance(ChangeMethodParameters::class.java)
|
||||||
+52
-60
@@ -192,54 +192,6 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
|||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
|
|
||||||
val results = ArrayList<PsiTypeParameter>()
|
|
||||||
accept(
|
|
||||||
object : PsiTypeVisitor<Unit>() {
|
|
||||||
override fun visitArrayType(arrayType: PsiArrayType) {
|
|
||||||
arrayType.componentType.accept(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitClassType(classType: PsiClassType) {
|
|
||||||
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
|
|
||||||
classType.parameters.forEach { it.accept(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWildcardType(wildcardType: PsiWildcardType) {
|
|
||||||
wildcardType.bound?.accept(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
|
|
||||||
val typeParameters = collectTypeParameters()
|
|
||||||
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
|
|
||||||
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
|
|
||||||
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
|
|
||||||
val dummyClassDescriptor = ClassDescriptorImpl(
|
|
||||||
dummyPackageDescriptor,
|
|
||||||
Name.identifier("Dummy"),
|
|
||||||
Modality.FINAL,
|
|
||||||
ClassKind.CLASS,
|
|
||||||
emptyList(),
|
|
||||||
SourceElement.NO_SOURCE,
|
|
||||||
false,
|
|
||||||
LockBasedStorageManager.NO_LOCKS
|
|
||||||
)
|
|
||||||
val typeParameterResolver = object : TypeParameterResolver {
|
|
||||||
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
|
|
||||||
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
|
|
||||||
val index = typeParameters.indexOf(psiTypeParameter)
|
|
||||||
if (index < 0) return null
|
|
||||||
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
|
|
||||||
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
|
|
||||||
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ExpectedTypes.toKotlinTypeInfo(resolutionFacade: ResolutionFacade): TypeInfo {
|
private fun ExpectedTypes.toKotlinTypeInfo(resolutionFacade: ResolutionFacade): TypeInfo {
|
||||||
val candidateTypes = flatMapTo(LinkedHashSet<KotlinType>()) {
|
val candidateTypes = flatMapTo(LinkedHashSet<KotlinType>()) {
|
||||||
@@ -532,20 +484,60 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
|||||||
|
|
||||||
override fun createChangeParametersActions(target: JvmMethod, request: ChangeParametersRequest): List<IntentionAction> {
|
override fun createChangeParametersActions(target: JvmMethod, request: ChangeParametersRequest): List<IntentionAction> {
|
||||||
val ktNamedFunction = (target as? KtLightElement<*, *>)?.kotlinOrigin as? KtNamedFunction ?: return emptyList()
|
val ktNamedFunction = (target as? KtLightElement<*, *>)?.kotlinOrigin as? KtNamedFunction ?: return emptyList()
|
||||||
|
return listOfNotNull(ChangeMethodParameters.create(ktNamedFunction,request ))
|
||||||
val helper = JvmPsiConversionHelper.getInstance(target.project)
|
|
||||||
|
|
||||||
val params = request.expectedParameters.map { ep ->
|
|
||||||
val name = ep.semanticNames.singleOrNull() ?: return emptyList()
|
|
||||||
val expectedType = ep.expectedTypes.singleOrNull() ?: return emptyList()
|
|
||||||
|
|
||||||
val kotlinType =
|
|
||||||
helper.convertType(expectedType.theType).resolveToKotlinType(ktNamedFunction.getResolutionFacade()) ?: return emptyList()
|
|
||||||
Name.identifier(name) to kotlinType
|
|
||||||
}
|
|
||||||
return listOf(ChangeMethodParameters(ktNamedFunction, params, { request.isValid }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
|
||||||
|
val results = ArrayList<PsiTypeParameter>()
|
||||||
|
accept(
|
||||||
|
object : PsiTypeVisitor<Unit>() {
|
||||||
|
override fun visitArrayType(arrayType: PsiArrayType) {
|
||||||
|
arrayType.componentType.accept(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClassType(classType: PsiClassType) {
|
||||||
|
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
|
||||||
|
classType.parameters.forEach { it.accept(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWildcardType(wildcardType: PsiWildcardType) {
|
||||||
|
wildcardType.bound?.accept(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
|
||||||
|
val typeParameters = collectTypeParameters()
|
||||||
|
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
|
||||||
|
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
|
||||||
|
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
|
||||||
|
val dummyClassDescriptor = ClassDescriptorImpl(
|
||||||
|
dummyPackageDescriptor,
|
||||||
|
Name.identifier("Dummy"),
|
||||||
|
Modality.FINAL,
|
||||||
|
ClassKind.CLASS,
|
||||||
|
emptyList(),
|
||||||
|
SourceElement.NO_SOURCE,
|
||||||
|
false,
|
||||||
|
LockBasedStorageManager.NO_LOCKS
|
||||||
|
)
|
||||||
|
val typeParameterResolver = object : TypeParameterResolver {
|
||||||
|
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
|
||||||
|
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
|
||||||
|
val index = typeParameters.indexOf(psiTypeParameter)
|
||||||
|
if (index < 0) return null
|
||||||
|
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
|
||||||
|
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
|
||||||
|
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun JvmPsiConversionHelper.asPsiType(param: Pair<SuggestedNameInfo, List<ExpectedType>>): PsiType? =
|
private fun JvmPsiConversionHelper.asPsiType(param: Pair<SuggestedNameInfo, List<ExpectedType>>): PsiType? =
|
||||||
param.second.firstOrNull()?.theType?.let { convertType(it) }
|
param.second.firstOrNull()?.theType?.let { convertType(it) }
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.lang.jvm.actions.*
|
||||||
|
import com.intellij.lang.jvm.types.JvmType
|
||||||
|
import com.intellij.psi.PsiType
|
||||||
|
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.uast.UMethod
|
||||||
|
|
||||||
|
class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||||
|
|
||||||
|
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
|
||||||
|
|
||||||
|
fun testSetParameters() {
|
||||||
|
myFixture.configureByText(
|
||||||
|
"foo.kt",
|
||||||
|
"""
|
||||||
|
class Foo {
|
||||||
|
fun ba<caret>r() {}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
myFixture.launchAction(
|
||||||
|
createChangeParametersActions(
|
||||||
|
myFixture.atCaret<UMethod>().javaPsi,
|
||||||
|
setMethodParametersRequest(
|
||||||
|
linkedMapOf<String, JvmType>(
|
||||||
|
"i" to PsiType.INT,
|
||||||
|
"file" to PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope)
|
||||||
|
).entries
|
||||||
|
)
|
||||||
|
).findWithText("Change method parameters to '(i: Int, file: File)'")
|
||||||
|
)
|
||||||
|
myFixture.checkResult(
|
||||||
|
"""
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun bar(i: Int, file: File) {}
|
||||||
|
}
|
||||||
|
""".trimIndent(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+166
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.lang.jvm.actions.*
|
||||||
|
import com.intellij.lang.jvm.types.JvmType
|
||||||
|
import com.intellij.psi.PsiType
|
||||||
|
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.uast.UMethod
|
||||||
|
|
||||||
|
class CommonIntentionActionsParametersTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||||
|
|
||||||
|
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
myFixture.configureByText("Anno.kt", "annotation class Anno(val i: Int)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSetParameters() {
|
||||||
|
myFixture.configureByText(
|
||||||
|
"foo.kt",
|
||||||
|
"""
|
||||||
|
class Foo {
|
||||||
|
fun ba<caret>r() {}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
myFixture.launchAction(
|
||||||
|
createChangeParametersActions(
|
||||||
|
myFixture.atCaret<UMethod>().javaPsi,
|
||||||
|
setMethodParametersRequest(
|
||||||
|
linkedMapOf<String, JvmType>(
|
||||||
|
"i" to PsiType.INT,
|
||||||
|
"file" to PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope)
|
||||||
|
).entries
|
||||||
|
)
|
||||||
|
).findWithText("Change method parameters to '(i: Int, file: File)'")
|
||||||
|
)
|
||||||
|
myFixture.checkResult(
|
||||||
|
"""
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun bar(i: Int, file: File) {}
|
||||||
|
}
|
||||||
|
""".trimIndent(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun testAddParameterToTheEnd() {
|
||||||
|
myFixture.configureByText(
|
||||||
|
"foo.kt",
|
||||||
|
"""
|
||||||
|
class Foo {
|
||||||
|
fun ba<caret>r(@Anno(3) a: Int) {}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
runParametersTransformation("Change method parameters to '(a: Int, file: File)'") { currentParameters ->
|
||||||
|
currentParameters + expectedParameter(
|
||||||
|
PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
myFixture.checkResult(
|
||||||
|
"""
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun bar(@Anno(3) a: Int, file: File) {}
|
||||||
|
}
|
||||||
|
""".trimIndent(), true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun testAddParameterToTheBeginning() {
|
||||||
|
myFixture.configureByText(
|
||||||
|
"foo.kt",
|
||||||
|
"""
|
||||||
|
class Foo {
|
||||||
|
fun ba<caret>r(@Anno(3) a: Int) {}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
runParametersTransformation("Change method parameters to '(file: File, a: Int)'") { currentParameters ->
|
||||||
|
listOf(
|
||||||
|
expectedParameter(
|
||||||
|
PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file"
|
||||||
|
)
|
||||||
|
) + currentParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
myFixture.checkResult(
|
||||||
|
"""
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun bar(file: File, @Anno(3) a: Int) {}
|
||||||
|
}
|
||||||
|
""".trimIndent(), true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testReplaceInTheMiddle() {
|
||||||
|
myFixture.configureByText(
|
||||||
|
"foo.kt",
|
||||||
|
"""
|
||||||
|
class Foo {
|
||||||
|
fun ba<caret>r(@Anno(1) a: Int, @Anno(2) b: Int, @Anno(3) c: Int) {}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
runParametersTransformation("Change method parameters to '(a: Int, file: File, c: Int)'") { currentParameters ->
|
||||||
|
ArrayList<ExpectedParameter>(currentParameters).apply {
|
||||||
|
this[1] = expectedParameter(
|
||||||
|
PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope), "file"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myFixture.checkResult(
|
||||||
|
"""
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun bar(@Anno(1) a: Int, file: File, @Anno(3) c: Int) {}
|
||||||
|
}
|
||||||
|
""".trimIndent(), true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runParametersTransformation(
|
||||||
|
actionName: String,
|
||||||
|
transformation: (List<ChangeParametersRequest.ExistingParameterWrapper>) -> List<ExpectedParameter>
|
||||||
|
) {
|
||||||
|
val psiMethod = myFixture.atCaret<UMethod>().javaPsi
|
||||||
|
val currentParameters = psiMethod.parameters.map { ChangeParametersRequest.ExistingParameterWrapper(it) }
|
||||||
|
myFixture.launchAction(
|
||||||
|
createChangeParametersActions(
|
||||||
|
psiMethod,
|
||||||
|
SimpleChangeParametersRequest(
|
||||||
|
transformation(currentParameters)
|
||||||
|
)
|
||||||
|
).findWithText(actionName)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SimpleChangeParametersRequest(private val list: List<ExpectedParameter>) : ChangeParametersRequest {
|
||||||
|
override fun getExpectedParameters(): List<ExpectedParameter> = list
|
||||||
|
|
||||||
|
override fun isValid(): Boolean = true
|
||||||
|
}
|
||||||
@@ -11,11 +11,9 @@ import com.intellij.lang.jvm.JvmElement
|
|||||||
import com.intellij.lang.jvm.JvmModifier
|
import com.intellij.lang.jvm.JvmModifier
|
||||||
import com.intellij.lang.jvm.actions.*
|
import com.intellij.lang.jvm.actions.*
|
||||||
import com.intellij.lang.jvm.types.JvmSubstitutor
|
import com.intellij.lang.jvm.types.JvmSubstitutor
|
||||||
import com.intellij.lang.jvm.types.JvmType
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Pair.pair
|
import com.intellij.openapi.util.Pair.pair
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.codeStyle.SuggestedNameInfo
|
|
||||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
|
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
@@ -23,9 +21,6 @@ import org.jetbrains.kotlin.asJava.toLightElements
|
|||||||
import org.jetbrains.kotlin.idea.search.allScope
|
import org.jetbrains.kotlin.idea.search.allScope
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||||
import org.jetbrains.uast.UMethod
|
|
||||||
import org.jetbrains.uast.UParameter
|
|
||||||
import org.jetbrains.uast.UastContext
|
|
||||||
import org.jetbrains.uast.toUElement
|
import org.jetbrains.uast.toUElement
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
|
|
||||||
@@ -57,8 +52,6 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NameInfo(vararg names: String) : SuggestedNameInfo(names)
|
|
||||||
|
|
||||||
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
|
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
|
||||||
|
|
||||||
fun testMakeNotFinal() {
|
fun testMakeNotFinal() {
|
||||||
@@ -632,57 +625,12 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
|
|||||||
""".trim().trimMargin(), true)
|
""".trim().trimMargin(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testSetParameters() {
|
|
||||||
myFixture.configureByText(
|
|
||||||
"foo.kt", """
|
|
||||||
|class Foo {
|
|
||||||
| fun ba<caret>r() {}
|
|
||||||
|}
|
|
||||||
""".trim().trimMargin()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
myFixture.launchAction(
|
|
||||||
com.intellij.lang.jvm.actions.createChangeParametersActions(
|
|
||||||
myFixture.atCaret<UMethod>().javaPsi,
|
|
||||||
setMethodParametersRequest(
|
|
||||||
linkedMapOf<String, JvmType>(
|
|
||||||
"i" to PsiType.INT,
|
|
||||||
"file" to PsiType.getTypeByName("java.io.File", project, myFixture.file.resolveScope)
|
|
||||||
).entries
|
|
||||||
)
|
|
||||||
).findWithText("Change method parameters to '(i: Int, file: File)'")
|
|
||||||
)
|
|
||||||
myFixture.checkResult(
|
|
||||||
"""
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class Foo {
|
|
||||||
fun bar(i: Int, file: File) {}
|
|
||||||
}
|
|
||||||
""".trimIndent(), true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeParams(vararg psyTypes: PsiType): List<UParameter> {
|
|
||||||
val uastContext = UastContext(myFixture.project)
|
|
||||||
val factory = JavaPsiFacade.getElementFactory(myFixture.project)
|
|
||||||
val parameters = psyTypes.mapIndexed { index, psiType -> factory.createParameter("param$index", psiType) }
|
|
||||||
return parameters.map { uastContext.convertElement(it, null, UParameter::class.java) as UParameter }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun expectedTypes(vararg psiTypes: PsiType) = psiTypes.map { expectedType(it) }
|
private fun expectedTypes(vararg psiTypes: PsiType) = psiTypes.map { expectedType(it) }
|
||||||
|
|
||||||
private fun expectedParams(vararg psyTypes: PsiType) =
|
private fun expectedParams(vararg psyTypes: PsiType) =
|
||||||
psyTypes.mapIndexed { index, psiType -> expectedParameter(expectedTypes(psiType), "param$index") }
|
psyTypes.mapIndexed { index, psiType -> expectedParameter(expectedTypes(psiType), "param$index") }
|
||||||
|
|
||||||
private inline fun <reified T : JvmElement> CodeInsightTestFixture.atCaret() = elementAtCaret.toUElement() as T
|
|
||||||
|
|
||||||
@Suppress("CAST_NEVER_SUCCEEDS")
|
|
||||||
private fun List<IntentionAction>.findWithText(text: String): IntentionAction =
|
|
||||||
this.firstOrNull { it.text == text } ?:
|
|
||||||
Assert.fail("intention with text '$text' was not found, only ${this.joinToString { "\"${it.text}\"" }} available") as Nothing
|
|
||||||
|
|
||||||
class FieldRequest(
|
class FieldRequest(
|
||||||
private val project: Project,
|
private val project: Project,
|
||||||
val modifiers: List<JvmModifier>,
|
val modifiers: List<JvmModifier>,
|
||||||
@@ -703,7 +651,14 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() {
|
|||||||
override fun isValid(): Boolean = true
|
override fun isValid(): Boolean = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified T : JvmElement> CodeInsightTestFixture.atCaret() = elementAtCaret.toUElement() as T
|
||||||
|
|
||||||
|
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||||
|
internal fun List<IntentionAction>.findWithText(text: String): IntentionAction =
|
||||||
|
this.firstOrNull { it.text == text } ?:
|
||||||
|
Assert.fail("intention with text '$text' was not found, only ${this.joinToString { "\"${it.text}\"" }} available") as Nothing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user