172: Revert "Refactoring: Use modifier list in CallableInfo where possible"

This reverts commit 99be75c
This commit is contained in:
Vyacheslav Gerasimov
2018-01-18 02:16:51 +03:00
committed by Nikolay Krasko
parent 577e6e5206
commit deb2ffb49f
14 changed files with 2728 additions and 0 deletions
@@ -0,0 +1,281 @@
/*
* 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.callableBuilder
import com.intellij.psi.PsiElement
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassInfo
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.getResolvableApproximations
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import java.util.*
/**
* Represents a concrete type or a set of types yet to be inferred from an expression.
*/
abstract class TypeInfo(val variance: Variance) {
object Empty: TypeInfo(Variance.INVARIANT) {
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> = Collections.emptyList()
}
class ByExpression(val expression: KtExpression, variance: Variance): TypeInfo(variance) {
override fun getPossibleNamesFromExpression(bindingContext: BindingContext): Array<String> {
return KotlinNameSuggester.suggestNamesByExpressionOnly(expression, bindingContext, { true }).toTypedArray()
}
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> =
expression.guessTypes(
context = builder.currentFileContext,
module = builder.currentFileModule,
pseudocode = builder.pseudocode
).flatMap { it.getPossibleSupertypes(variance, builder) }
}
class ByTypeReference(val typeReference: KtTypeReference, variance: Variance): TypeInfo(variance) {
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> =
builder.currentFileContext[BindingContext.TYPE, typeReference].getPossibleSupertypes(variance, builder)
}
class ByType(val theType: KotlinType, variance: Variance): TypeInfo(variance) {
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> =
theType.getPossibleSupertypes(variance, builder)
}
class ByReceiverType(variance: Variance): TypeInfo(variance) {
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> =
(builder.placement as CallablePlacement.WithReceiver).receiverTypeCandidate.theType.getPossibleSupertypes(variance, builder)
}
class ByExplicitCandidateTypes(val types: List<KotlinType>) : TypeInfo(Variance.INVARIANT) {
override fun getPossibleTypes(builder: CallableBuilder) = types
}
abstract class DelegatingTypeInfo(val delegate: TypeInfo): TypeInfo(delegate.variance) {
override val substitutionsAllowed: Boolean = delegate.substitutionsAllowed
override fun getPossibleNamesFromExpression(bindingContext: BindingContext) = delegate.getPossibleNamesFromExpression(bindingContext)
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> = delegate.getPossibleTypes(builder)
}
class NoSubstitutions(delegate: TypeInfo): DelegatingTypeInfo(delegate) {
override val substitutionsAllowed: Boolean = false
}
class StaticContextRequired(delegate: TypeInfo): DelegatingTypeInfo(delegate) {
override val staticContextRequired: Boolean = true
}
class OfThis(delegate: TypeInfo) : DelegatingTypeInfo(delegate)
val isOfThis: Boolean
get() = when (this) {
is OfThis -> true
is DelegatingTypeInfo -> delegate.isOfThis
else -> false
}
open val substitutionsAllowed: Boolean = true
open val staticContextRequired: Boolean = false
open fun getPossibleNamesFromExpression(bindingContext: BindingContext): Array<String> = ArrayUtil.EMPTY_STRING_ARRAY
abstract fun getPossibleTypes(builder: CallableBuilder): List<KotlinType>
private fun getScopeForTypeApproximation(config: CallableBuilderConfiguration, placement: CallablePlacement?): LexicalScope? {
if (placement == null) return config.originalElement.getResolutionScope()
val containingElement = when (placement) {
is CallablePlacement.NoReceiver -> {
placement.containingElement
}
is CallablePlacement.WithReceiver -> {
val receiverClassDescriptor =
placement.receiverTypeCandidate.theType.constructor.declarationDescriptor
val classDeclaration = receiverClassDescriptor?.let { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
if (!config.isExtension && classDeclaration != null) classDeclaration else config.currentFile
}
}
return when (containingElement) {
is KtClassOrObject -> (containingElement.resolveToDescriptorIfAny() as? ClassDescriptorWithResolutionScopes)?.scopeForMemberDeclarationResolution
is KtBlockExpression -> (containingElement.statements.firstOrNull() ?: containingElement).getResolutionScope()
is KtElement -> containingElement.containingKtFile.getResolutionScope()
else -> null
}
}
protected fun KotlinType?.getPossibleSupertypes(variance: Variance, callableBuilder: CallableBuilder): List<KotlinType> {
if (this == null || ErrorUtils.containsErrorType(this)) {
return Collections.singletonList(callableBuilder.currentFileModule.builtIns.anyType)
}
val scope = getScopeForTypeApproximation(callableBuilder.config, callableBuilder.placement)
val approximations = getResolvableApproximations(scope, false, true)
return when (variance) {
Variance.IN_VARIANCE -> approximations.toList()
else -> listOf(approximations.firstOrNull() ?: this)
}
}
}
fun TypeInfo(expressionOfType: KtExpression, variance: Variance): TypeInfo = TypeInfo.ByExpression(expressionOfType, variance)
fun TypeInfo(typeReference: KtTypeReference, variance: Variance): TypeInfo = TypeInfo.ByTypeReference(typeReference, variance)
fun TypeInfo(theType: KotlinType, variance: Variance): TypeInfo = TypeInfo.ByType(theType, variance)
fun TypeInfo.noSubstitutions(): TypeInfo = (this as? TypeInfo.NoSubstitutions) ?: TypeInfo.NoSubstitutions(this)
fun TypeInfo.forceNotNull(): TypeInfo {
class ForcedNotNull(delegate: TypeInfo): TypeInfo.DelegatingTypeInfo(delegate) {
override fun getPossibleTypes(builder: CallableBuilder): List<KotlinType> =
super.getPossibleTypes(builder).map { it.makeNotNullable() }
}
return (this as? ForcedNotNull) ?: ForcedNotNull(this)
}
fun TypeInfo.ofThis() = TypeInfo.OfThis(this)
/**
* Encapsulates information about a function parameter that is going to be created.
*/
class ParameterInfo(
val typeInfo: TypeInfo,
val nameSuggestions: List<String>
) {
constructor(typeInfo: TypeInfo, preferredName: String? = null): this(typeInfo, listOfNotNull(preferredName))
}
enum class CallableKind {
FUNCTION,
CLASS_WITH_PRIMARY_CONSTRUCTOR,
CONSTRUCTOR,
PROPERTY
}
abstract class CallableInfo (
val name: String,
val receiverTypeInfo: TypeInfo,
val returnTypeInfo: TypeInfo,
val possibleContainers: List<KtElement>,
val typeParameterInfos: List<TypeInfo>,
val isAbstract: Boolean = false,
val isForCompanion: Boolean = false,
val modifierList: KtModifierList? = null
) {
abstract val kind: CallableKind
abstract val parameterInfos: List<ParameterInfo>
abstract fun copy(receiverTypeInfo: TypeInfo = this.receiverTypeInfo,
possibleContainers: List<KtElement> = this.possibleContainers,
isAbstract: Boolean = this.isAbstract): CallableInfo
}
class FunctionInfo(name: String,
receiverTypeInfo: TypeInfo,
returnTypeInfo: TypeInfo,
possibleContainers: List<KtElement> = Collections.emptyList(),
override val parameterInfos: List<ParameterInfo> = Collections.emptyList(),
typeParameterInfos: List<TypeInfo> = Collections.emptyList(),
val isOperator: Boolean = false,
val isInfix: Boolean = false,
isAbstract: Boolean = false,
isForCompanion: Boolean = false,
modifierList: KtModifierList? = null,
val preferEmptyBody: Boolean = false
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isAbstract, isForCompanion, modifierList) {
override val kind: CallableKind get() = CallableKind.FUNCTION
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = FunctionInfo(
name,
receiverTypeInfo,
returnTypeInfo,
possibleContainers,
parameterInfos,
typeParameterInfos,
isOperator,
isInfix,
isAbstract
)
}
class ClassWithPrimaryConstructorInfo(
val classInfo: ClassInfo,
expectedTypeInfo: TypeInfo,
modifierList: KtModifierList? = null
): CallableInfo(
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments, false, modifierList = modifierList
) {
override val kind: CallableKind get() = CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR
override val parameterInfos: List<ParameterInfo> get() = classInfo.parameterInfos
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
}
class ConstructorInfo(
override val parameterInfos: List<ParameterInfo>,
val targetClass: PsiElement,
val isPrimary: Boolean = false,
modifierList: KtModifierList? = null,
val withBody: Boolean = false
): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList(), false, modifierList = modifierList) {
override val kind: CallableKind get() = CallableKind.CONSTRUCTOR
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
}
class PropertyInfo(name: String,
receiverTypeInfo: TypeInfo,
returnTypeInfo: TypeInfo,
val writable: Boolean,
possibleContainers: List<KtElement> = Collections.emptyList(),
typeParameterInfos: List<TypeInfo> = Collections.emptyList(),
isAbstract: Boolean = false,
val isLateinitPreferred: Boolean = false,
isForCompanion: Boolean = false,
modifierList: KtModifierList? = null,
val withInitializer: Boolean = false
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isAbstract, isForCompanion, modifierList) {
override val kind: CallableKind get() = CallableKind.PROPERTY
override val parameterInfos: List<ParameterInfo> get() = Collections.emptyList()
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) =
copyProperty(receiverTypeInfo, possibleContainers, isAbstract)
fun copyProperty(
receiverTypeInfo: TypeInfo = this.receiverTypeInfo,
possibleContainers: List<KtElement> = this.possibleContainers,
isAbstract: Boolean = this.isAbstract,
isLateinitPreferred: Boolean = this.isLateinitPreferred
) = PropertyInfo(
name,
receiverTypeInfo,
returnTypeInfo,
writable,
possibleContainers,
typeParameterInfos,
isAbstract,
isLateinitPreferred,
isForCompanion,
modifierList,
withInitializer
)
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.project.builtIns
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.*
object CreateBinaryOperationActionFactory : CreateCallableMemberFromUsageFactory<KtBinaryExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtBinaryExpression? {
return diagnostic.psiElement.parent as? KtBinaryExpression
}
override fun createCallableInfo(element: KtBinaryExpression, diagnostic: Diagnostic): CallableInfo? {
val token = element.operationToken as KtToken
val operationName = when (token) {
KtTokens.IDENTIFIER -> element.operationReference.getReferencedName()
else -> OperatorConventions.getNameForOperationSymbol(token, false, true)?.asString()
} ?: return null
val inOperation = token in OperatorConventions.IN_OPERATIONS
val comparisonOperation = token in OperatorConventions.COMPARISON_OPERATIONS
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 = element.builtIns
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
val returnType = when {
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)))
val isOperator = token != KtTokens.IDENTIFIER
return FunctionInfo(operationName, receiverType, returnType, parameterInfos = parameters,
isOperator = isOperator,
isInfix = !isOperator)
}
}
@@ -0,0 +1,342 @@
/*
* Copyright 2010-2016 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.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.util.isAbstract
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import java.lang.AssertionError
import java.util.*
sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
extensionsEnabled: Boolean = true
) : CreateCallableMemberFromUsageFactory<E>(extensionsEnabled) {
protected abstract fun doCreateCallableInfo(
expression: E,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
): CallableInfo?
protected fun getExpressionOfInterest(diagnostic: Diagnostic): KtExpression? {
val diagElement = diagnostic.psiElement
if (PsiTreeUtil.getParentOfType(
diagElement,
KtTypeReference::class.java, KtAnnotationEntry::class.java, KtImportDirective::class.java
) != null) return null
return when (diagnostic.factory) {
in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS, Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND -> {
val parent = diagElement.parent
if (parent is KtCallExpression && parent.calleeExpression == diagElement) parent else diagElement
}
Errors.NO_VALUE_FOR_PARAMETER,
Errors.TOO_MANY_ARGUMENTS,
Errors.NONE_APPLICABLE -> diagElement.getNonStrictParentOfType<KtCallExpression>()
Errors.TYPE_MISMATCH -> (diagElement.parent as? KtValueArgument)?.getStrictParentOfType<KtCallExpression>()
else -> throw AssertionError("Unexpected diagnostic: ${diagnostic.factory}")
} as? KtExpression
}
override fun createCallableInfo(element: E, diagnostic: Diagnostic): CallableInfo? {
val project = element.project
val calleeExpr = when (element) {
is KtCallExpression -> element.calleeExpression
is KtSimpleNameExpression -> element
else -> null
} as? KtSimpleNameExpression ?: return null
if (calleeExpr.getReferencedNameElementType() != KtTokens.IDENTIFIER) return null
val analysisResult = calleeExpr.analyzeAndGetResult()
val receiver = element.getCall(analysisResult.bindingContext)?.explicitReceiver
val receiverType = getReceiverTypeInfo(analysisResult.bindingContext, project, receiver) ?: return null
val possibleContainers =
if (receiverType is TypeInfo.Empty) {
val containers = with(element.getQualifiedExpressionForSelectorOrThis().getExtractionContainers()) {
if (element is KtCallExpression) this else filter { it is KtClassBody || it is KtFile }
}
if (containers.isNotEmpty()) containers else return null
}
else Collections.emptyList()
return doCreateCallableInfo(element, analysisResult, calleeExpr.getReferencedName(), receiverType, possibleContainers)
}
private fun getReceiverTypeInfo(context: BindingContext, project: Project, receiver: Receiver?): TypeInfo? {
return when (receiver) {
null -> TypeInfo.Empty
is Qualifier -> {
val qualifierType = context.getType(receiver.expression)
if (qualifierType != null) return TypeInfo(qualifierType, Variance.IN_VARIANCE)
if (receiver !is ClassQualifier) return null
val classifierType = receiver.descriptor.classValueType
if (classifierType != null) return TypeInfo(classifierType, Variance.IN_VARIANCE)
val javaClassifier = receiver.descriptor as? JavaClassDescriptor ?: return null
val javaClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, javaClassifier) as? PsiClass
if (javaClass == null || !javaClass.canRefactor()) return null
TypeInfo.StaticContextRequired(TypeInfo(javaClassifier.defaultType, Variance.IN_VARIANCE))
}
is ReceiverValue -> TypeInfo(receiver.type, Variance.IN_VARIANCE)
else -> throw AssertionError("Unexpected receiver: $receiver")
}
}
protected fun getAbstractCallableInfo(mainCallable: CallableInfo, originalExpression: KtExpression): CallableInfo? {
val receiverTypeInfo: TypeInfo
val receiverType: KotlinType
val originalReceiverTypeInfo = mainCallable.receiverTypeInfo
if (originalReceiverTypeInfo != TypeInfo.Empty) {
if (originalReceiverTypeInfo !is TypeInfo.ByType) return null
receiverTypeInfo = originalReceiverTypeInfo
receiverType = receiverTypeInfo.theType
}
else {
val containingClass = originalExpression.getStrictParentOfType<KtClassOrObject>() as? KtClass ?: return null
if (containingClass is KtEnumEntry) return null
receiverType = (containingClass.unsafeResolveToDescriptor() as ClassDescriptor).defaultType
receiverTypeInfo = TypeInfo(receiverType, Variance.IN_VARIANCE).ofThis()
}
if (!receiverType.isAbstract() && TypeUtils.getAllSupertypes(receiverType).all { !it.isAbstract() }) return null
return mainCallable.copy(receiverTypeInfo = receiverTypeInfo, possibleContainers = emptyList(), isAbstract = true)
}
protected fun getCallableWithReceiverInsideExtension(
mainCallable: CallableInfo,
originalExpression: KtExpression,
context: BindingContext,
receiverType: TypeInfo
): CallableInfo? {
if (receiverType != TypeInfo.Empty) return null
val callable = (originalExpression.getParentOfTypeAndBranch<KtFunction> { bodyExpression }
?: originalExpression.getParentOfTypeAndBranches<KtProperty> { listOf(getter, setter) })
?: return null
if (callable !is KtFunctionLiteral && callable.receiverTypeReference == null) return null
val callableDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, callable] as? CallableDescriptor ?: return null
val extensionReceiverType = callableDescriptor.extensionReceiverParameter?.type ?: return null
val newReceiverTypeInfo = TypeInfo(extensionReceiverType, Variance.IN_VARIANCE)
return mainCallable.copy(receiverTypeInfo = newReceiverTypeInfo, possibleContainers = emptyList())
}
sealed class Property: CreateCallableFromCallActionFactory<KtSimpleNameExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtSimpleNameExpression? {
val refExpr = getExpressionOfInterest(diagnostic) as? KtNameReferenceExpression ?: return null
if (refExpr.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null) return null
return refExpr
}
override fun doCreateCallableInfo(
expression: KtSimpleNameExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
): CallableInfo? {
val fullCallExpr = expression.getQualifiedExpressionForSelectorOrThis()
val varExpected = fullCallExpr.getAssignmentByLHS() != null
val expressionForTypeGuess = fullCallExpr.getExpressionForTypeGuess()
val returnTypes = expressionForTypeGuess.guessTypes(analysisResult.bindingContext, analysisResult.moduleDescriptor)
val returnTypeInfo = TypeInfo(expressionForTypeGuess, if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE)
val canBeLateinit =
varExpected
&& returnTypes.any { !it.isMarkedNullable && !KotlinBuiltIns.isPrimitiveType(it) }
&& fullCallExpr.parents.firstOrNull { it is KtDeclarationWithBody || it is KtClassInitializer } is KtDeclarationWithBody
return PropertyInfo(name, receiverType, returnTypeInfo, varExpected, possibleContainers, isLateinitPreferred = canBeLateinit)
}
object Default : Property() {
override fun doCreateCallableInfo(
expression: KtSimpleNameExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
): CallableInfo? {
return super.doCreateCallableInfo(
expression,
analysisResult,
name,
receiverType,
possibleContainers.filterNot { it is KtClassBody && (it.parent as KtClassOrObject).isInterfaceClass() }
)
}
}
object Abstract : Property() {
override fun doCreateCallableInfo(
expression: KtSimpleNameExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
) = super.doCreateCallableInfo(expression, analysisResult, name, receiverType, possibleContainers)?.let {
getAbstractCallableInfo(it, expression)
}
}
object ByImplicitExtensionReceiver : Property() {
override fun doCreateCallableInfo(
expression: KtSimpleNameExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
) = super.doCreateCallableInfo(expression, analysisResult, name, receiverType, possibleContainers)?.let {
ByImplicitExtensionReceiver.getCallableWithReceiverInsideExtension(it, expression, analysisResult.bindingContext, receiverType)
}
}
}
sealed class Function: CreateCallableFromCallActionFactory<KtCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtCallExpression? {
return getExpressionOfInterest(diagnostic) as? KtCallExpression
}
override fun doCreateCallableInfo(
expression: KtCallExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
): CallableInfo? {
val parameters = expression.getParameterInfos()
val typeParameters = expression.getTypeInfoForTypeArguments()
val fullCallExpression = expression.getQualifiedExpressionForSelectorOrThis()
val expectedType = fullCallExpression.guessTypes(analysisResult.bindingContext, analysisResult.moduleDescriptor).singleOrNull()
val returnType = if (expectedType != null) {
TypeInfo(expectedType, Variance.OUT_VARIANCE)
} else {
TypeInfo(fullCallExpression, Variance.OUT_VARIANCE)
}
return FunctionInfo(name, receiverType, returnType, possibleContainers, parameters, typeParameters)
}
object Default : Function()
object Abstract : Function() {
override fun doCreateCallableInfo(
expression: KtCallExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
) = super.doCreateCallableInfo(expression, analysisResult, name, receiverType, possibleContainers)?.let {
getAbstractCallableInfo(it, expression)
}
}
object ByImplicitExtensionReceiver : Function() {
override fun doCreateCallableInfo(
expression: KtCallExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
) = super.doCreateCallableInfo(expression, analysisResult, name, receiverType, possibleContainers)?.let {
getCallableWithReceiverInsideExtension(it, expression, analysisResult.bindingContext, receiverType)
}
}
}
object Constructor: CreateCallableFromCallActionFactory<KtCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtCallExpression? {
return getExpressionOfInterest(diagnostic) as? KtCallExpression
}
override fun doCreateCallableInfo(
expression: KtCallExpression,
analysisResult: AnalysisResult,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
): CallableInfo? {
if (expression.typeArguments.isNotEmpty()) return null
val classDescriptor = expression
.calleeExpression
?.getReferenceTargets(analysisResult.bindingContext)
?.mapNotNull { (it as? ConstructorDescriptor)?.containingDeclaration }
?.distinct()
?.singleOrNull() as? ClassDescriptor
val klass = classDescriptor?.source?.getPsi()
if ((klass !is KtClass && klass !is PsiClass) || !klass.canRefactor()) return null
val expectedType = analysisResult.bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expression.getQualifiedExpressionForSelectorOrThis()]
?: classDescriptor.builtIns.nullableAnyType
if (!classDescriptor.defaultType.isSubtypeOf(expectedType)) return null
val parameters = expression.getParameterInfos()
return ConstructorInfo(parameters, klass)
}
}
companion object {
val FUNCTIONS = arrayOf(Function.Default,
Function.Abstract,
Function.ByImplicitExtensionReceiver,
Constructor)
val INSTANCES = arrayOf(Function.Default,
Function.Abstract,
Function.ByImplicitExtensionReceiver,
Constructor,
Property.Default,
Property.Abstract,
Property.ByImplicitExtensionReceiver)
}
}
@@ -0,0 +1,57 @@
/*
* 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 org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
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.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.types.Variance
object CreateComponentFunctionActionFactory : CreateCallableMemberFromUsageFactory<KtDestructuringDeclaration>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtDestructuringDeclaration? {
QuickFixUtil.getParentElementOfType(diagnostic, KtDestructuringDeclaration::class.java)?.let { return it }
return QuickFixUtil.getParentElementOfType(diagnostic, KtForExpression::class.java)?.destructuringDeclaration
}
override fun createCallableInfo(element: KtDestructuringDeclaration, diagnostic: Diagnostic): CallableInfo? {
val diagnosticWithParameters = Errors.COMPONENT_FUNCTION_MISSING.cast(diagnostic)
val name = diagnosticWithParameters.a
if (!DataClassDescriptorResolver.isComponentLike(name)) return null
val componentNumber = DataClassDescriptorResolver.getComponentIndex(name.asString()) - 1
val targetType = diagnosticWithParameters.b
val targetClassDescriptor = targetType.constructor.declarationDescriptor as? ClassDescriptor
if (targetClassDescriptor != null && targetClassDescriptor.isData) return null
val ownerTypeInfo = TypeInfo(targetType, Variance.IN_VARIANCE)
val entries = element.entries
val entry = entries[componentNumber]
val returnTypeInfo = TypeInfo(entry, Variance.OUT_VARIANCE)
return FunctionInfo(name.identifier, ownerTypeInfo, returnTypeInfo, isOperator = true)
}
}
@@ -0,0 +1,40 @@
/*
* 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 org.jetbrains.kotlin.diagnostics.Diagnostic
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.KtArrayAccessExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
object CreateGetFunctionActionFactory : CreateGetSetFunctionActionFactory(isGet = true) {
override fun createCallableInfo(element: KtArrayAccessExpression, diagnostic: Diagnostic): CallableInfo? {
val arrayExpr = element.arrayExpression ?: return null
val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE)
val parameters = element.indexExpressions.map { ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE)) }
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
return FunctionInfo(
OperatorNameConventions.GET.asString(), arrayType, returnType, Collections.emptyList(), parameters, isOperator = true
)
}
}
@@ -0,0 +1,43 @@
/*
* 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 org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.project.builtIns
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.KtForExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
object CreateHasNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<KtForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtForExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, KtForExpression::class.java)
}
override fun createCallableInfo(element: KtForExpression, 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(element.builtIns.booleanType, Variance.OUT_VARIANCE)
return FunctionInfo(OperatorNameConventions.HAS_NEXT.asString(), ownerType, returnType, isOperator = true)
}
}
@@ -0,0 +1,53 @@
/*
* 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 org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.project.builtIns
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.KtCallExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.util.OperatorNameConventions
object CreateInvokeFunctionActionFactory : CreateCallableMemberFromUsageFactory<KtCallExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtCallExpression? {
return diagnostic.psiElement.parent as? KtCallExpression
}
override fun createCallableInfo(element: KtCallExpression, 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 = element.builtIns.nullableAnyType
val parameters = element.valueArguments.map {
ParameterInfo(
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
it.getArgumentName()?.referenceExpression?.getReferencedName()
)
}
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
return FunctionInfo(OperatorNameConventions.INVOKE.asString(), receiverType, returnType, parameterInfos = parameters, isOperator = true)
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2016 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 org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
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.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactory<KtForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtForExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, KtForExpression::class.java)
}
override fun createCallableInfo(element: KtForExpression, diagnostic: Diagnostic): CallableInfo? {
val file = diagnostic.psiFile as? KtFile ?: return null
val iterableExpr = element.loopRange ?: return null
val variableExpr: KtExpression = ((element.loopParameter ?: element.destructuringDeclaration) ?: return null) as KtExpression
val iterableType = TypeInfo(iterableExpr, Variance.IN_VARIANCE)
val (bindingContext, moduleDescriptor) = file.analyzeWithAllCompilerChecks()
val returnJetType = moduleDescriptor.builtIns.iterator.defaultType
val returnJetTypeParameterTypes = variableExpr.guessTypes(bindingContext, moduleDescriptor)
if (returnJetTypeParameterTypes.size != 1) return null
val returnJetTypeParameterType = TypeProjectionImpl(returnJetTypeParameterTypes[0])
val returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType)
val newReturnJetType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(returnJetType.annotations,
returnJetType.constructor,
returnJetTypeArguments,
returnJetType.isMarkedNullable,
returnJetType.memberScope)
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
return FunctionInfo(OperatorNameConventions.ITERATOR.asString(), iterableType, returnType, isOperator = true)
}
}
@@ -0,0 +1,44 @@
/*
* 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 org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
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.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
object CreateNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<KtForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtForExpression? {
return QuickFixUtil.getParentElementOfType(diagnostic, KtForExpression::class.java)
}
override fun createCallableInfo(element: KtForExpression, diagnostic: Diagnostic): CallableInfo? {
val diagnosticWithParameters = DiagnosticFactory.cast(diagnostic, Errors.NEXT_MISSING, Errors.NEXT_NONE_APPLICABLE)
val ownerType = TypeInfo(diagnosticWithParameters.a, Variance.IN_VARIANCE)
val variableExpr = element.loopParameter ?: element.destructuringDeclaration ?: return null
val returnType = TypeInfo(variableExpr as KtExpression, Variance.OUT_VARIANCE)
return FunctionInfo(OperatorNameConventions.NEXT.asString(), ownerType, returnType, isOperator = true)
}
}
@@ -0,0 +1,97 @@
/*
* 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.util.SmartList
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.VariableAccessorDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.project.languageVersionSettings
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.KtExpression
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
object CreatePropertyDelegateAccessorsActionFactory : CreateCallableMemberFromUsageFactory<KtExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtExpression? {
return diagnostic.psiElement as? KtExpression
}
override fun extractFixData(element: KtExpression, diagnostic: Diagnostic): List<CallableInfo> {
val context = element.analyze()
fun isApplicableForAccessor(accessor: VariableAccessorDescriptor?): Boolean =
accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null
val property = element.getNonStrictParentOfType<KtProperty>() ?: return emptyList()
val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptorWithAccessors
?: return emptyList()
if (propertyDescriptor is LocalVariableDescriptor
&& !element.languageVersionSettings.supportsFeature(LanguageFeature.LocalDelegatedProperties)) {
return emptyList()
}
val propertyReceiver = propertyDescriptor.extensionReceiverParameter ?: propertyDescriptor.dispatchReceiverParameter
val propertyType = propertyDescriptor.type
val accessorReceiverType = TypeInfo(element, Variance.IN_VARIANCE)
val builtIns = propertyDescriptor.builtIns
val thisRefParam = ParameterInfo(TypeInfo(propertyReceiver?.type ?: builtIns.nullableNothingType, Variance.IN_VARIANCE))
val kPropertyStarType = ReflectionTypes.createKPropertyStarType(propertyDescriptor.module) ?: return emptyList()
val metadataParam = ParameterInfo(TypeInfo(kPropertyStarType, Variance.IN_VARIANCE), "property")
val callableInfos = SmartList<CallableInfo>()
if (isApplicableForAccessor(propertyDescriptor.getter)) {
val getterInfo = FunctionInfo(
name = OperatorNameConventions.GET_VALUE.asString(),
receiverTypeInfo = accessorReceiverType,
returnTypeInfo = TypeInfo(propertyType, Variance.OUT_VARIANCE),
parameterInfos = listOf(thisRefParam, metadataParam),
isOperator = true
)
callableInfos.add(getterInfo)
}
if (propertyDescriptor.isVar && isApplicableForAccessor(propertyDescriptor.setter)) {
val newValueParam = ParameterInfo(TypeInfo(propertyType, Variance.IN_VARIANCE))
val setterInfo = FunctionInfo(
name = OperatorNameConventions.SET_VALUE.asString(),
receiverTypeInfo = accessorReceiverType,
returnTypeInfo = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE),
parameterInfos = listOf(thisRefParam, metadataParam, newValueParam),
isOperator = true
)
callableInfos.add(setterInfo)
}
return callableInfos
}
}
@@ -0,0 +1,64 @@
/*
* 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 org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.project.builtIns
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.*
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
object CreateSetFunctionActionFactory : CreateGetSetFunctionActionFactory(isGet = false) {
override fun createCallableInfo(element: KtArrayAccessExpression, diagnostic: Diagnostic): CallableInfo? {
val arrayExpr = element.arrayExpression ?: return null
val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE)
val builtIns = element.builtIns
val parameters = element.indexExpressions.mapTo(ArrayList<ParameterInfo>()) {
ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE))
}
val assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, KtOperationExpression::class.java) ?: return null
val valType = when (assignmentExpr) {
is KtBinaryExpression -> {
TypeInfo(assignmentExpr.right ?: return null, Variance.IN_VARIANCE)
}
is KtUnaryExpression -> {
if (assignmentExpr.operationToken !in OperatorConventions.INCREMENT_OPERATIONS) return null
val rhsType = assignmentExpr.resolveToCall()?.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.unitType, Variance.OUT_VARIANCE)
return FunctionInfo(
OperatorNameConventions.SET.asString(), arrayType, returnType, Collections.emptyList(), parameters, isOperator = true
)
}
}
@@ -0,0 +1,44 @@
/*
* 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 org.jetbrains.kotlin.diagnostics.Diagnostic
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.KtToken
import org.jetbrains.kotlin.psi.KtUnaryExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
object CreateUnaryOperationActionFactory: CreateCallableMemberFromUsageFactory<KtUnaryExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtUnaryExpression? {
return diagnostic.psiElement.parent as? KtUnaryExpression
}
override fun createCallableInfo(element: KtUnaryExpression, diagnostic: Diagnostic): CallableInfo? {
val token = element.operationToken as KtToken
val operationName = OperatorConventions.getNameForOperationSymbol(token, true, false) ?: return null
val incDec = token in OperatorConventions.INCREMENT_OPERATIONS
val receiverExpr = element.baseExpression ?: return null
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(element, Variance.OUT_VARIANCE)
return FunctionInfo(operationName.asString(), receiverType, returnType, isOperator = true)
}
}
@@ -0,0 +1,390 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.lang.jvm.*
import com.intellij.lang.jvm.actions.*
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.appendModifier
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateCallableFromUsageFix
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.approximateFlexibleTypes
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
import org.jetbrains.kotlin.load.java.lazy.child
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeAttributes
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.annotations.JVM_FIELD_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.supertypes
class KotlinElementActionsFactory : JvmElementActionsFactory() {
companion object {
val javaPsiModifiersMapping = mapOf(
JvmModifier.PRIVATE to KtTokens.PRIVATE_KEYWORD,
JvmModifier.PUBLIC to KtTokens.PUBLIC_KEYWORD,
JvmModifier.PROTECTED to KtTokens.PUBLIC_KEYWORD,
JvmModifier.ABSTRACT to KtTokens.ABSTRACT_KEYWORD
)
}
private class FakeExpressionFromParameter(private val psiParam: PsiParameter) : PsiReferenceExpressionImpl() {
override fun getText(): String = psiParam.name!!
override fun getProject(): Project = psiParam.project
override fun getParent(): PsiElement = psiParam.parent
override fun getType(): PsiType? = psiParam.type
override fun isValid(): Boolean = true
override fun getContainingFile(): PsiFile = psiParam.containingFile
override fun getReferenceName(): String? = psiParam.name
override fun resolve(): PsiElement? = psiParam
}
private class ModifierBuilder(
private val targetContainer: KtElement,
private val allowJvmStatic: Boolean = true
) {
private val psiFactory = KtPsiFactory(targetContainer.project)
val modifierList = psiFactory.createEmptyModifierList()
private fun JvmModifier.transformAndAppend(): Boolean {
javaPsiModifiersMapping[this]?.let {
modifierList.appendModifier(it)
return true
}
when (this) {
JvmModifier.STATIC -> {
if (allowJvmStatic && targetContainer is KtClassOrObject) {
addAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME)
}
}
JvmModifier.ABSTRACT -> modifierList.appendModifier(KtTokens.ABSTRACT_KEYWORD)
JvmModifier.FINAL -> modifierList.appendModifier(KtTokens.FINAL_KEYWORD)
else -> return false
}
return true
}
var isValid = true
private set
fun addJvmModifier(modifier: JvmModifier) {
isValid = isValid && modifier.transformAndAppend()
}
fun addJvmModifiers(modifiers: Iterable<JvmModifier>) {
modifiers.forEach { addJvmModifier(it) }
}
fun addAnnotation(fqName: FqName) {
if (!isValid) return
modifierList.add(psiFactory.createAnnotationEntry("@${fqName.asString()}"))
}
}
class CreatePropertyFix(
private val targetClass: JvmClass,
contextElement: KtElement,
propertyInfo: PropertyInfo
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
override fun getFamilyName() = "Add property"
override fun getText(): String {
val info = callableInfos.first() as PropertyInfo
return buildString {
append("Add '")
if (info.isLateinitPreferred) {
append("lateinit ")
}
append(if (info.writable) "var" else "val")
append("' property '${info.name}' to '${targetClass.name}'")
}
}
}
private fun JvmClass.toKtClassOrFile(): KtElement? {
val psi = sourceElement
return when (psi) {
is KtClassOrObject -> psi
is KtLightClassForSourceDeclaration -> psi.kotlinOrigin
is KtLightClassForFacade -> psi.files.firstOrNull()
else -> null
}
}
private inline fun <reified T : KtElement> JvmElement.toKtElement() = sourceElement?.unwrapped as? T
private fun fakeParametersExpressions(parameters: List<JvmParameter>, project: Project): Array<PsiExpression>? =
when {
parameters.isEmpty() -> emptyArray()
else -> JavaPsiFacade
.getElementFactory(project)
.createParameterList(
parameters.map { it.name }.toTypedArray(),
parameters.map { it.type as? PsiType ?: return null }.toTypedArray()
)
.parameters
.map(::FakeExpressionFromParameter)
.toTypedArray()
}
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
val results = ArrayList<PsiTypeParameter>()
accept(
object : PsiTypeVisitor<Unit>() {
override fun visitArrayType(arrayType: PsiArrayType) {
arrayType.componentType.accept(this)
}
override fun visitClassType(classType: PsiClassType) {
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
classType.parameters.forEach { it.accept(this) }
}
override fun visitWildcardType(wildcardType: PsiWildcardType) {
wildcardType.bound?.accept(this)
}
}
)
return results
}
private fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
val typeParameters = collectTypeParameters()
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
val dummyClassDescriptor = ClassDescriptorImpl(
dummyPackageDescriptor,
Name.identifier("Dummy"),
Modality.FINAL,
ClassKind.CLASS,
emptyList(),
SourceElement.NO_SOURCE,
false
)
val typeParameterResolver = object : TypeParameterResolver {
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
val index = typeParameters.indexOf(psiTypeParameter)
if (index < 0) return null
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
}
}
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
}
private fun ExpectedTypes.toKotlinTypeInfo(resolutionFacade: ResolutionFacade): TypeInfo {
val candidateTypes = flatMapTo(LinkedHashSet<KotlinType>()) {
val ktType = (it.theType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: return@flatMapTo emptyList()
when (it.theKind) {
ExpectedType.Kind.EXACT, ExpectedType.Kind.SUBTYPE -> listOf(ktType)
ExpectedType.Kind.SUPERTYPE -> listOf(ktType) + ktType.supertypes()
}
}
if (candidateTypes.isEmpty()) {
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
return TypeInfo(nullableAnyType, Variance.INVARIANT)
}
return TypeInfo.ByExplicitCandidateTypes(candidateTypes.toList())
}
override fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List<IntentionAction> {
val kModifierOwner = target.toKtElement<KtModifierListOwner>() ?: return emptyList()
val modifier = request.modifier
val shouldPresent = request.shouldPresent
val (kToken, shouldPresentMapped) = if (JvmModifier.FINAL == modifier)
KtTokens.OPEN_KEYWORD to !shouldPresent
else
javaPsiModifiersMapping[modifier] to shouldPresent
if (kToken == null) return emptyList()
val action = if (shouldPresentMapped)
AddModifierFix.createIfApplicable(kModifierOwner, kToken)
else
RemoveModifierFix(kModifierOwner, kToken, false)
return listOfNotNull(action)
}
override fun createAddConstructorActions(targetClass: JvmClass, request: MemberRequest.Constructor): List<IntentionAction> {
val targetKtClass = targetClass.toKtClassOrFile() as? KtClass ?: return emptyList()
if (request.typeParameters.isNotEmpty()) return emptyList()
val modifierBuilder = ModifierBuilder(targetKtClass).apply { addJvmModifiers(request.modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetKtClass.getResolutionFacade()
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
val parameterInfos = request.parameters.mapIndexed { index, param ->
val ktType = (param.type as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val name = param.name ?: "arg${index + 1}"
ParameterInfo(TypeInfo(ktType, Variance.IN_VARIANCE), listOf(name))
}
val needPrimary = !targetKtClass.hasExplicitPrimaryConstructor()
val constructorInfo = ConstructorInfo(
parameterInfos,
targetKtClass,
isPrimary = needPrimary,
modifierList = modifierBuilder.modifierList,
withBody = true
)
val addConstructorAction = object : CreateCallableFromUsageFix<KtElement>(targetKtClass, listOf(constructorInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add ${if (needPrimary) "primary" else "secondary"} constructor to '${targetClass.name}'"
}
val changePrimaryConstructorAction = run {
val primaryConstructor = targetKtClass.primaryConstructor ?: return@run null
val lightMethod = primaryConstructor.toLightMethods().firstOrNull() ?: return@run null
val project = targetKtClass.project
val fakeParametersExpressions = fakeParametersExpressions(request.parameters, project) ?: return@run null
QuickFixFactory.getInstance()
.createChangeMethodSignatureFromUsageFix(
lightMethod,
fakeParametersExpressions,
PsiSubstitutor.EMPTY,
targetKtClass,
false,
2
).takeIf { it.isAvailable(project, null, targetKtClass.containingFile) }
}
return listOfNotNull(changePrimaryConstructorAction, addConstructorAction)
}
override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifier(request.visibilityModifier) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
val ktType = (request.propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
val propertyInfo = PropertyInfo(
request.propertyName,
TypeInfo.Empty,
TypeInfo(ktType, Variance.INVARIANT),
request.setterRequired,
listOf(targetContainer),
modifierList = modifierBuilder.modifierList,
withInitializer = true
)
val propertyInfos = if (request.setterRequired) {
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
}
else {
listOf(propertyInfo)
}
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
}
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer, allowJvmStatic = false).apply {
addJvmModifiers(request.modifiers)
addAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME)
}
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val typeInfo = request.fieldType.toKotlinTypeInfo(resolutionFacade)
val writable = JvmModifier.FINAL !in request.modifiers
val propertyInfo = PropertyInfo(
request.fieldName,
TypeInfo.Empty,
typeInfo,
writable,
listOf(targetContainer),
isForCompanion = JvmModifier.STATIC in request.modifiers,
modifierList = modifierBuilder.modifierList,
withInitializer = true
)
val propertyInfos = if (writable) {
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
}
else {
listOf(propertyInfo)
}
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
}
override fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> {
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(request.modifiers) }
if (!modifierBuilder.isValid) return emptyList()
val resolutionFacade = targetContainer.getResolutionFacade()
val returnTypeInfo = request.returnType.toKotlinTypeInfo(resolutionFacade)
val parameterInfos = request.parameters.map { (suggestedNames, expectedTypes) ->
ParameterInfo(expectedTypes.toKotlinTypeInfo(resolutionFacade), suggestedNames.names.toList())
}
val functionInfo = FunctionInfo(
request.methodName,
TypeInfo.Empty,
returnTypeInfo,
listOf(targetContainer),
parameterInfos,
isAbstract = JvmModifier.ABSTRACT in request.modifiers,
isForCompanion = JvmModifier.STATIC in request.modifiers,
modifierList = modifierBuilder.modifierList,
preferEmptyBody = true
)
val action = object : CreateCallableFromUsageFix<KtElement>(targetContainer, listOf(functionInfo)) {
override fun getFamilyName() = "Add method"
override fun getText() = "Add method '${request.methodName}' to '${targetClass.name}'"
}
return listOf(action)
}
}