Create From Usage: Generalize function builder for both functions and properties

This commit is contained in:
Alexey Sedunov
2014-09-29 15:02:14 +04:00
parent 9032a6166e
commit be211d7cda
15 changed files with 130 additions and 87 deletions
@@ -216,9 +216,8 @@ public class JetPsiFactory(private val project: Project) {
return createClass("class A(){}").getBody()!!
}
public fun createParameter(name: String, `type`: String): JetParameter {
val function = createFunction("fun foo(" + name + " : " + `type` + ") {}")
return function.getValueParameters().first()
public fun createParameter(text : String): JetParameter {
return createClass("class A($text)").getPrimaryConstructorParameters().first()
}
public fun createParameterList(text: String): JetParameterList {
@@ -90,18 +90,18 @@ class TypeCandidate(val theType: JetType, scope: JetScope? = null) {
}
}
class FunctionBuilderConfiguration(
val functionInfo: FunctionInfo,
class CallableBuilderConfiguration(
val callableInfo: CallableInfo,
val currentFile: JetFile,
val currentEditor: Editor
)
trait FunctionPlacement {
class WithReceiver(val receiverTypeCandidate: TypeCandidate): FunctionPlacement
class NoReceiver(val containingElement: JetElement): FunctionPlacement
trait CallablePlacement {
class WithReceiver(val receiverTypeCandidate: TypeCandidate): CallablePlacement
class NoReceiver(val containingElement: JetElement): CallablePlacement
}
class FunctionBuilder(val config: FunctionBuilderConfiguration) {
class CallableBuilder(val config: CallableBuilderConfiguration) {
private var finished: Boolean = false
val currentFileContext: BindingContext
@@ -115,7 +115,7 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
currentFileModule = exhaust.getModuleDescriptor()
}
public var placement: FunctionPlacement by Delegates.notNull()
public var placement: CallablePlacement by Delegates.notNull()
fun computeTypeCandidates(typeInfo: TypeInfo): List<TypeCandidate> =
typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(this).map { TypeCandidate(it) } }
@@ -174,18 +174,18 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
val placement = placement
when {
placement is FunctionPlacement.NoReceiver -> {
placement is CallablePlacement.NoReceiver -> {
receiverClassDescriptor = null
isExtension = false
containingElement = placement.containingElement
}
placement is FunctionPlacement.WithReceiver -> {
placement is CallablePlacement.WithReceiver -> {
receiverClassDescriptor = DescriptorUtils.getClassDescriptorForType(placement.receiverTypeCandidate.theType)
val classDeclaration = receiverClassDescriptor?.let { DescriptorToSourceUtils.classDescriptorToDeclaration(it) }
isExtension = !(classDeclaration is JetClassOrObject && classDeclaration.isWritable())
containingElement = if (isExtension) config.currentFile else classDeclaration as JetElement
}
else -> throw IllegalArgumentException("Unexpected function kind: $placement")
else -> throw IllegalArgumentException("Unexpected placement: $placement")
}
val receiverType = receiverClassDescriptor?.getDefaultType()
@@ -198,7 +198,7 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
containingFileEditor = config.currentEditor
}
isUnit = config.functionInfo.returnTypeInfo.let { it is TypeInfo.ByType && it.theType.isUnit() }
isUnit = config.callableInfo.returnTypeInfo.let { it is TypeInfo.ByType && it.theType.isUnit() }
val scope = if (isExtension || receiverClassDescriptor == null) {
currentFileModule.getPackage(config.currentFile.getPackageFqName())!!.getMemberScope()
@@ -209,15 +209,15 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
// figure out type substitutions for type parameters
val classTypeParameters = receiverType?.getArguments() ?: Collections.emptyList()
val ownerTypeArguments = (placement as? FunctionPlacement.WithReceiver)?.receiverTypeCandidate?.theType?.getArguments()
val ownerTypeArguments = (placement as? CallablePlacement.WithReceiver)?.receiverTypeCandidate?.theType?.getArguments()
?: Collections.emptyList()
assert(ownerTypeArguments.size == classTypeParameters.size)
val substitutions = ownerTypeArguments.zip(classTypeParameters).map {
JetTypeSubstitution(it.first.getType(), it.second.getType())
}.copyToArray()
config.functionInfo.parameterInfos.forEach { parameter -> computeTypeCandidates(parameter.typeInfo, substitutions, scope) }
config.callableInfo.parameterInfos.forEach { parameter -> computeTypeCandidates(parameter.typeInfo, substitutions, scope) }
if (!isUnit) {
computeTypeCandidates(config.functionInfo.returnTypeInfo, substitutions, scope)
computeTypeCandidates(config.callableInfo.returnTypeInfo, substitutions, scope)
}
// now that we have done substitutions, we can throw it away
@@ -225,9 +225,9 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
// figure out type parameter renames to avoid conflicts
typeParameterNameMap = getTypeParameterRenames(scope)
config.functionInfo.parameterInfos.forEach { renderTypeCandidates(it.typeInfo, typeParameterNameMap) }
config.callableInfo.parameterInfos.forEach { renderTypeCandidates(it.typeInfo, typeParameterNameMap) }
if (!isUnit) {
renderTypeCandidates(config.functionInfo.returnTypeInfo, typeParameterNameMap)
renderTypeCandidates(config.callableInfo.returnTypeInfo, typeParameterNameMap)
}
receiverTypeCandidate?.render(typeParameterNameMap)
}
@@ -239,13 +239,22 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
typeCandidates[typeInfo]?.forEach { it.render(typeParameterNameMap) }
}
private fun createFunctionSkeleton(): JetNamedFunction {
private fun createDeclarationSkeleton(): JetCallableDeclaration {
with (config) {
val parametersString = functionInfo.parameterInfos.indices.map { i -> "p$i: Any" }.joinToString(", ")
val returnTypeString = if (isUnit) "" else ": Any"
val ownerTypeString = if (isExtension) "${receiverTypeCandidate!!.renderedType!!}." else ""
val paramList = when (callableInfo.kind) {
CallableKind.FUNCTION -> "(${callableInfo.parameterInfos.indices.map { i -> "p$i: Any" }.joinToString(", ")})"
CallableKind.PROPERTY -> ""
}
val returnTypeString = if (isUnit) "" else ": Any"
val header = "$ownerTypeString${callableInfo.name}$paramList$returnTypeString"
val psiFactory = JetPsiFactory(currentFile)
val func = psiFactory.createFunction("fun $ownerTypeString${functionInfo.name}($parametersString)$returnTypeString { }")
val declaration = when (callableInfo.kind) {
CallableKind.FUNCTION -> psiFactory.createFunction("fun $header {}")
CallableKind.PROPERTY -> psiFactory.createProperty("val $header")
}
val newLine = psiFactory.createNewLine()
fun prepend(element: PsiElement, elementBeforeStart: PsiElement): PsiElement {
@@ -275,7 +284,7 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
}
when (containingElement) {
is JetFile -> return append(func, containingElement.getLastChild()!!, false) as JetNamedFunction
is JetFile -> return append(declaration, containingElement.getLastChild()!!, false) as JetCallableDeclaration
is JetClassOrObject -> {
var classBody = containingElement.getBody()
@@ -284,11 +293,11 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
containingElement.addBefore(psiFactory.createWhiteSpace(), classBody)
}
val rBrace = classBody!!.getRBrace()
return (rBrace?.let { append(func, it, true) }
?: append(func, classBody!!.getLastChild()!!, false)) as JetNamedFunction
return (rBrace?.let { append(declaration, it, true) }
?: append(declaration, classBody!!.getLastChild()!!, false)) as JetCallableDeclaration
}
is JetBlockExpression -> return prepend(func, containingElement.getLBrace()!!) as JetNamedFunction
is JetBlockExpression -> return prepend(declaration, containingElement.getLBrace()!!) as JetCallableDeclaration
else -> throw AssertionError("Invalid containing element: ${containingElement.getText()}")
}
@@ -300,13 +309,13 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
allTypeParametersNotInScope.addAll(receiverTypeCandidate?.typeParameters?.toList() ?: Collections.emptyList())
config.functionInfo.parameterInfos.stream()
config.callableInfo.parameterInfos.stream()
.flatMap { typeCandidates[it.typeInfo]!!.stream() }
.flatMap { it.typeParameters.stream() }
.toCollection(allTypeParametersNotInScope)
if (!isUnit) {
computeTypeCandidates(config.functionInfo.returnTypeInfo).stream().flatMapTo(allTypeParametersNotInScope) { it.typeParameters.stream() }
computeTypeCandidates(config.callableInfo.returnTypeInfo).stream().flatMapTo(allTypeParametersNotInScope) { it.typeParameters.stream() }
}
val validator = CollectingValidator { scope.getClassifier(Name.identifier(it)) == null }
@@ -316,14 +325,14 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
}
private fun setupTypeReferencesForShortening(
func: JetNamedFunction,
declaration: JetCallableDeclaration,
typeRefsToShorten: MutableList<JetTypeReference>, parameterTypeExpressions: List<TypeExpression>,
returnTypeExpression: TypeExpression?) {
if (isExtension) {
val receiverTypeRef = JetPsiFactory(func).createType(receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap))
val receiverTypeRef = JetPsiFactory(declaration).createType(receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap))
replaceWithLongerName(receiverTypeRef, receiverTypeCandidate.theType)
val funcReceiverTypeRef = func.getReceiverTypeRef()
val funcReceiverTypeRef = declaration.getReceiverTypeRef()
if (funcReceiverTypeRef != null) {
typeRefsToShorten.add(funcReceiverTypeRef)
}
@@ -331,24 +340,30 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
if (!isUnit) {
returnTypeExpression!!
val returnTypeRef = func.getReturnTypeRef()
val returnTypeRef = declaration.getReturnTypeRef()
if (returnTypeRef != null) {
val returnType = returnTypeExpression.getTypeFromSelection(returnTypeRef.getText() ?: throw AssertionError("Expression for function return type shouldn't be empty: function = ${func.getText()}"))
val returnType = returnTypeExpression.getTypeFromSelection(
returnTypeRef.getText()
?: throw AssertionError("Expression for return type shouldn't be empty: declaration = ${declaration.getText()}")
)
if (returnType != null) {
// user selected a given type
replaceWithLongerName(returnTypeRef, returnType)
typeRefsToShorten.add(func.getReturnTypeRef()!!)
typeRefsToShorten.add(declaration.getReturnTypeRef()!!)
}
}
}
val valueParameters = func.getValueParameters()
val valueParameters = declaration.getValueParameterList()?.getParameters() ?: Collections.emptyList<JetParameter>()
val parameterIndicesToShorten = ArrayList<Int>()
assert(valueParameters.size == parameterTypeExpressions.size)
for ((i, parameter) in valueParameters.stream().withIndices()) {
val parameterTypeRef = parameter.getTypeReference()
if (parameterTypeRef != null) {
val parameterType = parameterTypeExpressions[i].getTypeFromSelection(parameterTypeRef.getText() ?: throw AssertionError("Expression for function parameter type shouldn't be empty: function = ${func.getText()}"))
val parameterType = parameterTypeExpressions[i].getTypeFromSelection(
parameterTypeRef.getText()
?: throw AssertionError("Expression for parameter type shouldn't be empty: declaration = ${declaration.getText()}")
)
if (parameterType != null) {
replaceWithLongerName(parameterTypeRef, parameterType)
parameterIndicesToShorten.add(i)
@@ -356,8 +371,11 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
}
}
val expandedValueParameters = func.getValueParameters()
parameterIndicesToShorten.stream().map { expandedValueParameters[it].getTypeReference() }.filterNotNullTo(typeRefsToShorten)
declaration.getValueParameterList()?.getParameters()?.let { expandedValueParameters ->
parameterIndicesToShorten.stream()
.map { expandedValueParameters[it].getTypeReference() }
.filterNotNullTo(typeRefsToShorten)
}
}
private fun setupFunctionBody(func: JetNamedFunction) {
@@ -368,7 +386,7 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(it).asString())
properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, it.getName().asString())
}
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, config.functionInfo.name)
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, config.callableInfo.name)
val bodyText = try {
fileTemplate!!.getText(properties)
@@ -386,37 +404,36 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
func.getBodyExpression()!!.replace(newBodyExpression)
}
private fun setupReturnTypeTemplate(builder: TemplateBuilder, func: JetNamedFunction): TypeExpression {
val returnTypeRef = func.getReturnTypeRef()!!
val returnTypeExpression = TypeExpression(typeCandidates[config.functionInfo.returnTypeInfo]!!)
private fun setupReturnTypeTemplate(builder: TemplateBuilder, declaration: JetCallableDeclaration): TypeExpression {
val returnTypeRef = declaration.getReturnTypeRef()!!
val returnTypeExpression = TypeExpression(typeCandidates[config.callableInfo.returnTypeInfo]!!)
builder.replaceElement(returnTypeRef, returnTypeExpression)
return returnTypeExpression
}
private fun setupTypeParameterListTemplate(builder: TemplateBuilderImpl, func: JetNamedFunction): TypeParameterListExpression {
private fun setupTypeParameterListTemplate(builder: TemplateBuilderImpl, declaration: JetCallableDeclaration): TypeParameterListExpression {
val typeParameterMap = HashMap<String, Array<String>>()
val receiverTypeParameterNames = receiverTypeCandidate?.let { it.typeParameterNames!! } ?: ArrayUtil.EMPTY_STRING_ARRAY
config.functionInfo.parameterInfos.stream().flatMap { typeCandidates[it.typeInfo]!!.stream() }.forEach {
config.callableInfo.parameterInfos.stream().flatMap { typeCandidates[it.typeInfo]!!.stream() }.forEach {
typeParameterMap[it.renderedType!!] = it.typeParameterNames!!
}
if (func.getReturnTypeRef() != null) {
typeCandidates[config.functionInfo.returnTypeInfo]!!.forEach {
if (declaration.getReturnTypeRef() != null) {
typeCandidates[config.callableInfo.returnTypeInfo]!!.forEach {
typeParameterMap[it.renderedType!!] = it.typeParameterNames!!
}
}
// ((3, 3) is after "fun")
builder.replaceElement(func, TextRange.create(3, 3), TYPE_PARAMETER_LIST_VARIABLE_NAME, null, false)
builder.replaceElement(declaration, TextRange.create(3, 3), TYPE_PARAMETER_LIST_VARIABLE_NAME, null, false)
return TypeParameterListExpression(receiverTypeParameterNames, typeParameterMap)
}
private fun setupParameterTypeTemplates(builder: TemplateBuilder, parameterList: JetParameterList): List<TypeExpression> {
val jetParameters = parameterList.getParameters()
assert(jetParameters.size == config.functionInfo.parameterInfos.size)
private fun setupParameterTypeTemplates(builder: TemplateBuilder, parameterList: List<JetParameter>): List<TypeExpression> {
assert(parameterList.size == config.callableInfo.parameterInfos.size)
val typeParameters = ArrayList<TypeExpression>()
for ((parameter, jetParameter) in config.functionInfo.parameterInfos.zip(jetParameters)) {
for ((parameter, jetParameter) in config.callableInfo.parameterInfos.zip(parameterList)) {
val parameterTypeExpression = TypeExpression(typeCandidates[parameter.typeInfo]!!)
val parameterTypeRef = jetParameter.getTypeReference()!!
builder.replaceElement(parameterTypeRef, parameterTypeExpression)
@@ -454,9 +471,8 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
}
fun buildAndRunTemplate() {
val func = createFunctionSkeleton()
val project = func.getProject()
val parameterList = func.getValueParameterList()!!
val declaration = createDeclarationSkeleton()
val project = declaration.getProject()
// build templates
PsiDocumentManager.getInstance(project).commitAllDocuments()
@@ -466,20 +482,21 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
caretModel.moveToOffset(containingFile.getNode().getStartOffset())
val builder = TemplateBuilderImpl(containingFile)
val returnTypeExpression = if (isUnit) null else setupReturnTypeTemplate(builder, func)
val parameterTypeExpressions = setupParameterTypeTemplates(builder, parameterList)
val returnTypeExpression = if (isUnit) null else setupReturnTypeTemplate(builder, declaration)
val parameterTypeExpressions =
setupParameterTypeTemplates(builder, declaration.getValueParameterList()?.getParameters() ?: Collections.emptyList())
// add a segment for the parameter list
// Note: because TemplateBuilderImpl does not have a replaceElement overload that takes in both a TextRange and alwaysStopAt, we
// need to create the segment first and then hack the Expression into the template later. We use this template to update the type
// parameter list as the user makes selections in the parameter types, and we need alwaysStopAt to be false so the user can't tab to
// it.
val expression = setupTypeParameterListTemplate(builder, func)
val expression = setupTypeParameterListTemplate(builder, declaration)
// the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it
val templateImpl = builder.buildInlineTemplate() as TemplateImpl
val variables = templateImpl.getVariables()!!
for (i in 0..(config.functionInfo.parameterInfos.size - 1)) {
for (i in 0..(config.callableInfo.parameterInfos.size - 1)) {
Collections.swap(variables, i * 2, i * 2 + 1)
}
@@ -494,15 +511,19 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
override fun templateFinished(template: Template?, brokenOff: Boolean) {
// file templates
val offset = templateImpl.getSegmentOffset(0)
val newFunc = PsiTreeUtil.findElementOfClassAtOffset(containingFile, offset, javaClass<JetNamedFunction>(), false)!!
val newDeclaration = PsiTreeUtil.findElementOfClassAtOffset(
containingFile, offset, javaClass<JetCallableDeclaration>(), false
)!!
val typeRefsToShorten = ArrayList<JetTypeReference>()
ApplicationManager.getApplication()!!.runWriteAction {
// file templates
setupFunctionBody(newFunc)
if (newDeclaration is JetNamedFunction) {
setupFunctionBody(newDeclaration)
}
// change short type names to fully qualified ones (to be shortened below)
setupTypeReferencesForShortening(newFunc, typeRefsToShorten, parameterTypeExpressions, returnTypeExpression)
setupTypeReferencesForShortening(newDeclaration, typeRefsToShorten, parameterTypeExpressions, returnTypeExpression)
ShortenReferences.process(typeRefsToShorten)
}
}
@@ -512,4 +533,4 @@ class FunctionBuilder(val config: FunctionBuilderConfiguration) {
}
}
fun FunctionBuilderConfiguration.createBuilder(): FunctionBuilder = FunctionBuilder(this)
fun CallableBuilderConfiguration.createBuilder(): CallableBuilder = CallableBuilder(this)
@@ -16,7 +16,7 @@ import org.jetbrains.jet.plugin.util.supertypes
*/
abstract class TypeInfo(val variance: Variance) {
object Empty: TypeInfo(Variance.INVARIANT) {
override fun getPossibleTypes(builder: FunctionBuilder): List<JetType> = Collections.emptyList()
override fun getPossibleTypes(builder: CallableBuilder): List<JetType> = Collections.emptyList()
}
class ByExpression(val expression: JetExpression, variance: Variance): TypeInfo(variance) {
@@ -24,22 +24,22 @@ abstract class TypeInfo(val variance: Variance) {
JetNameSuggester.suggestNamesForExpression(expression, EmptyValidator)
}
override fun getPossibleTypes(builder: FunctionBuilder): List<JetType> =
override fun getPossibleTypes(builder: CallableBuilder): List<JetType> =
expression.guessTypes(builder.currentFileContext).flatMap { it.getPossibleSupertypes(variance) }
}
class ByType(val theType: JetType, variance: Variance, val keepUnsubstituted: Boolean = false): TypeInfo(variance) {
override fun getPossibleTypes(builder: FunctionBuilder): List<JetType> =
override fun getPossibleTypes(builder: CallableBuilder): List<JetType> =
theType.getPossibleSupertypes(variance)
}
class ByReceiverType(variance: Variance): TypeInfo(variance) {
override fun getPossibleTypes(builder: FunctionBuilder): List<JetType> =
(builder.placement as FunctionPlacement.WithReceiver).receiverTypeCandidate.theType.getPossibleSupertypes(variance)
override fun getPossibleTypes(builder: CallableBuilder): List<JetType> =
(builder.placement as CallablePlacement.WithReceiver).receiverTypeCandidate.theType.getPossibleSupertypes(variance)
}
open val possibleNamesFromExpression: Array<String> get() = ArrayUtil.EMPTY_STRING_ARRAY
abstract fun getPossibleTypes(builder: FunctionBuilder): List<JetType>
abstract fun getPossibleTypes(builder: CallableBuilder): List<JetType>
protected fun JetType.getPossibleSupertypes(variance: Variance): List<JetType> {
val single = Collections.singletonList(this)
@@ -61,9 +61,32 @@ class ParameterInfo(
val preferredName: String? = null
)
class FunctionInfo (
enum class CallableKind {
FUNCTION
PROPERTY
}
class CallableInfo (
val name: String,
val kind: CallableKind,
val receiverTypeInfo: TypeInfo,
val returnTypeInfo: TypeInfo,
val parameterInfos: List<ParameterInfo> = Collections.emptyList()
)
) {
{
if (kind == CallableKind.PROPERTY) assert (parameterInfos.isEmpty(), "$kind: Parameters are not allowed")
}
}
fun createFunctionInfo(name: String,
receiverTypeInfo: TypeInfo,
returnTypeInfo: TypeInfo,
parameterInfos: List<ParameterInfo> = Collections.emptyList()): CallableInfo {
return CallableInfo(name, CallableKind.FUNCTION, receiverTypeInfo, returnTypeInfo, parameterInfos)
}
fun createPropertyInfo(name: String,
receiverTypeInfo: TypeInfo,
returnTypeInfo: TypeInfo): CallableInfo {
return CallableInfo(name, CallableKind.PROPERTY, receiverTypeInfo, returnTypeInfo)
}
@@ -37,6 +37,6 @@ public object CreateBinaryOperationActionFactory: JetSingleIntentionActionFactor
else -> TypeInfo(callExpr, Variance.OUT_VARIANCE)
}
val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_VARIANCE)))
return CreateFunctionFromUsageFix(callExpr, FunctionInfo(operationName, receiverType, returnType, parameters))
return CreateFunctionFromUsageFix(callExpr, createFunctionInfo(operationName, receiverType, returnType, parameters))
}
}
@@ -33,6 +33,6 @@ object CreateComponentFunctionActionFactory : JetSingleIntentionActionFactory()
val entry = entries[componentNumber]
val returnType = TypeInfo(entry, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(multiDeclaration!!, FunctionInfo(name.getIdentifier(), ownerType, returnType))
return CreateFunctionFromUsageFix(multiDeclaration!!, createFunctionInfo(name.getIdentifier(), ownerType, returnType))
}
}
@@ -47,6 +47,6 @@ object CreateFunctionFromCallActionFactory : JetSingleIntentionActionFactory() {
}
val returnType = TypeInfo(fullCallExpr, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(callExpr, FunctionInfo(calleeExpr.getReferencedName(), receiverType, returnType, parameters))
return CreateFunctionFromUsageFix(callExpr, createFunctionInfo(calleeExpr.getReferencedName(), receiverType, returnType, parameters))
}
}
@@ -14,15 +14,15 @@ import org.jetbrains.jet.plugin.refactoring.chooseContainerElementIfNecessary
import org.jetbrains.jet.plugin.refactoring.getExtractionContainers
import org.jetbrains.jet.lang.psi.JetClassBody
public class CreateFunctionFromUsageFix(element: PsiElement, val functionInfo: FunctionInfo) : CreateFromUsageFixBase(element) {
public class CreateFunctionFromUsageFix(element: PsiElement, val functionInfo: CallableInfo) : CreateFromUsageFixBase(element) {
override fun getText(): String {
return JetBundle.message("create.function.from.usage", functionInfo.name)
}
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
val functionBuilder = FunctionBuilderConfiguration(functionInfo, file!!, editor!!).createBuilder()
val functionBuilder = CallableBuilderConfiguration(functionInfo, file!!, editor!!).createBuilder()
fun runBuilder(placement: FunctionPlacement) {
fun runBuilder(placement: CallablePlacement) {
functionBuilder.placement = placement
CommandProcessor.getInstance().executeCommand(project, { functionBuilder.build() }, getText(), null)
}
@@ -35,7 +35,7 @@ public class CreateFunctionFromUsageFix(element: PsiElement, val functionInfo: F
DescriptorToDeclarationUtil.getDeclaration(file, descriptor) as JetClassOrObject
}
chooseContainerElementIfNecessary(receiverTypeCandidates, editor, popupTitle, false, toPsi) {
runBuilder(FunctionPlacement.WithReceiver(it))
runBuilder(CallablePlacement.WithReceiver(it))
}
}
else {
@@ -43,7 +43,7 @@ public class CreateFunctionFromUsageFix(element: PsiElement, val functionInfo: F
chooseContainerElementIfNecessary(element.getExtractionContainers(), editor, popupTitle, true, { it }) {
val container = if (it is JetClassBody) it.getParent() as JetClassOrObject else it
runBuilder(FunctionPlacement.NoReceiver(container))
runBuilder(CallablePlacement.NoReceiver(container))
}
}
}
@@ -18,6 +18,6 @@ object CreateGetFunctionActionFactory : JetSingleIntentionActionFactory() {
}
val returnType = TypeInfo(accessExpr, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(accessExpr, FunctionInfo("get", arrayType, returnType, parameters))
return CreateFunctionFromUsageFix(accessExpr, createFunctionInfo("get", arrayType, returnType, parameters))
}
}
@@ -17,6 +17,6 @@ object CreateHasNextFunctionActionFactory : JetSingleIntentionActionFactory() {
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
val returnType = TypeInfo(KotlinBuiltIns.getInstance().getBooleanType(), Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(forExpr, FunctionInfo("hasNext", ownerType, returnType))
return CreateFunctionFromUsageFix(forExpr, createFunctionInfo("hasNext", ownerType, returnType))
}
}
@@ -28,6 +28,6 @@ object CreateInvokeFunctionActionFactory : JetSingleIntentionActionFactory() {
}
val returnType = TypeInfo(callExpr, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(callExpr, FunctionInfo("invoke", receiverType, returnType, parameters))
return CreateFunctionFromUsageFix(callExpr, createFunctionInfo("invoke", receiverType, returnType, parameters))
}
}
@@ -31,6 +31,6 @@ object CreateIteratorFunctionActionFactory : JetSingleIntentionActionFactory() {
val returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType)
val newReturnJetType = JetTypeImpl(returnJetType.getAnnotations(), returnJetType.getConstructor(), returnJetType.isNullable(), returnJetTypeArguments, returnJetType.getMemberScope())
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(forExpr, FunctionInfo("iterator", iterableType, returnType))
return CreateFunctionFromUsageFix(forExpr, createFunctionInfo("iterator", iterableType, returnType))
}
}
@@ -18,6 +18,6 @@ object CreateNextFunctionActionFactory : JetSingleIntentionActionFactory() {
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression
val returnType = TypeInfo(variableExpr, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(forExpr, FunctionInfo("next", ownerType, returnType))
return CreateFunctionFromUsageFix(forExpr, createFunctionInfo("next", ownerType, returnType))
}
}
@@ -26,6 +26,6 @@ object CreateSetFunctionActionFactory : JetSingleIntentionActionFactory() {
parameters.add(ParameterInfo(valType, "value"))
val returnType = TypeInfo(KotlinBuiltIns.getInstance().getUnitType(), Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(accessExpr, FunctionInfo("set", arrayType, returnType, parameters))
return CreateFunctionFromUsageFix(accessExpr, createFunctionInfo("set", arrayType, returnType, parameters))
}
}
@@ -22,6 +22,6 @@ public object CreateUnaryOperationActionFactory: JetSingleIntentionActionFactory
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(callExpr, Variance.OUT_VARIANCE)
return CreateFunctionFromUsageFix(callExpr, FunctionInfo(operationName.asString(), receiverType, returnType))
return CreateFunctionFromUsageFix(callExpr, createFunctionInfo(operationName.asString(), receiverType, returnType))
}
}
@@ -108,7 +108,7 @@ data class ExtractionData(
val originalStartOffset = originalElements.first?.let { e -> e.getTextRange()!!.getStartOffset() }
private val itFakeDeclaration by Delegates.lazy { JetPsiFactory(originalFile).createParameter("it", "Any?") }
private val itFakeDeclaration by Delegates.lazy { JetPsiFactory(originalFile).createParameter("it: Any?") }
val refOffsetToDeclaration by Delegates.lazy {
fun isExtractableIt(descriptor: DeclarationDescriptor, context: BindingContext): Boolean {