Create from usage: Use type predicates provided by control-flow analysis to suggest more precise types
#KT-7742 Fixed
This commit is contained in:
+4
@@ -35,6 +35,8 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.getContainingPseudocode
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||
@@ -131,6 +133,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
val currentFileContext: BindingContext
|
||||
val currentFileModule: ModuleDescriptor
|
||||
|
||||
val pseudocode: Pseudocode? by Delegates.lazy { config.originalElement.getContainingPseudocode(currentFileContext) }
|
||||
|
||||
private val typeCandidates = HashMap<TypeInfo, List<TypeCandidate>>()
|
||||
|
||||
init {
|
||||
|
||||
+5
-1
@@ -48,7 +48,11 @@ abstract class TypeInfo(val variance: Variance) {
|
||||
}
|
||||
|
||||
override fun getPossibleTypes(builder: CallableBuilder): List<JetType> =
|
||||
expression.guessTypes(builder.currentFileContext, builder.currentFileModule).flatMap { it.getPossibleSupertypes(variance) }
|
||||
expression.guessTypes(
|
||||
context = builder.currentFileContext,
|
||||
module = builder.currentFileModule,
|
||||
pseudocode = builder.pseudocode
|
||||
).flatMap { it.getPossibleSupertypes(variance) }
|
||||
}
|
||||
|
||||
class ByTypeReference(val typeReference: JetTypeReference, variance: Variance): TypeInfo(variance) {
|
||||
|
||||
+23
-7
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
|
||||
|
||||
import com.intellij.refactoring.psi.SearchUtils
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
@@ -36,8 +37,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import java.util.HashSet
|
||||
import java.util.LinkedHashSet
|
||||
import java.util.*
|
||||
|
||||
private fun JetType.contains(inner: JetType): Boolean {
|
||||
return JetTypeChecker.DEFAULT.equalTypes(this, inner) || getArguments().any { inner in it.getType() }
|
||||
@@ -90,9 +90,9 @@ fun JetType.getTypeParameters(): Set<TypeParameterDescriptor> {
|
||||
fun JetExpression.guessTypes(
|
||||
context: BindingContext,
|
||||
module: ModuleDescriptor,
|
||||
pseudocode: Pseudocode? = null,
|
||||
coerceUnusedToUnit: Boolean = true
|
||||
): Array<JetType> {
|
||||
|
||||
if (coerceUnusedToUnit
|
||||
&& this !is JetDeclaration
|
||||
&& isUsedAsStatement(context)
|
||||
@@ -108,9 +108,7 @@ fun JetExpression.guessTypes(
|
||||
|
||||
// expression has an expected type
|
||||
val theType2 = context[BindingContext.EXPECTED_EXPRESSION_TYPE, this]
|
||||
if (theType2 != null) {
|
||||
return array(theType2)
|
||||
}
|
||||
if (theType2 != null) return arrayOf(theType2)
|
||||
|
||||
val parent = getParent()
|
||||
return when {
|
||||
@@ -174,7 +172,11 @@ fun JetExpression.guessTypes(
|
||||
parent is JetStringTemplateEntryWithExpression && parent.getExpression() == this -> {
|
||||
array(module.builtIns.getStringType())
|
||||
}
|
||||
else -> array() // can't infer anything
|
||||
else -> {
|
||||
pseudocode?.getElementValue(this)?.let {
|
||||
getExpectedTypePredicate(it, context).getRepresentativeTypes().toTypedArray()
|
||||
} ?: arrayOf() // can't infer anything
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,4 +232,18 @@ fun JetExpression.getExpressionForTypeGuess() = getAssignmentByLHS()?.getRight()
|
||||
|
||||
fun JetCallElement.getTypeInfoForTypeArguments(): List<TypeInfo> {
|
||||
return getTypeArguments().map { it.getTypeReference()?.let { TypeInfo(it, Variance.INVARIANT) } }.filterNotNull()
|
||||
}
|
||||
|
||||
private fun TypePredicate.getRepresentativeTypes(): Set<JetType> {
|
||||
return when (this) {
|
||||
is SingleType -> Collections.singleton(targetType)
|
||||
is AllSubtypes -> Collections.singleton(upperBound)
|
||||
is ForAllTypes -> {
|
||||
if (typeSets.isEmpty()) AllTypes.getRepresentativeTypes()
|
||||
else typeSets.map { it.getRepresentativeTypes() }.reduce { a, b -> a intersect b }
|
||||
}
|
||||
is ForSomeType -> typeSets.flatMapTo(LinkedHashSet<JetType>()) { it.getRepresentativeTypes() }
|
||||
is AllTypes -> emptySet()
|
||||
else -> throw AssertionError("Invalid type predicate: ${this}")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -91,8 +91,8 @@ private fun JetExpression.getInheritableTypeInfo(
|
||||
context: BindingContext,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
containingDeclaration: PsiElement): Pair<TypeInfo, (ClassKind) -> Boolean> {
|
||||
val types = guessTypes(context, moduleDescriptor, false)
|
||||
if (types.size != 1) return TypeInfo.Empty to { classKind -> true }
|
||||
val types = guessTypes(context, moduleDescriptor, coerceUnusedToUnit = false)
|
||||
if (types.size() != 1) return TypeInfo.Empty to { classKind -> true }
|
||||
|
||||
val type = types.first()
|
||||
val descriptor = type.getConstructor().getDeclarationDescriptor()
|
||||
|
||||
Reference in New Issue
Block a user