Create From Usage: Do not keep semantic information in quickfix instances directly as it leads to memory leaks

This commit is contained in:
Alexey Sedunov
2015-07-24 21:12:30 +03:00
parent 9d84e4b60a
commit 5bc2a4b14c
34 changed files with 1148 additions and 728 deletions
@@ -288,3 +288,5 @@ public fun PsiElement.getTextWithLocation(): String = "'${this.getText()}' at ${
public fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element)
public fun <E: PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> =
SmartPointerManager.getInstance(getProject()).createSmartPsiElementPointer(this)
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.NotNull
public object NullQuickFix : IntentionAction {
override fun getText() = ""
override fun getFamilyName() = ""
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) = false
override fun startInWriteAction() = false
override fun invoke(NotNull project: Project, editor: Editor?, file: PsiFile?) {
throw UnsupportedOperationException("invoke() shouldn't be called")
}
}
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClas
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromReferenceExpressionActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateLocalVariableActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory
import org.jetbrains.kotlin.lexer.JetTokens.*
import org.jetbrains.kotlin.psi.JetClass
@@ -250,11 +250,11 @@ public class QuickFixRegistrar : QuickFixContributor {
NO_VALUE_FOR_PARAMETER.registerFactory(CreateBinaryOperationActionFactory)
TOO_MANY_ARGUMENTS.registerFactory(CreateBinaryOperationActionFactory)
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(CreateCallableFromCallActionFactory)
UNRESOLVED_REFERENCE.registerFactory(CreateCallableFromCallActionFactory)
NO_VALUE_FOR_PARAMETER.registerFactory(CreateCallableFromCallActionFactory)
TOO_MANY_ARGUMENTS.registerFactory(CreateCallableFromCallActionFactory)
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateCallableFromCallActionFactory)
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
UNRESOLVED_REFERENCE.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
NO_VALUE_FOR_PARAMETER.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
TOO_MANY_ARGUMENTS.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
NO_VALUE_FOR_PARAMETER.registerFactory(CreateConstructorFromDelegationCallActionFactory)
TOO_MANY_ARGUMENTS.registerFactory(CreateConstructorFromDelegationCallActionFactory)
@@ -269,9 +269,9 @@ public class QuickFixRegistrar : QuickFixContributor {
UNRESOLVED_REFERENCE.registerFactory(CreateLocalVariableActionFactory)
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateLocalVariableActionFactory)
UNRESOLVED_REFERENCE.registerFactory(CreateParameterActionFactory)
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(CreateParameterActionFactory)
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateParameterActionFactory)
UNRESOLVED_REFERENCE.registerFactory(CreateParameterByRefActionFactory)
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(CreateParameterByRefActionFactory)
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateParameterByRefActionFactory)
NAMED_PARAMETER_NOT_FOUND.registerFactory(CreateParameterByNamedArgumentActionFactory)
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.NotNull
public class QuickFixWithDelegateFactory(
private val delegateFactory: () -> IntentionAction
) : IntentionAction {
private val familyName: String
private val text: String
private val startInWriteAction: Boolean
init {
val delegate = delegateFactory()
familyName = delegate.familyName
text = delegate.text
startInWriteAction = delegate.startInWriteAction()
}
override fun getFamilyName() = familyName
override fun getText() = text
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) =
delegateFactory().isAvailable(project, editor, file)
override fun startInWriteAction() = startInWriteAction
override fun invoke(NotNull project: Project, editor: Editor?, file: PsiFile?) {
delegateFactory().invoke(project, editor, file)
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.util.Ref
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.singletonOrEmptyList
public abstract class CreateFromUsageFactory<E : JetElement, D> : JetIntentionActionsFactory() {
protected abstract fun getElementOfInterest(diagnostic: Diagnostic): E?
protected open fun createQuickFix(
originalElementPointer: SmartPsiElementPointer<E>,
diagnostic: Diagnostic,
quickFixDataFactory: (SmartPsiElementPointer<E>) -> D
): QuickFixWithDelegateFactory? = null
protected open fun createQuickFixes(
originalElementPointer: SmartPsiElementPointer<E>,
diagnostic: Diagnostic,
quickFixDataFactory: (SmartPsiElementPointer<E>) -> D
): List<QuickFixWithDelegateFactory> = createQuickFix(originalElementPointer, diagnostic, quickFixDataFactory).singletonOrEmptyList()
protected abstract fun createQuickFixData(element: E, diagnostic: Diagnostic): D
override final fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val diagnosticMessage = DefaultErrorMessages.render(diagnostic)
val diagnosticElementPointer = diagnostic.psiElement.createSmartPointer()
val originalElement = getElementOfInterest(diagnostic) ?: return null
val originalElementPointer = originalElement.createSmartPointer()
val file = originalElement.containingFile
val project = file.project
// Cache data so that it can be shared between quick fixes bound to the same element & diagnostic
// Cache null values
var cachedData: Ref<D>? = null
val actions: List<QuickFixWithDelegateFactory>
try {
actions = createQuickFixes(originalElementPointer, diagnostic) factory@ {
val element = it.element ?: return@factory null
val diagnosticElement = diagnosticElementPointer.element ?: return@factory null
if (!diagnosticElement.isValid || !element.isValid) return@factory null
val currentDiagnostic =
element.analyze(BodyResolveMode.PARTIAL)
.diagnostics
.forElement(diagnosticElement)
.firstOrNull { DefaultErrorMessages.render(it) == diagnosticMessage } ?: return@factory null
if (cachedData == null) {
cachedData = Ref(createQuickFixData(element, currentDiagnostic))
}
cachedData!!.get()
}.filter { it.isAvailable(project, null, file) }
}
finally {
cachedData = null // Do not keep cache after all actions are initialized
}
return actions
}
}
@@ -16,10 +16,10 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
import org.jetbrains.kotlin.psi.JetElement
public abstract class CreateFromUsageFixBase(element: PsiElement) : JetIntentionAction<PsiElement>(element) {
public abstract class CreateFromUsageFixBase<T: JetElement>(element: T) : JetIntentionAction<T>(element) {
override fun getFamilyName(): String = JetBundle.message("create.from.usage.family")
}
@@ -234,6 +234,16 @@ fun JetCallElement.getTypeInfoForTypeArguments(): List<TypeInfo> {
return getTypeArguments().map { it.getTypeReference()?.let { TypeInfo(it, Variance.INVARIANT) } }.filterNotNull()
}
fun JetCallExpression.getParameterInfos(): List<ParameterInfo> {
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
return valueArguments.map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
it.getArgumentName()?.getReferenceExpression()?.getReferencedName()
)
}
}
private fun TypePredicate.getRepresentativeTypes(): Set<JetType> {
return when (this) {
is SingleType -> Collections.singleton(targetType)
@@ -16,44 +16,44 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.lexer.JetToken
import org.jetbrains.kotlin.types.Variance
import java.util.Collections
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.lexer.JetToken
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.Collections
public object CreateBinaryOperationActionFactory: JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val callExpr = diagnostic.getPsiElement().getParent() as? JetBinaryExpression ?: return null
val token = callExpr.getOperationToken() as JetToken
public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetBinaryExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetBinaryExpression? {
return diagnostic.psiElement.parent as? JetBinaryExpression
}
override fun createCallableInfo(element: JetBinaryExpression, diagnostic: Diagnostic): CallableInfo? {
val token = element.operationToken as JetToken
val operationName = when (token) {
JetTokens.IDENTIFIER -> callExpr.getOperationReference().getReferencedName()
else -> OperatorConventions.getNameForOperationSymbol(token)?.asString()
} ?: return null
JetTokens.IDENTIFIER -> element.operationReference.getReferencedName()
else -> OperatorConventions.getNameForOperationSymbol(token)?.asString()
} ?: return null
val inOperation = token in OperatorConventions.IN_OPERATIONS
val comparisonOperation = token in OperatorConventions.COMPARISON_OPERATIONS
val leftExpr = callExpr.getLeft() ?: return null
val rightExpr = callExpr.getRight() ?: return null
val leftExpr = element.left ?: return null
val rightExpr = element.right ?: return null
val receiverExpr = if (inOperation) rightExpr else leftExpr
val argumentExpr = if (inOperation) leftExpr else rightExpr
val builtIns = KotlinBuiltIns.getInstance()
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
val returnType = when {
inOperation -> TypeInfo.ByType(builtIns.getBooleanType(), Variance.INVARIANT).noSubstitutions()
comparisonOperation -> TypeInfo.ByType(builtIns.getIntType(), Variance.INVARIANT).noSubstitutions()
else -> TypeInfo(callExpr, Variance.OUT_VARIANCE)
inOperation -> TypeInfo.ByType(builtIns.booleanType, Variance.INVARIANT).noSubstitutions()
comparisonOperation -> TypeInfo.ByType(builtIns.intType, Variance.INVARIANT).noSubstitutions()
else -> TypeInfo(element, Variance.OUT_VARIANCE)
}
val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_VARIANCE)))
return CreateCallableFromUsageFixes(callExpr, FunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters))
return FunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters)
}
}
@@ -16,124 +16,91 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import java.util.Collections
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.resolve.BindingContext
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import com.intellij.psi.PsiClass
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.core.refactoring.getExtractionContainers
import org.jetbrains.kotlin.idea.refactoring.*
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import java.util.ArrayList
import java.util.Collections
object CreateCallableFromCallActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val diagElement = diagnostic.getPsiElement()
sealed class CreateCallableFromCallActionFactory<E : JetExpression>(
extensionsEnabled: Boolean = true
) : CreateCallableMemberFromUsageFactory<E>(extensionsEnabled) {
protected abstract fun doCreateCallableInfo(
expression: E,
context: BindingContext,
name: String,
receiverType: TypeInfo,
possibleContainers: List<JetElement>
): CallableInfo?
protected fun getExpressionOfInterest(diagnostic: Diagnostic): JetExpression? {
val diagElement = diagnostic.psiElement
if (PsiTreeUtil.getParentOfType(
diagElement,
javaClass<JetTypeReference>(), javaClass<JetAnnotationEntry>(), javaClass<JetImportDirective>()
) != null) return null
val callExpr = when (diagnostic.getFactory()) {
in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS, Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND -> {
val parent = diagElement.getParent()
if (parent is JetCallExpression && parent.getCalleeExpression() == diagElement) parent else diagElement
}
return when (diagnostic.factory) {
in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS, Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND -> {
val parent = diagElement.parent
if (parent is JetCallExpression && parent.calleeExpression == diagElement) parent else diagElement
}
Errors.NO_VALUE_FOR_PARAMETER,
Errors.TOO_MANY_ARGUMENTS -> diagElement.getNonStrictParentOfType<JetCallExpression>()
Errors.NO_VALUE_FOR_PARAMETER,
Errors.TOO_MANY_ARGUMENTS -> diagElement.getNonStrictParentOfType<JetCallExpression>()
else -> throw AssertionError("Unexpected diagnostic: ${diagnostic.getFactory()}")
} as? JetExpression ?: return null
else -> throw AssertionError("Unexpected diagnostic: ${diagnostic.factory}")
} as? JetExpression
}
val project = callExpr.getProject()
override fun createCallableInfo(element: E, diagnostic: Diagnostic): CallableInfo? {
val project = element.project
val calleeExpr = when (callExpr) {
is JetCallExpression -> callExpr.getCalleeExpression()
is JetSimpleNameExpression -> callExpr
val calleeExpr = when (element) {
is JetCallExpression -> element.calleeExpression
is JetSimpleNameExpression -> element
else -> null
} as? JetSimpleNameExpression ?: return null
if (calleeExpr.getReferencedNameElementType() != JetTokens.IDENTIFIER) return null
val callParent = callExpr.getParent()
val fullCallExpr =
if (callParent is JetQualifiedExpression && callParent.getSelectorExpression() == callExpr) callParent else callExpr
val context = calleeExpr.analyze()
val receiver = callExpr.getCall(context)?.getExplicitReceiver() ?: ReceiverValue.NO_RECEIVER
val receiver = element.getCall(context)?.explicitReceiver ?: ReceiverValue.NO_RECEIVER
val receiverType = getReceiverTypeInfo(context, project, receiver) ?: return null
val possibleContainers =
if (receiverType is TypeInfo.Empty) {
val containers = with(fullCallExpr.getExtractionContainers()) {
if (callExpr is JetCallExpression) this else filter { it is JetClassBody || it is JetFile }
val containers = with(element.getQualifiedExpressionForSelectorOrThis().getExtractionContainers()) {
if (element is JetCallExpression) this else filter { it is JetClassBody || it is JetFile }
}
if (containers.isNotEmpty()) containers else return null
}
else Collections.emptyList()
val name = calleeExpr.getReferencedName()
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
val callableInfos = ArrayList<CallableInfo>(2)
when (callExpr) {
is JetCallExpression -> {
val parameters = callExpr.getValueArguments().map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
it.getArgumentName()?.getReferenceExpression()?.getReferencedName()
)
}
val typeParameters = callExpr.getTypeInfoForTypeArguments()
val returnType = TypeInfo(fullCallExpr, Variance.OUT_VARIANCE)
callableInfos.add(FunctionInfo(name, receiverType, returnType, possibleContainers, parameters, typeParameters))
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, fullCallExpr] ?: anyType
val constructorDescriptor = callExpr.getResolvedCall(context)?.getResultingDescriptor() as? ConstructorDescriptor
val classDescriptor = constructorDescriptor?.getContainingDeclaration() as? ClassDescriptor
val klass = classDescriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
if ((klass is JetClass || klass is PsiClass) && klass.canRefactor()
&& typeParameters.isEmpty()
&& classDescriptor!!.getDefaultType().isSubtypeOf(expectedType)) {
callableInfos.add(SecondaryConstructorInfo(parameters, klass))
}
}
is JetSimpleNameExpression -> {
val varExpected = fullCallExpr.getAssignmentByLHS() != null
val returnType = TypeInfo(
fullCallExpr.getExpressionForTypeGuess(),
if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE
)
callableInfos.add(PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers))
}
}
return callableInfos.flatMap{ CreateCallableFromUsageFixes(callExpr, it) }
return doCreateCallableInfo(element, context, calleeExpr.getReferencedName(), receiverType, possibleContainers)
}
private fun getReceiverTypeInfo(context: BindingContext, project: Project, receiver: ReceiverValue): TypeInfo? {
@@ -146,9 +113,83 @@ object CreateCallableFromCallActionFactory : JetIntentionActionsFactory() {
val classifier = receiver.classifier as? JavaClassDescriptor ?: return null
val javaClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classifier) as? PsiClass
if (javaClass == null || !javaClass.canRefactor()) return null
TypeInfo.StaticContextRequired(TypeInfo(classifier.getDefaultType(), Variance.IN_VARIANCE))
TypeInfo.StaticContextRequired(TypeInfo(classifier.defaultType, Variance.IN_VARIANCE))
}
else -> TypeInfo(receiver.getType(), Variance.IN_VARIANCE)
else -> TypeInfo(receiver.type, Variance.IN_VARIANCE)
}
}
object Property: CreateCallableFromCallActionFactory<JetSimpleNameExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetSimpleNameExpression? {
return getExpressionOfInterest(diagnostic) as? JetSimpleNameExpression
}
override fun doCreateCallableInfo(
expression: JetSimpleNameExpression,
context: BindingContext,
name: String,
receiverType: TypeInfo,
possibleContainers: List<JetElement>
): CallableInfo? {
val fullCallExpr = expression.getQualifiedExpressionForSelectorOrThis()
val varExpected = fullCallExpr.getAssignmentByLHS() != null
val returnType = TypeInfo(
fullCallExpr.getExpressionForTypeGuess(),
if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE
)
return PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers)
}
}
object Function: CreateCallableFromCallActionFactory<JetCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
return getExpressionOfInterest(diagnostic) as? JetCallExpression
}
override fun doCreateCallableInfo(
expression: JetCallExpression,
context: BindingContext,
name: String,
receiverType: TypeInfo,
possibleContainers: List<JetElement>
): CallableInfo? {
val parameters = expression.getParameterInfos()
val typeParameters = expression.getTypeInfoForTypeArguments()
val returnType = TypeInfo(expression.getQualifiedExpressionForSelectorOrThis(), Variance.OUT_VARIANCE)
return FunctionInfo(name, receiverType, returnType, possibleContainers, parameters, typeParameters)
}
}
object Constructor: CreateCallableFromCallActionFactory<JetCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
return getExpressionOfInterest(diagnostic) as? JetCallExpression
}
override fun doCreateCallableInfo(
expression: JetCallExpression,
context: BindingContext,
name: String,
receiverType: TypeInfo,
possibleContainers: List<JetElement>
): CallableInfo? {
if (expression.typeArguments.isNotEmpty()) return null
val constructorDescriptor = expression.getResolvedCall(context)?.resultingDescriptor as? ConstructorDescriptor
val classDescriptor = constructorDescriptor?.containingDeclaration as? ClassDescriptor
val klass = classDescriptor?.source?.getPsi()
if ((klass !is JetClass && klass !is PsiClass) || !klass.canRefactor()) return null
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, expression.getQualifiedExpressionForSelectorOrThis()]
?: KotlinBuiltIns.getInstance().nullableAnyType
if (!classDescriptor!!.defaultType.isSubtypeOf(expectedType)) return null
val parameters = expression.getParameterInfos()
return SecondaryConstructorInfo(parameters, klass)
}
}
companion object {
val INSTANCES = arrayOf(Function, Constructor, Property)
}
}
@@ -21,35 +21,37 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.core.refactoring.chooseContainerElementIfNecessary
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.JetClassBody
import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import java.util.Collections
import java.util.HashSet
public class CreateCallableFromUsageFix(originalElement: JetElement, callableInfos: List<CallableInfo>)
: CreateCallableFromUsageFixBase(originalElement, callableInfos, false) {
constructor(originalExpression: JetElement, callableInfo: CallableInfo) : this(originalExpression, Collections.singletonList(callableInfo))
}
public class CreateCallableFromUsageFix<E : JetElement>(
originalExpression: E,
callableInfos: List<CallableInfo>
) : CreateCallableFromUsageFixBase<E>(originalExpression, callableInfos, false)
public class CreateExtensionCallableFromUsageFix(originalElement: JetElement, callableInfos: List<CallableInfo>)
: CreateCallableFromUsageFixBase(originalElement, callableInfos, true), LowPriorityAction {
constructor(originalExpression: JetElement, callableInfo: CallableInfo) : this(originalExpression, Collections.singletonList(callableInfo))
}
public class CreateExtensionCallableFromUsageFix<E : JetElement>(
originalExpression: E,
callableInfos: List<CallableInfo>
) : CreateCallableFromUsageFixBase<E>(originalExpression, callableInfos, true), LowPriorityAction
public abstract class CreateCallableFromUsageFixBase(
originalElement: JetElement,
public abstract class CreateCallableFromUsageFixBase<E : JetElement>(
originalExpression: E,
val callableInfos: List<CallableInfo>,
val isExtension: Boolean
) : CreateFromUsageFixBase(originalElement) {
) : CreateFromUsageFixBase<E>(originalExpression) {
init {
assert (callableInfos.isNotEmpty()) { "No CallableInfos: ${originalElement.getElementTextWithContext()}" }
assert (callableInfos.isNotEmpty()) { "No CallableInfos: ${originalExpression.getElementTextWithContext()}" }
if (callableInfos.size() > 1) {
val receiverSet = callableInfos.mapTo(HashSet<TypeInfo>()) { it.receiverTypeInfo }
if (receiverSet.size() > 1) throw AssertionError("All functions must have common receiver: $receiverSet")
@@ -60,7 +62,7 @@ public abstract class CreateCallableFromUsageFixBase(
}
private fun getDeclarationIfApplicable(project: Project, candidate: TypeCandidate): PsiElement? {
val descriptor = candidate.theType.getConstructor().getDeclarationDescriptor() ?: return null
val descriptor = candidate.theType.constructor.declarationDescriptor ?: return null
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
if (declaration !is JetClassOrObject && declaration !is PsiClass) return null
return if (isExtension || declaration.canRefactor()) declaration else null
@@ -92,23 +94,23 @@ public abstract class CreateCallableFromUsageFixBase(
}.toString()
}
fun isAvailable(): Boolean {
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
if (!super.isAvailable(project, editor, file)) return false
if (file !is JetFile) return false
val receiverInfo = callableInfos.first().receiverTypeInfo
if (receiverInfo is TypeInfo.Empty) return !isExtension
// TODO: Remove after companion object extensions are supported
if (isExtension && receiverInfo.staticContextRequired) return false
val file = element.getContainingFile() as JetFile
val project = file.getProject()
val callableBuilder =
CallableBuilderConfiguration(callableInfos, element as JetExpression, file, null, isExtension).createBuilder()
val callableBuilder = CallableBuilderConfiguration(callableInfos, element, file, null, isExtension).createBuilder()
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfos.first().receiverTypeInfo)
val propertyInfo = callableInfos.firstOrNull { it is PropertyInfo } as PropertyInfo?
val isFunction = callableInfos.any { it.kind == CallableKind.FUNCTION }
return receiverTypeCandidates.any {
val declaration = getDeclarationIfApplicable(project, it)
val insertToJavaInterface = declaration is PsiClass && declaration.isInterface()
val insertToJavaInterface = declaration is PsiClass && declaration.isInterface
when {
propertyInfo != null && insertToJavaInterface && (!receiverInfo.staticContextRequired || propertyInfo.writable) ->
false
@@ -128,7 +130,7 @@ public abstract class CreateCallableFromUsageFixBase(
fun runBuilder(placement: CallablePlacement) {
callableBuilder.placement = placement
project.executeCommand(getText()) { callableBuilder.build() }
project.executeCommand(text) { callableBuilder.build() }
}
if (callableInfo is SecondaryConstructorInfo) {
@@ -149,30 +151,13 @@ public abstract class CreateCallableFromUsageFixBase(
}
else {
assert(callableInfo.receiverTypeInfo is TypeInfo.Empty) {
"No receiver type candidates: ${element.getText()} in ${file.getText()}"
"No receiver type candidates: ${element.text} in ${file.text}"
}
chooseContainerElementIfNecessary(callableInfo.possibleContainers, editor, popupTitle, true, { it }) {
val container = if (it is JetClassBody) it.getParent() as JetClassOrObject else it
val container = if (it is JetClassBody) it.parent as JetClassOrObject else it
runBuilder(CallablePlacement.NoReceiver(container))
}
}
}
}
public fun CreateCallableFromUsageFixes(
originalExpression: JetExpression,
callableInfos: List<CallableInfo>
) : List<CreateCallableFromUsageFixBase> {
return listOf(
CreateCallableFromUsageFix(originalExpression, callableInfos),
CreateExtensionCallableFromUsageFix(originalExpression, callableInfos)
).filter { it.isAvailable() }
}
public fun CreateCallableFromUsageFixes(
originalExpression: JetExpression,
callableInfo: CallableInfo
) : List<CreateCallableFromUsageFixBase> {
return CreateCallableFromUsageFixes(originalExpression, Collections.singletonList(callableInfo))
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.NullQuickFix
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
public abstract class CreateCallableMemberFromUsageFactory<E : JetElement>(
val extensionsSupported: Boolean = true
) : CreateFromUsageFactory<E, List<CallableInfo>>() {
private fun newCallableQuickFix(
originalElementPointer: SmartPsiElementPointer<E>,
quickFixDataFactory: (SmartPsiElementPointer<E>) -> List<CallableInfo>,
quickFixFactory: (E, List<CallableInfo>) -> CreateCallableFromUsageFixBase<E>
): QuickFixWithDelegateFactory {
return QuickFixWithDelegateFactory {
val data = quickFixDataFactory(originalElementPointer).orEmpty()
val originalElement = originalElementPointer.element
if (data.isNotEmpty() && originalElement != null) quickFixFactory(originalElement, data) else NullQuickFix
}
}
protected open fun createCallableInfo(element: E, diagnostic: Diagnostic): CallableInfo? = null
override fun createQuickFixData(element: E, diagnostic: Diagnostic): List<CallableInfo>
= createCallableInfo(element, diagnostic).singletonOrEmptyList()
override fun createQuickFixes(
originalElementPointer: SmartPsiElementPointer<E>,
diagnostic: Diagnostic,
quickFixDataFactory: (SmartPsiElementPointer<E>) -> List<CallableInfo>
): List<QuickFixWithDelegateFactory> {
val memberFix = newCallableQuickFix(originalElementPointer, quickFixDataFactory) { element, data ->
CreateCallableFromUsageFix(element, data)
}
if (!extensionsSupported) return listOf(memberFix)
val extensionFix = newCallableQuickFix(originalElementPointer, quickFixDataFactory) { element, data ->
CreateExtensionCallableFromUsageFix(element, data)
}
return listOf(memberFix, extensionFix)
}
}
@@ -17,39 +17,38 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.resolve.dataClassUtils.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.psi.JetMultiDeclaration
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetForExpression
import org.jetbrains.kotlin.psi.JetMultiDeclaration
import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
object CreateComponentFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
object CreateComponentFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetMultiDeclaration>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetMultiDeclaration? {
QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetMultiDeclaration>())?.let { return it }
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())?.multiParameter
}
override fun createCallableInfo(element: JetMultiDeclaration, diagnostic: Diagnostic): CallableInfo? {
val diagnosticWithParameters = Errors.COMPONENT_FUNCTION_MISSING.cast(diagnostic)
val name = diagnosticWithParameters.getA()
val name = diagnosticWithParameters.a
if (!isComponentLike(name)) return null
val componentNumber = getComponentIndex(name) - 1
var multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetMultiDeclaration>())
val ownerType = if (multiDeclaration == null) {
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())!!
multiDeclaration = forExpr.getMultiParameter()!!
TypeInfo(diagnosticWithParameters.getB(), Variance.IN_VARIANCE)
}
else {
val rhs = multiDeclaration.getInitializer() ?: return null
TypeInfo(rhs, Variance.IN_VARIANCE)
}
val entries = multiDeclaration.getEntries()
val ownerType = element.initializer?.let { TypeInfo(it, Variance.IN_VARIANCE) }
?: TypeInfo(diagnosticWithParameters.b, Variance.IN_VARIANCE)
val entries = element.entries
val entry = entries[componentNumber]
val returnType = TypeInfo(entry, Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(multiDeclaration, FunctionInfo(name.getIdentifier(), ownerType, returnType))
return FunctionInfo(name.identifier, ownerType, returnType)
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -24,45 +23,48 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.SecondaryConstructorInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.Variance
object CreateConstructorFromDelegationCallActionFactory : JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val delegationCall = diagnostic.getPsiElement().getStrictParentOfType<JetConstructorDelegationCall>() ?: return null
val calleeExpression = delegationCall.getCalleeExpression() ?: return null
val currentClass = delegationCall.getStrictParentOfType<JetClass>() ?: return null
object CreateConstructorFromDelegationCallActionFactory : CreateCallableMemberFromUsageFactory<JetConstructorDelegationCall>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetConstructorDelegationCall? {
return diagnostic.psiElement.getStrictParentOfType<JetConstructorDelegationCall>()
}
val project = currentClass.getProject()
override fun createCallableInfo(element: JetConstructorDelegationCall, diagnostic: Diagnostic): CallableInfo? {
val calleeExpression = element.calleeExpression ?: return null
val currentClass = element.getStrictParentOfType<JetClass>() ?: return null
val project = currentClass.project
val classDescriptor = currentClass.resolveToDescriptor() as? ClassDescriptor ?: return null
val targetClass = if (calleeExpression.isThis()) {
val targetClass = if (calleeExpression.isThis) {
currentClass
}
else {
val superClassDescriptor = DescriptorUtils.getSuperclassDescriptors(classDescriptor)
.singleOrNull { it.getKind() == ClassKind.CLASS } ?: return null
val superClassDescriptor =
DescriptorUtils.getSuperclassDescriptors(classDescriptor).singleOrNull { it.kind == ClassKind.CLASS } ?: return null
DescriptorToSourceUtilsIde.getAnyDeclaration(project, superClassDescriptor) ?: return null
}
if (!(targetClass.canRefactor() && (targetClass is JetClass || targetClass is PsiClass))) return null
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
val parameters = delegationCall.getValueArguments().map {
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
val parameters = element.valueArguments.map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
it.getArgumentName()?.asName?.asString()
)
}
return CreateCallableFromUsageFix(delegationCall, SecondaryConstructorInfo(parameters, targetClass))
return SecondaryConstructorInfo(parameters, targetClass)
}
}
@@ -16,49 +16,48 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.SecondaryConstructorInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.Variance
object CreateConstructorFromDelegatorToSuperCallActionFactory : JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val delegationCall = diagnostic.getPsiElement().getStrictParentOfType<JetDelegatorToSuperCall>() ?: return null
val typeReference = delegationCall.getCalleeExpression().getTypeReference() ?: return null
object CreateConstructorFromDelegatorToSuperCallActionFactory : CreateCallableMemberFromUsageFactory<JetDelegatorToSuperCall>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetDelegatorToSuperCall? {
return diagnostic.psiElement.getStrictParentOfType<JetDelegatorToSuperCall>()
}
val project = delegationCall.getProject()
override fun createCallableInfo(element: JetDelegatorToSuperCall, diagnostic: Diagnostic): CallableInfo? {
val typeReference = element.calleeExpression.typeReference ?: return null
val project = element.project
val superType = typeReference.analyze()[BindingContext.TYPE, typeReference] ?: return null
val superClassDescriptor = superType.getConstructor().getDeclarationDescriptor() as? ClassDescriptor ?: return null
if (superClassDescriptor.getKind() != ClassKind.CLASS) return null
val superClassDescriptor = superType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
if (superClassDescriptor.kind != ClassKind.CLASS) return null
val targetClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, superClassDescriptor) ?: return null
if (!(targetClass.canRefactor() && (targetClass is JetClass || targetClass is PsiClass))) return null
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
val parameters = delegationCall.getValueArguments().map {
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
val parameters = element.valueArguments.map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
it.getArgumentName()?.asName?.asString()
)
}
return CreateCallableFromUsageFix(delegationCall, SecondaryConstructorInfo(parameters, targetClass))
return SecondaryConstructorInfo(parameters, targetClass)
}
}
@@ -17,25 +17,26 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetArrayAccessExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import java.util.Collections
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
object CreateGetFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>()) ?: return null
val arrayExpr = accessExpr.getArrayExpression() ?: return null
object CreateGetFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetArrayAccessExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetArrayAccessExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>())
}
override fun createCallableInfo(element: JetArrayAccessExpression, diagnostic: Diagnostic): CallableInfo? {
val arrayExpr = element.arrayExpression ?: return null
val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE)
val parameters = accessExpr.getIndexExpressions().map {
ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE))
}
val returnType = TypeInfo(accessExpr, Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(accessExpr, FunctionInfo("get", arrayType, returnType, Collections.emptyList(), parameters))
val parameters = element.indexExpressions.map { ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE)) }
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
return FunctionInfo("get", arrayType, returnType, Collections.emptyList(), parameters)
}
}
@@ -16,24 +16,27 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetForExpression
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.types.Variance
object CreateHasNextFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val diagnosticWithParameters = DiagnosticFactory.cast(diagnostic, Errors.HAS_NEXT_MISSING, Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE)
val ownerType = TypeInfo(diagnosticWithParameters.getA(), Variance.IN_VARIANCE)
object CreateHasNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())
}
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
val returnType = TypeInfo(KotlinBuiltIns.getInstance().getBooleanType(), Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(forExpr, FunctionInfo("hasNext", ownerType, returnType))
override fun createCallableInfo(element: JetForExpression, diagnostic: Diagnostic): CallableInfo? {
val diagnosticWithParameters =
DiagnosticFactory.cast(diagnostic, Errors.HAS_NEXT_MISSING, Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE)
val ownerType = TypeInfo(diagnosticWithParameters.a, Variance.IN_VARIANCE)
val returnType = TypeInfo(KotlinBuiltIns.getInstance().booleanType, Variance.OUT_VARIANCE)
return FunctionInfo("hasNext", ownerType, returnType)
}
}
@@ -16,11 +16,10 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
@@ -28,27 +27,26 @@ import org.jetbrains.kotlin.psi.JetCallExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
object CreateInvokeFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val callExpr = diagnostic.getPsiElement().getParent() as? JetCallExpression ?: return null
object CreateInvokeFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
return diagnostic.psiElement.parent as? JetCallExpression
}
val expectedType = Errors.FUNCTION_EXPECTED.cast(diagnostic).getB()
if (expectedType.isError()) return null
override fun createCallableInfo(element: JetCallExpression, diagnostic: Diagnostic): CallableInfo? {
val expectedType = Errors.FUNCTION_EXPECTED.cast(diagnostic).b
if (expectedType.isError) return null
val receiverType = TypeInfo(expectedType, Variance.IN_VARIANCE)
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
val parameters = callExpr.getValueArguments().map {
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
val parameters = element.valueArguments.map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
it.getArgumentName()?.getReferenceExpression()?.getReferencedName()
)
}
val returnType = TypeInfo(callExpr, Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(
callExpr,
FunctionInfo(OperatorConventions.INVOKE.asString(), receiverType, returnType, emptyList(), parameters)
)
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
return FunctionInfo(OperatorConventions.INVOKE.asString(), receiverType, returnType, emptyList(), parameters)
}
}
@@ -16,30 +16,33 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.psi.JetForExpression
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.types.TypeProjectionImpl
import java.util.Collections
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetForExpression
import org.jetbrains.kotlin.types.JetTypeImpl
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
import java.util.Collections
object CreateIteratorFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val file = diagnostic.getPsiFile() as? JetFile ?: return null
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
val iterableExpr = forExpr.getLoopRange() ?: return null
val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression
object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())
}
override fun createCallableInfo(element: JetForExpression, diagnostic: Diagnostic): CallableInfo? {
val file = diagnostic.psiFile as? JetFile ?: return null
val iterableExpr = element.loopRange ?: return null
val variableExpr: JetExpression = ((element.loopParameter ?: element.multiParameter) ?: return null) as JetExpression
val iterableType = TypeInfo(iterableExpr, Variance.IN_VARIANCE)
val returnJetType = KotlinBuiltIns.getInstance().getIterator().getDefaultType()
val returnJetType = KotlinBuiltIns.getInstance().iterator.defaultType
val analysisResult = file.analyzeFullyAndGetResult()
val returnJetTypeParameterTypes = variableExpr.guessTypes(analysisResult.bindingContext, analysisResult.moduleDescriptor)
@@ -47,8 +50,12 @@ object CreateIteratorFunctionActionFactory : JetIntentionActionsFactory() {
val returnJetTypeParameterType = TypeProjectionImpl(returnJetTypeParameterTypes[0])
val returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType)
val newReturnJetType = JetTypeImpl(returnJetType.getAnnotations(), returnJetType.getConstructor(), returnJetType.isMarkedNullable(), returnJetTypeArguments, returnJetType.getMemberScope())
val newReturnJetType = JetTypeImpl(returnJetType.annotations,
returnJetType.constructor,
returnJetType.isMarkedNullable,
returnJetTypeArguments,
returnJetType.memberScope)
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(forExpr, FunctionInfo("iterator", iterableType, returnType))
return FunctionInfo("iterator", iterableType, returnType)
}
}
@@ -17,24 +17,27 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetForExpression
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.types.Variance
object CreateNextFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
object CreateNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())
}
override fun createCallableInfo(element: JetForExpression, diagnostic: Diagnostic): CallableInfo? {
val diagnosticWithParameters = DiagnosticFactory.cast(diagnostic, Errors.NEXT_MISSING, Errors.NEXT_NONE_APPLICABLE)
val ownerType = TypeInfo(diagnosticWithParameters.getA(), Variance.IN_VARIANCE)
val ownerType = TypeInfo(diagnosticWithParameters.a, Variance.IN_VARIANCE)
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 CreateCallableFromUsageFixes(forExpr, FunctionInfo("next", ownerType, returnType))
val variableExpr = element.loopParameter ?: element.multiParameter ?: return null
val returnType = TypeInfo(variableExpr as JetExpression, Variance.OUT_VARIANCE)
return FunctionInfo("next", ownerType, returnType)
}
}
@@ -16,48 +16,49 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import com.intellij.util.SmartList
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.Variance
object CreatePropertyDelegateAccessorsActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val expression = diagnostic.getPsiElement() as? JetExpression ?: return null
val context = expression.analyze()
object CreatePropertyDelegateAccessorsActionFactory : CreateCallableMemberFromUsageFactory<JetExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetExpression? {
return diagnostic.psiElement as? JetExpression
}
override fun createQuickFixData(element: JetExpression, diagnostic: Diagnostic): List<CallableInfo> {
val context = element.analyze()
fun isApplicableForAccessor(accessor: PropertyAccessorDescriptor?): Boolean =
accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null
val builtIns = KotlinBuiltIns.getInstance()
val property = expression.getNonStrictParentOfType<JetProperty>() ?: return null
val property = element.getNonStrictParentOfType<JetProperty>() ?: return emptyList()
val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? PropertyDescriptor
?: return null
?: return emptyList()
val propertyReceiver = propertyDescriptor.getExtensionReceiverParameter() ?: propertyDescriptor.getDispatchReceiverParameter()
val propertyType = propertyDescriptor.getType()
val propertyReceiver = propertyDescriptor.extensionReceiverParameter ?: propertyDescriptor.dispatchReceiverParameter
val propertyType = propertyDescriptor.type
val accessorReceiverType = TypeInfo(expression, Variance.IN_VARIANCE)
val thisRefParam = ParameterInfo(TypeInfo(propertyReceiver?.getType() ?: builtIns.getNullableNothingType(), Variance.IN_VARIANCE))
val metadataParam = ParameterInfo(TypeInfo(builtIns.getPropertyMetadata().getDefaultType(), Variance.IN_VARIANCE))
val accessorReceiverType = TypeInfo(element, Variance.IN_VARIANCE)
val thisRefParam = ParameterInfo(TypeInfo(propertyReceiver?.type ?: builtIns.nullableNothingType, Variance.IN_VARIANCE))
val metadataParam = ParameterInfo(TypeInfo(builtIns.propertyMetadata.defaultType, Variance.IN_VARIANCE))
val callableInfos = SmartList<CallableInfo>()
if (isApplicableForAccessor(propertyDescriptor.getGetter())) {
if (isApplicableForAccessor(propertyDescriptor.getter)) {
val getterInfo = FunctionInfo(
name = "get",
receiverTypeInfo = accessorReceiverType,
@@ -67,17 +68,17 @@ object CreatePropertyDelegateAccessorsActionFactory : JetIntentionActionsFactory
callableInfos.add(getterInfo)
}
if (propertyDescriptor.isVar() && isApplicableForAccessor(propertyDescriptor.getSetter())) {
if (propertyDescriptor.isVar && isApplicableForAccessor(propertyDescriptor.setter)) {
val newValueParam = ParameterInfo(TypeInfo(propertyType, Variance.IN_VARIANCE))
val setterInfo = FunctionInfo(
name = "set",
receiverTypeInfo = accessorReceiverType,
returnTypeInfo = TypeInfo(builtIns.getUnitType(), Variance.OUT_VARIANCE),
returnTypeInfo = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE),
parameterInfos = listOf(thisRefParam, metadataParam, newValueParam)
)
callableInfos.add(setterInfo)
}
return CreateCallableFromUsageFixes(expression, callableInfos)
return callableInfos
}
}
@@ -16,53 +16,56 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.psi.JetArrayAccessExpression
import org.jetbrains.kotlin.types.Variance
import java.util.ArrayList
import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import java.util.Collections
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetArrayAccessExpression
import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.psi.JetOperationExpression
import org.jetbrains.kotlin.psi.JetUnaryExpression
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.ArrayList
import java.util.Collections
object CreateSetFunctionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>()) ?: return null
val arrayExpr = accessExpr.getArrayExpression() ?: return null
object CreateSetFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetArrayAccessExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetArrayAccessExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>())
}
override fun createCallableInfo(element: JetArrayAccessExpression, diagnostic: Diagnostic): CallableInfo? {
val arrayExpr = element.arrayExpression ?: return null
val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE)
val builtIns = KotlinBuiltIns.getInstance()
val parameters = accessExpr.getIndexExpressions().mapTo(ArrayList<ParameterInfo>()) {
val parameters = element.indexExpressions.mapTo(ArrayList<ParameterInfo>()) {
ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE))
}
val assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetOperationExpression>()) ?: return null
val valType = when (assignmentExpr) {
is JetBinaryExpression -> {
TypeInfo(assignmentExpr.getRight() ?: return null, Variance.IN_VARIANCE)
TypeInfo(assignmentExpr.right ?: return null, Variance.IN_VARIANCE)
}
is JetUnaryExpression -> {
if (assignmentExpr.getOperationToken() !in OperatorConventions.INCREMENT_OPERATIONS) return null
if (assignmentExpr.operationToken !in OperatorConventions.INCREMENT_OPERATIONS) return null
val context = assignmentExpr.analyze()
val rhsType = assignmentExpr.getResolvedCall(context)?.getResultingDescriptor()?.getReturnType()
TypeInfo(if (rhsType == null || ErrorUtils.containsErrorType(rhsType)) builtIns.getAnyType() else rhsType, Variance.IN_VARIANCE)
val rhsType = assignmentExpr.getResolvedCall(context)?.resultingDescriptor?.returnType
TypeInfo(if (rhsType == null || ErrorUtils.containsErrorType(rhsType)) builtIns.anyType else rhsType, Variance.IN_VARIANCE)
}
else -> return null
}
parameters.add(ParameterInfo(valType, "value"))
val returnType = TypeInfo(builtIns.getUnitType(), Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(accessExpr, FunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters))
val returnType = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE)
return FunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters)
}
}
@@ -17,25 +17,28 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.lexer.JetToken
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.psi.JetUnaryExpression
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
public object CreateUnaryOperationActionFactory: JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
val callExpr = diagnostic.getPsiElement().getParent() as? JetUnaryExpression ?: return null
val token = callExpr.getOperationToken() as JetToken
public object CreateUnaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetUnaryExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetUnaryExpression? {
return diagnostic.psiElement.parent as? JetUnaryExpression
}
override fun createCallableInfo(element: JetUnaryExpression, diagnostic: Diagnostic): CallableInfo? {
val token = element.operationToken as JetToken
val operationName = OperatorConventions.getNameForOperationSymbol(token) ?: return null
val incDec = token in OperatorConventions.INCREMENT_OPERATIONS
val receiverExpr = callExpr.getBaseExpression() ?: return null
val receiverExpr = element.baseExpression ?: return null
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(callExpr, Variance.OUT_VARIANCE)
return CreateCallableFromUsageFixes(callExpr, FunctionInfo(operationName.asString(), receiverType, returnType))
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(element, Variance.OUT_VARIANCE)
return FunctionInfo(operationName.asString(), receiverType, returnType)
}
}
@@ -16,28 +16,22 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetAnnotationEntry
import org.jetbrains.kotlin.psi.JetUserType
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall
import org.jetbrains.kotlin.psi.JetCallElement
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.psi.JetConstructorCalleeExpression
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
import java.util.Collections
import org.jetbrains.kotlin.idea.caches.resolve.analyze
public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val diagElement = diagnostic.getPsiElement()
public object CreateClassFromCallWithConstructorCalleeActionFactory : CreateClassFromUsageFactory<JetCallElement>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallElement? {
val diagElement = diagnostic.psiElement
val callElement = PsiTreeUtil.getParentOfType(
diagElement,
@@ -45,26 +39,34 @@ public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleI
javaClass<JetDelegatorToSuperCall>()
) as? JetCallElement ?: return null
val isAnnotation = callElement is JetAnnotationEntry
val callee = callElement.getCalleeExpression() as? JetConstructorCalleeExpression ?: return null
val calleeRef = callee.getConstructorReferenceExpression() ?: return null
val callee = callElement.calleeExpression as? JetConstructorCalleeExpression ?: return null
val calleeRef = callee.constructorReferenceExpression ?: return null
if (!calleeRef.isAncestor(diagElement)) return null
return callElement
}
val file = callElement.getContainingFile() as? JetFile ?: return null
val typeRef = callee.getTypeReference() ?: return null
val userType = typeRef.getTypeElement() as? JetUserType ?: return null
override fun getPossibleClassKinds(element: JetCallElement, diagnostic: Diagnostic): List<ClassKind> {
return (if (element is JetAnnotationEntry) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS).singletonList()
}
override fun createQuickFixData(element: JetCallElement, diagnostic: Diagnostic): ClassInfo? {
val isAnnotation = element is JetAnnotationEntry
val callee = element.calleeExpression as? JetConstructorCalleeExpression ?: return null
val calleeRef = callee.constructorReferenceExpression ?: return null
val file = element.containingFile as? JetFile ?: return null
val typeRef = callee.typeReference ?: return null
val userType = typeRef.typeElement as? JetUserType ?: return null
val context = userType.analyze()
val qualifier = userType.getQualifier()?.getReferenceExpression()
val qualifier = userType.qualifier?.referenceExpression
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
val valueArguments = callElement.getValueArguments()
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
val valueArguments = element.valueArguments
val defaultParamName = if (valueArguments.size() == 1) "value" else null
val parameterInfos = valueArguments.map {
ParameterInfo(
@@ -75,13 +77,12 @@ public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleI
val typeArgumentInfos = when {
isAnnotation -> Collections.emptyList<TypeInfo>()
else -> callElement.getTypeArguments()
.map { it.getTypeReference()?.let { TypeInfo(it, Variance.INVARIANT) } }
else -> element.typeArguments
.map { it.typeReference?.let { TypeInfo(it, Variance.INVARIANT) } }
.filterNotNull()
}
val classInfo = ClassInfo(
kind = if (isAnnotation) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS,
return ClassInfo(
name = calleeRef.getReferencedName(),
targetParent = targetParent,
expectedTypeInfo = TypeInfo.Empty,
@@ -89,6 +90,5 @@ public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleI
open = !isAnnotation,
typeArguments = typeArgumentInfos
)
return CreateClassFromUsageFix(callElement, classInfo)
}
}
@@ -16,43 +16,63 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeInfoForTypeArguments
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.JetTypeReference
import org.jetbrains.kotlin.psi.JetCallExpression
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetQualifiedExpression
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetAnnotationEntry
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
import java.util.Collections
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val diagElement = diagnostic.getPsiElement()
public object CreateClassFromConstructorCallActionFactory: CreateClassFromUsageFactory<JetCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
val diagElement = diagnostic.psiElement
if (diagElement.getNonStrictParentOfType<JetTypeReference>() != null) return null
val callExpr = diagElement.parent as? JetCallExpression ?: return null
return if (callExpr.calleeExpression == diagElement) callExpr else null
}
override fun getPossibleClassKinds(element: JetCallExpression, diagnostic: Diagnostic): List<ClassKind> {
val inAnnotationEntry = diagnostic.psiElement.getNonStrictParentOfType<JetAnnotationEntry>() != null
val (context, moduleDescriptor) = element.analyzeFullyAndGetResult()
val file = element.containingFile as? JetFile ?: return emptyList()
val call = element.getCall(context) ?: return emptyList()
val targetParent = getTargetParentByCall(call, file) ?: return emptyList()
val classKind = if (inAnnotationEntry) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS
val fullCallExpr = element.getQualifiedExpressionForSelectorOrThis()
if (!fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent).second(classKind)) return emptyList()
return classKind.singletonList()
}
override fun createQuickFixData(element: JetCallExpression, diagnostic: Diagnostic): ClassInfo? {
val diagElement = diagnostic.psiElement
if (diagElement.getNonStrictParentOfType<JetTypeReference>() != null) return null
val inAnnotationEntry = diagElement.getNonStrictParentOfType<JetAnnotationEntry>() != null
val callExpr = diagElement.getParent() as? JetCallExpression ?: return null
if (callExpr.getCalleeExpression() != diagElement) return null
val callExpr = diagElement.parent as? JetCallExpression ?: return null
if (callExpr.calleeExpression != diagElement) return null
val calleeExpr = callExpr.getCalleeExpression() as? JetSimpleNameExpression ?: return null
val calleeExpr = callExpr.calleeExpression as? JetSimpleNameExpression ?: return null
val name = calleeExpr.getReferencedName()
if (!inAnnotationEntry && !name.checkClassName()) return null
val callParent = callExpr.getParent()
val callParent = callExpr.parent
val fullCallExpr =
if (callParent is JetQualifiedExpression && callParent.getSelectorExpression() == callExpr) callParent else callExpr
if (callParent is JetQualifiedExpression && callParent.selectorExpression == callExpr) callParent else callExpr
val file = fullCallExpr.getContainingFile() as? JetFile ?: return null
val file = fullCallExpr.containingFile as? JetFile ?: return null
val (context, moduleDescriptor) = callExpr.analyzeFullyAndGetResult()
@@ -60,9 +80,9 @@ public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionAct
val targetParent = getTargetParentByCall(call, file) ?: return null
val inner = isInnerClassExpected(call)
val valueArguments = callExpr.getValueArguments()
val valueArguments = callExpr.valueArguments
val defaultParamName = if (inAnnotationEntry && valueArguments.size() == 1) "value" else null
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
val parameterInfos = valueArguments.map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
@@ -77,8 +97,7 @@ public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionAct
val typeArgumentInfos = if (inAnnotationEntry) Collections.emptyList() else callExpr.getTypeInfoForTypeArguments()
val classInfo = ClassInfo(
kind = classKind,
return ClassInfo(
name = name,
targetParent = targetParent,
expectedTypeInfo = expectedTypeInfo,
@@ -86,6 +105,5 @@ public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionAct
typeArguments = typeArgumentInfos,
parameterInfos = parameterInfos
)
return CreateClassFromUsageFix(callExpr, classInfo)
}
}
@@ -16,74 +16,74 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.JetTypeReference
import java.util.Collections
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetQualifiedExpression
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.JetCallExpression
import org.jetbrains.kotlin.psi.JetImportDirective
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetReferenceExpression
import java.util.Arrays
import org.jetbrains.kotlin.psi.JetDotQualifiedExpression
import org.jetbrains.kotlin.psi.psiUtil.isDotReceiver
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.isDotReceiver
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import java.util.Arrays
import java.util.Collections
public object CreateClassFromReferenceExpressionActionFactory : JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
public object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFactory<JetSimpleNameExpression>(true) {
override fun getElementOfInterest(diagnostic: Diagnostic): JetSimpleNameExpression? {
val refExpr = diagnostic.psiElement as? JetSimpleNameExpression ?: return null
if (refExpr.getNonStrictParentOfType<JetTypeReference>() != null) return null
return refExpr
}
private fun getFullCallExpression(element: JetSimpleNameExpression): JetExpression? {
return element.parent?.let {
when {
it is JetCallExpression && it.calleeExpression == element -> return null
it is JetQualifiedExpression && it.selectorExpression == element -> it
else -> element
}
} as? JetExpression
}
private fun isQualifierExpected(element: JetSimpleNameExpression) = element.isDotReceiver() || ((element.parent as? JetDotQualifiedExpression)?.isDotReceiver() ?: false)
private fun isInsideOfImport(element: JetSimpleNameExpression) = element.getNonStrictParentOfType<JetImportDirective>() != null
override fun getPossibleClassKinds(element: JetSimpleNameExpression, diagnostic: Diagnostic): List<ClassKind> {
fun isEnum(element: PsiElement): Boolean {
return when (element) {
is JetClass -> element.isEnum()
is PsiClass -> element.isEnum()
is PsiClass -> element.isEnum
else -> false
}
}
val refExpr = diagnostic.getPsiElement() as? JetSimpleNameExpression ?: return Collections.emptyList()
if (refExpr.getNonStrictParentOfType<JetTypeReference>() != null) return Collections.emptyList()
val file = element.containingFile as? JetFile ?: return Collections.emptyList()
val file = refExpr.getContainingFile() as? JetFile ?: return Collections.emptyList()
val name = element.getReferencedName()
val name = refExpr.getReferencedName()
val (context, moduleDescriptor) = element.analyzeFullyAndGetResult()
val (context, moduleDescriptor) = refExpr.analyzeFullyAndGetResult()
val fullCallExpr = getFullCallExpression(element) ?: return Collections.emptyList()
val fullCallExpr = refExpr.getParent()?.let {
when {
it is JetCallExpression && it.getCalleeExpression() == refExpr -> return Collections.emptyList()
it is JetQualifiedExpression && it.getSelectorExpression() == refExpr -> it
else -> refExpr
}
} as? JetExpression ?: return Collections.emptyList()
val inImport = refExpr.getNonStrictParentOfType<JetImportDirective>() != null
val qualifierExpected = refExpr.isDotReceiver() || ((refExpr.getParent() as? JetDotQualifiedExpression)?.isDotReceiver() ?: false)
if (inImport || qualifierExpected) {
val receiverSelector = (fullCallExpr as? JetQualifiedExpression)?.getReceiverExpression()?.getQualifiedElementSelector() as? JetReferenceExpression
val inImport = element.getNonStrictParentOfType<JetImportDirective>() != null
if (inImport || isQualifierExpected(element)) {
val receiverSelector = (fullCallExpr as? JetQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? JetReferenceExpression
val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] }
val targetParent =
getTargetParentByQualifier(refExpr.getContainingJetFile(), receiverSelector != null, qualifierDescriptor)
getTargetParentByQualifier(element.getContainingJetFile(), receiverSelector != null, qualifierDescriptor)
?: return Collections.emptyList()
val createPackageAction = refExpr.getCreatePackageFixIfApplicable(targetParent)
if (createPackageAction != null) return Collections.singletonList(createPackageAction)
element.getCreatePackageFixIfApplicable(targetParent)?.let { return emptyList() }
return (if (name.checkClassName()) ClassKind.values() else arrayOf())
if (!name.checkClassName()) return emptyList()
return ClassKind
.values()
.filter {
when (it) {
ClassKind.ANNOTATION_CLASS -> inImport
@@ -91,24 +91,15 @@ public object CreateClassFromReferenceExpressionActionFactory : JetIntentionActi
else -> true
}
}
.map {
val classInfo = ClassInfo(
kind = it,
name = name,
targetParent = targetParent,
expectedTypeInfo = TypeInfo.Empty
)
CreateClassFromUsageFix(refExpr, classInfo)
}
}
if (fullCallExpr.getAssignmentByLHS() != null) return Collections.emptyList()
val call = refExpr.getCall(context) ?: return Collections.emptyList()
val call = element.getCall(context) ?: return Collections.emptyList()
val targetParent = getTargetParentByCall(call, file) ?: return Collections.emptyList()
if (isInnerClassExpected(call)) return Collections.emptyList()
val (expectedTypeInfo, filter) = fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent)
val filter = fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent).second
return Arrays.asList(ClassKind.OBJECT, ClassKind.ENUM_ENTRY)
.filter {
@@ -118,14 +109,41 @@ public object CreateClassFromReferenceExpressionActionFactory : JetIntentionActi
else -> false
}
}
.map {
val classInfo = ClassInfo(
kind = it,
name = name,
targetParent = targetParent,
expectedTypeInfo = expectedTypeInfo
)
CreateClassFromUsageFix(refExpr, classInfo)
}
}
override fun createQuickFixData(element: JetSimpleNameExpression, diagnostic: Diagnostic): ClassInfo? {
val file = element.containingFile as? JetFile ?: return null
val name = element.getReferencedName()
val (context, moduleDescriptor) = element.analyzeFullyAndGetResult()
val fullCallExpr = getFullCallExpression(element) ?: return null
if (isInsideOfImport(element) || isQualifierExpected(element)) {
val receiverSelector = (fullCallExpr as? JetQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? JetReferenceExpression
val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] }
val targetParent =
getTargetParentByQualifier(element.getContainingJetFile(), receiverSelector != null, qualifierDescriptor)
?: return null
return ClassInfo(
name = name,
targetParent = targetParent,
expectedTypeInfo = TypeInfo.Empty
)
}
val call = element.getCall(context) ?: return null
val targetParent = getTargetParentByCall(call, file) ?: return null
val expectedTypeInfo = fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent).first
return ClassInfo(
name = name,
targetParent = targetParent,
expectedTypeInfo = expectedTypeInfo
)
}
}
@@ -16,49 +16,36 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import java.util.Collections
import org.jetbrains.kotlin.psi.JetUserType
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.psi.JetDelegatorToSuperClass
import org.jetbrains.kotlin.psi.JetConstructorCalleeExpression
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.JetConstructorCalleeExpression
import org.jetbrains.kotlin.psi.JetDelegatorToSuperClass
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetUserType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.Variance
import java.util.Collections
public object CreateClassFromTypeReferenceActionFactory: JetIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val userType = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetUserType>()) ?: return Collections.emptyList()
val typeArguments = userType.getTypeArgumentsAsTypes()
public object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<JetUserType>(true) {
override fun getElementOfInterest(diagnostic: Diagnostic): JetUserType? {
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetUserType>())
}
val refExpr = userType.getReferenceExpression() ?: return Collections.emptyList()
val name = refExpr.getReferencedName()
val typeRefParent = userType.getParent()?.getParent()
override fun getPossibleClassKinds(element: JetUserType, diagnostic: Diagnostic): List<ClassKind> {
val typeRefParent = element.parent?.parent
if (typeRefParent is JetConstructorCalleeExpression) return Collections.emptyList()
val traitExpected = typeRefParent is JetDelegatorToSuperClass
val context = userType.analyze()
val isQualifier = (element.parent as? JetUserType)?.let { it.qualifier == element } ?: false
val file = userType.getContainingFile() as? JetFile ?: return Collections.emptyList()
val isQualifier = (userType.getParent() as? JetUserType)?.let { it.getQualifier() == userType } ?: false
val qualifier = userType.getQualifier()?.getReferenceExpression()
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return Collections.emptyList()
val possibleKinds = when {
return when {
traitExpected -> Collections.singletonList(ClassKind.TRAIT)
else -> ClassKind.values().filter {
val noTypeArguments = typeArguments.isEmpty()
val noTypeArguments = element.typeArgumentsAsTypes.isEmpty()
when (it) {
ClassKind.OBJECT -> noTypeArguments && isQualifier
ClassKind.ANNOTATION_CLASS -> noTypeArguments && !isQualifier
@@ -68,22 +55,29 @@ public object CreateClassFromTypeReferenceActionFactory: JetIntentionActionsFact
}
}
}
}
val anyType = KotlinBuiltIns.getInstance().getAnyType()
override fun createQuickFixData(element: JetUserType, diagnostic: Diagnostic): ClassInfo? {
val name = element.referenceExpression?.getReferencedName() ?: return null
if (element.parent?.parent is JetConstructorCalleeExpression) return null
val createPackageAction = refExpr.getCreatePackageFixIfApplicable(targetParent)
val createClassActions = possibleKinds.map {
val classInfo = ClassInfo(
kind = it,
name = name,
targetParent = targetParent,
expectedTypeInfo = TypeInfo.Empty,
typeArguments = typeArguments.map {
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
}
)
CreateClassFromUsageFix(userType, classInfo)
}
return createPackageAction.singletonOrEmptyList() + createClassActions
val file = element.containingFile as? JetFile ?: return null
val context = element.analyze()
val qualifier = element.qualifier?.referenceExpression
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
val anyType = KotlinBuiltIns.getInstance().anyType
return ClassInfo(
name = name,
targetParent = targetParent,
expectedTypeInfo = TypeInfo.Empty,
typeArguments = element.typeArgumentsAsTypes.map {
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
}
)
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.NullQuickFix
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFactory
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetUserType
abstract class CreateClassFromUsageFactory<E : JetElement>(
val createPackageIsAvailable: Boolean = false
) : CreateFromUsageFactory<E, ClassInfo?>() {
protected abstract fun getPossibleClassKinds(element: E, diagnostic: Diagnostic): List<ClassKind>
override fun createQuickFixes(
originalElementPointer: SmartPsiElementPointer<E>,
diagnostic: Diagnostic,
quickFixDataFactory: (SmartPsiElementPointer<E>) -> ClassInfo?
): List<QuickFixWithDelegateFactory> {
val originalElement = originalElementPointer.element ?: return emptyList()
val classFixes = getPossibleClassKinds(originalElement, diagnostic).map { classKind ->
QuickFixWithDelegateFactory {
val currentElement = originalElementPointer.element
val data = quickFixDataFactory(originalElementPointer)
if (currentElement != null && data != null) {
CreateClassFromUsageFix(originalElement, data.copy(kind = classKind))
} else NullQuickFix
}
}
if (!createPackageIsAvailable) return classFixes
val refExpr = (originalElement as? JetUserType)?.referenceExpression ?: return classFixes
val packageFix = QuickFixWithDelegateFactory {
quickFixDataFactory(originalElementPointer)?.let {
refExpr.getCreatePackageFixIfApplicable(it.targetParent)
} ?: NullQuickFix
}
return classFixes + packageFix
}
}
@@ -25,17 +25,13 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiPackage
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.core.refactoring.getOrCreateKotlinFile
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.ENUM_ENTRY
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.OBJECT
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.PLAIN_CLASS
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.TRAIT
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.*
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetFile
@@ -48,11 +44,12 @@ enum class ClassKind(val keyword: String, val description: String) {
ENUM_ENTRY("", "enum constant"),
ANNOTATION_CLASS("annotation class", "annotation"),
TRAIT("interface", "interface"),
OBJECT("object", "object")
OBJECT("object", "object"),
DEFAULT("", "") // Used as a placeholder and must be replaced with one of the kinds above
}
public class ClassInfo(
val kind: ClassKind,
public data class ClassInfo(
val kind: ClassKind = ClassKind.DEFAULT,
val name: String,
val targetParent: PsiElement,
val expectedTypeInfo: TypeInfo,
@@ -62,19 +59,19 @@ public class ClassInfo(
val parameterInfos: List<ParameterInfo> = Collections.emptyList()
)
public class CreateClassFromUsageFix(
element: JetElement,
public class CreateClassFromUsageFix<E : JetElement>(
element: E,
val classInfo: ClassInfo
): CreateFromUsageFixBase(element) {
): CreateFromUsageFixBase<E>(element) {
override fun getText() = "Create ${classInfo.kind.description} '${classInfo.name}'"
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
if (!super.isAvailable(project, editor, file)) return false
with(classInfo) {
if (kind == DEFAULT) return false
if (targetParent is PsiClass) {
if (kind == OBJECT || kind == ENUM_ENTRY) return false
if (targetParent.isInterface() && inner) return false
if (targetParent.isInterface && inner) return false
}
}
return true
@@ -82,27 +79,27 @@ public class CreateClassFromUsageFix(
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
fun createFileByPackage(psiPackage: PsiPackage): JetFile? {
val directories = psiPackage.getDirectories().filter { it.canRefactor() }
assert (directories.isNotEmpty()) { "Package '${psiPackage.getQualifiedName()}' must be refactorable" }
val directories = psiPackage.directories.filter { it.canRefactor() }
assert (directories.isNotEmpty()) { "Package '${psiPackage.qualifiedName}' must be refactorable" }
val currentModule = ModuleUtilCore.findModuleForPsiElement(file)
val preferredDirectory =
directories.firstOrNull { ModuleUtilCore.findModuleForPsiElement(it) == currentModule }
?: directories.firstOrNull()
val targetDirectory = if (directories.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode()) {
val targetDirectory = if (directories.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode) {
DirectoryChooserUtil.chooseDirectory(directories.toTypedArray(), preferredDirectory, project, HashMap())
}
else {
preferredDirectory
} ?: return null
val fileName = "${classInfo.name}.${JetFileType.INSTANCE.getDefaultExtension()}"
val fileName = "${classInfo.name}.${JetFileType.INSTANCE.defaultExtension}"
val targetFile = getOrCreateKotlinFile(fileName, targetDirectory)
if (targetFile == null) {
val filePath = "${targetDirectory.getVirtualFile().getPath()}/$fileName"
val filePath = "${targetDirectory.virtualFile.path}/$fileName"
CodeInsightUtils.showErrorHint(
targetDirectory.getProject(),
targetDirectory.project,
editor!!,
"File $filePath already exists but does not correspond to Kotlin file",
"Create file",
@@ -117,7 +114,7 @@ public class CreateClassFromUsageFix(
when (targetParent) {
is JetElement, is PsiClass -> targetParent
is PsiPackage -> createFileByPackage(targetParent)
else -> throw AssertionError("Unexpected element: " + targetParent.getText())
else -> throw AssertionError("Unexpected element: " + targetParent.text)
} ?: return
val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo)
@@ -125,7 +122,7 @@ public class CreateClassFromUsageFix(
Collections.singletonList(constructorInfo), element as JetElement, file, editor, false, kind == PLAIN_CLASS || kind == TRAIT
).createBuilder()
builder.placement = CallablePlacement.NoReceiver(targetParent)
project.executeCommand(getText()) { builder.build() }
project.executeCommand(text) { builder.build() }
}
}
}
@@ -17,14 +17,13 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.intentions.ConvertToBlockBodyIntention
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.util.application.executeCommand
@@ -47,7 +46,7 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
.filter { it is JetBlockExpression || it is JetDeclarationWithBody }
.firstOrNull() as? JetElement ?: return null
return object: CreateFromUsageFixBase(refExpr) {
return object: CreateFromUsageFixBase<JetSimpleNameExpression>(refExpr) {
override fun getText(): String = JetBundle.message("create.local.variable.from.usage", propertyName)
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
@@ -57,12 +56,12 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
val actualContainer = when (container) {
is JetBlockExpression -> container
else -> ConvertToBlockBodyIntention.convert(container as JetDeclarationWithBody).getBodyExpression()!!
else -> ConvertToBlockBodyIntention.convert(container as JetDeclarationWithBody).bodyExpression!!
} as JetBlockExpression
if (actualContainer != container) {
val bodyExpression = actualContainer.getStatements().first()
originalElement = (bodyExpression as? JetReturnExpression)?.getReturnedExpression() ?: bodyExpression
val bodyExpression = actualContainer.statements.first()!!
originalElement = (bodyExpression as? JetReturnExpression)?.returnedExpression ?: bodyExpression
}
val typeInfo = TypeInfo(
@@ -73,7 +72,7 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
with (CallableBuilderConfiguration(propertyInfo.singletonOrEmptyList(), originalElement, file, editor).createBuilder()) {
placement = CallablePlacement.NoReceiver(actualContainer)
project.executeCommand(getText()) { build() }
project.executeCommand(text) { build() }
}
}
}
@@ -1,147 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.JetPropertyAccessor
import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetClassInitializer
import org.jetbrains.kotlin.psi.JetClassBody
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeParameters
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import java.util.LinkedHashSet
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
import org.jetbrains.kotlin.psi.JetEnumEntry
import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.psi.JetDelegationSpecifier
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
object CreateParameterActionFactory: JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val result = (diagnostic.getPsiFile() as? JetFile)?.analyzeFullyAndGetResult() ?: return null
val context = result.bindingContext
val refExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetSimpleNameExpression>()) ?: return null
if (refExpr.getQualifiedElement() != refExpr) return null
val varExpected = refExpr.getAssignmentByLHS() != null
val paramType = refExpr.getExpressionForTypeGuess().guessTypes(context, result.moduleDescriptor).let {
when (it.size()) {
0 -> KotlinBuiltIns.getInstance().getAnyType()
1 -> it.first()
else -> return null
}
}
var valOrVar: JetValVar = JetValVar.None
fun chooseContainingClass(it: PsiElement): JetClass? {
valOrVar = if (varExpected) JetValVar.Var else JetValVar.Val
return it.parents.firstIsInstanceOrNull<JetClassOrObject>() as? JetClass
}
// todo: skip lambdas for now because Change Signature doesn't apply to them yet
val container = refExpr.parents
.filter {
it is JetNamedFunction || it is JetPropertyAccessor || it is JetClassBody || it is JetClassInitializer ||
it is JetDelegationSpecifier
}
.firstOrNull()
?.let {
when {
it is JetNamedFunction && varExpected,
it is JetPropertyAccessor -> chooseContainingClass(it)
it is JetClassInitializer -> it.getParent()?.getParent() as? JetClass
it is JetDelegationSpecifier -> {
val klass = it.getStrictParentOfType<JetClass>()
if (klass != null && !klass.isInterface() && klass !is JetEnumEntry) klass else null
}
it is JetClassBody -> {
val klass = it.getParent() as? JetClass
when {
klass is JetEnumEntry -> chooseContainingClass(klass)
klass != null && klass.isInterface() -> null
else -> klass
}
}
else -> it
}
} ?: return null
val functionDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, container]?.let {
if (it is ClassDescriptor) it.getUnsubstitutedPrimaryConstructor() else it
} as? FunctionDescriptor ?: return null
if (paramType.hasTypeParametersToAdd(functionDescriptor, context)) return null
return CreateParameterFromUsageFix(
functionDescriptor,
context,
JetParameterInfo(callableDescriptor = functionDescriptor,
name = refExpr.getReferencedName(),
type = paramType,
valOrVar = valOrVar),
refExpr
)
}
}
fun JetType.hasTypeParametersToAdd(functionDescriptor: FunctionDescriptor, context: BindingContext): Boolean {
val typeParametersToAdd = LinkedHashSet(getTypeParameters())
typeParametersToAdd.removeAll(functionDescriptor.getTypeParameters())
if (typeParametersToAdd.isEmpty()) return false
val scope = when(functionDescriptor) {
is ConstructorDescriptor -> {
val classDescriptor = functionDescriptor.getContainingDeclaration() as? ClassDescriptorWithResolutionScopes
classDescriptor?.getScopeForClassHeaderResolution()
}
is FunctionDescriptor -> {
val function = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) as? JetFunction
function?.let { context[BindingContext.RESOLUTION_SCOPE, it.getBodyExpression()] }
}
else -> null
} ?: return true
return typeParametersToAdd.any { scope.getClassifier(it.getName()) != it }
}
@@ -16,40 +16,38 @@
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import org.jetbrains.kotlin.psi.JetValueArgument
import org.jetbrains.kotlin.psi.JetCallElement
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
public object CreateParameterByNamedArgumentActionFactory: JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val result = (diagnostic.getPsiFile() as? JetFile)?.analyzeFullyAndGetResult() ?: return null
public object CreateParameterByNamedArgumentActionFactory: CreateParameterFromUsageFactory<JetValueArgument>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetValueArgument? {
val argument = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetValueArgument>()) ?: return null
return if (argument.isNamed()) argument else null
}
override fun createQuickFixData(element: JetValueArgument, diagnostic: Diagnostic): CreateParameterData<JetValueArgument>? {
val result = (diagnostic.psiFile as? JetFile)?.analyzeFullyAndGetResult() ?: return null
val context = result.bindingContext
val argument = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetValueArgument>()) ?: return null
val name = argument.getArgumentName()?.getText() ?: return null
val argumentExpression = argument.getArgumentExpression()
val name = element.getArgumentName()?.text ?: return null
val argumentExpression = element.getArgumentExpression()
val callElement = argument.getStrictParentOfType<JetCallElement>() ?: return null
val functionDescriptor = callElement.getResolvedCall(context)?.getResultingDescriptor() as? FunctionDescriptor ?: return null
val callable = DescriptorToSourceUtilsIde.getAnyDeclaration(callElement.getProject(), functionDescriptor) ?: return null
val callElement = element.getStrictParentOfType<JetCallElement>() ?: return null
val functionDescriptor = callElement.getResolvedCall(context)?.resultingDescriptor as? FunctionDescriptor ?: return null
val callable = DescriptorToSourceUtilsIde.getAnyDeclaration(callElement.project, functionDescriptor) ?: return null
if (!((callable is JetFunction || callable is JetClass) && callable.canRefactor())) return null
val anyType = KotlinBuiltIns.getInstance().getAnyType()
val anyType = KotlinBuiltIns.getInstance().anyType
val paramType = argumentExpression?.guessTypes(context, result.moduleDescriptor)?.let {
when (it.size()) {
0 -> anyType
@@ -65,6 +63,7 @@ public object CreateParameterByNamedArgumentActionFactory: JetSingleIntentionAct
type = paramType,
defaultValueForCall = argumentExpression
)
return CreateParameterFromUsageFix(functionDescriptor, context, parameterInfo, argument)
return CreateParameterData(context, parameterInfo, element)
}
}
@@ -0,0 +1,140 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeParameters
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.util.LinkedHashSet
object CreateParameterByRefActionFactory : CreateParameterFromUsageFactory<JetSimpleNameExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetSimpleNameExpression? {
val refExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetSimpleNameExpression>()) ?: return null
if (refExpr.getQualifiedElement() != refExpr) return null
return refExpr
}
override fun createQuickFixData(
element: JetSimpleNameExpression,
diagnostic: Diagnostic
): CreateParameterData<JetSimpleNameExpression>? {
val result = (diagnostic.psiFile as? JetFile)?.analyzeFullyAndGetResult() ?: return null
val context = result.bindingContext
val varExpected = element.getAssignmentByLHS() != null
val paramType = element.getExpressionForTypeGuess().guessTypes(context, result.moduleDescriptor).let {
when (it.size()) {
0 -> KotlinBuiltIns.getInstance().anyType
1 -> it.first()
else -> return null
}
}
var valOrVar: JetValVar = JetValVar.None
fun chooseContainingClass(it: PsiElement): JetClass? {
valOrVar = if (varExpected) JetValVar.Var else JetValVar.Val
return it.parents.firstIsInstanceOrNull<JetClassOrObject>() as? JetClass
}
// todo: skip lambdas for now because Change Signature doesn't apply to them yet
val container = element.parents
.filter {
it is JetNamedFunction || it is JetPropertyAccessor || it is JetClassBody || it is JetClassInitializer ||
it is JetDelegationSpecifier
}
.firstOrNull()
?.let {
when {
it is JetNamedFunction && varExpected,
it is JetPropertyAccessor -> chooseContainingClass(it)
it is JetClassInitializer -> it.parent?.parent as? JetClass
it is JetDelegationSpecifier -> {
val klass = it.getStrictParentOfType<JetClass>()
if (klass != null && !klass.isInterface() && klass !is JetEnumEntry) klass else null
}
it is JetClassBody -> {
val klass = it.parent as? JetClass
when {
klass is JetEnumEntry -> chooseContainingClass(klass)
klass != null && klass.isInterface() -> null
else -> klass
}
}
else -> it
}
} ?: return null
val functionDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, container]?.let {
if (it is ClassDescriptor) it.unsubstitutedPrimaryConstructor else it
} as? FunctionDescriptor ?: return null
if (paramType.hasTypeParametersToAdd(functionDescriptor, context)) return null
return CreateParameterData(
context,
JetParameterInfo(callableDescriptor = functionDescriptor,
name = element.getReferencedName(),
type = paramType,
valOrVar = valOrVar),
element
)
}
}
fun JetType.hasTypeParametersToAdd(functionDescriptor: FunctionDescriptor, context: BindingContext): Boolean {
val typeParametersToAdd = LinkedHashSet(getTypeParameters())
typeParametersToAdd.removeAll(functionDescriptor.typeParameters)
if (typeParametersToAdd.isEmpty()) return false
val scope =
when (functionDescriptor) {
is ConstructorDescriptor -> {
(functionDescriptor.containingDeclaration as? ClassDescriptorWithResolutionScopes)?.scopeForClassHeaderResolution
}
is FunctionDescriptor -> {
val function = functionDescriptor.source.getPsi() as? JetFunction
function?.let { context[BindingContext.RESOLUTION_SCOPE, it.bodyExpression] }
}
else -> null
} ?: return true
return typeParametersToAdd.any { scope.getClassifier(it.name) != it }
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.NullQuickFix
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFactory
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.resolve.BindingContext
data class CreateParameterData<E : JetElement>(
val context: BindingContext,
val parameterInfo: JetParameterInfo,
val originalExpression: E
)
abstract class CreateParameterFromUsageFactory<E : JetElement>: CreateFromUsageFactory<E, CreateParameterData<E>?>() {
override fun createQuickFix(
originalElementPointer: SmartPsiElementPointer<E>,
diagnostic: Diagnostic,
quickFixDataFactory: (SmartPsiElementPointer<E>) -> CreateParameterData<E>?
): QuickFixWithDelegateFactory? {
return QuickFixWithDelegateFactory {
quickFixDataFactory(originalElementPointer)?.let { data ->
CreateParameterFromUsageFix(data.parameterInfo.callableDescriptor as FunctionDescriptor,
data.context,
data.parameterInfo,
data.originalExpression)
} ?: NullQuickFix
}
}
}
@@ -27,14 +27,14 @@ import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.BindingContext
public class CreateParameterFromUsageFix(
public class CreateParameterFromUsageFix<E : JetElement>(
val functionDescriptor: FunctionDescriptor,
val bindingContext: BindingContext,
val parameterInfo: JetParameterInfo,
val defaultValueContext: JetElement
) : CreateFromUsageFixBase(defaultValueContext) {
val defaultValueContext: E
) : CreateFromUsageFixBase<E>(defaultValueContext) {
override fun getText(): String {
return JetBundle.message("create.parameter.from.usage", parameterInfo.getName())
return JetBundle.message("create.parameter.from.usage", parameterInfo.name)
}
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
@@ -46,6 +46,6 @@ public class CreateParameterFromUsageFix(
override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean = false
}
runChangeSignature(project, functionDescriptor, config, bindingContext, defaultValueContext, getText())
runChangeSignature(project, functionDescriptor, config, bindingContext, defaultValueContext, text)
}
}