New J2K: implement mutability inference in post-processing
#KT-24293 fixed #KT-19603 fixed
This commit is contained in:
@@ -143,6 +143,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
|
|||||||
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.mutability.AbstractMutabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
||||||
@@ -1062,6 +1063,9 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractNullabilityInferenceTest> {
|
testClass<AbstractNullabilityInferenceTest> {
|
||||||
model("inference/nullability")
|
model("inference/nullability")
|
||||||
}
|
}
|
||||||
|
testClass<AbstractMutabilityInferenceTest> {
|
||||||
|
model("inference/mutability")
|
||||||
|
}
|
||||||
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
||||||
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
|
|||||||
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.mutability.AbstractMutabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
||||||
@@ -1005,6 +1006,9 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractNullabilityInferenceTest> {
|
testClass<AbstractNullabilityInferenceTest> {
|
||||||
model("inference/nullability")
|
model("inference/nullability")
|
||||||
}
|
}
|
||||||
|
testClass<AbstractMutabilityInferenceTest> {
|
||||||
|
model("inference/mutability")
|
||||||
|
}
|
||||||
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
||||||
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
|
|||||||
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.mutability.AbstractMutabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
||||||
@@ -969,6 +970,9 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractNullabilityInferenceTest> {
|
testClass<AbstractNullabilityInferenceTest> {
|
||||||
model("inference/nullability")
|
model("inference/nullability")
|
||||||
}
|
}
|
||||||
|
testClass<AbstractMutabilityInferenceTest> {
|
||||||
|
model("inference/mutability")
|
||||||
|
}
|
||||||
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
||||||
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
|
|||||||
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.mutability.AbstractMutabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
||||||
@@ -965,6 +966,9 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractNullabilityInferenceTest> {
|
testClass<AbstractNullabilityInferenceTest> {
|
||||||
model("inference/nullability")
|
model("inference/nullability")
|
||||||
}
|
}
|
||||||
|
testClass<AbstractMutabilityInferenceTest> {
|
||||||
|
model("inference/mutability")
|
||||||
|
}
|
||||||
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
||||||
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest
|
|||||||
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.mutability.AbstractMutabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg
|
||||||
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg
|
||||||
@@ -965,6 +966,9 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractNullabilityInferenceTest> {
|
testClass<AbstractNullabilityInferenceTest> {
|
||||||
model("inference/nullability")
|
model("inference/nullability")
|
||||||
}
|
}
|
||||||
|
testClass<AbstractMutabilityInferenceTest> {
|
||||||
|
model("inference/mutability")
|
||||||
|
}
|
||||||
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
testClass<AbstractNewJavaToKotlinCopyPasteConversionTest> {
|
||||||
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
model("copyPaste", pattern = """^([^\.]+)\.java$""")
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -88,9 +88,7 @@ open class BoundTypeCalculatorImpl(
|
|||||||
valueParameters.map { parameter ->
|
valueParameters.map { parameter ->
|
||||||
parameter.typeReference?.typeElement?.let { typeElement ->
|
parameter.typeReference?.typeElement?.let { typeElement ->
|
||||||
inferenceContext.typeElementToTypeVariable[typeElement]
|
inferenceContext.typeElementToTypeVariable[typeElement]
|
||||||
}?.let { typeVariable ->
|
}?.asBoundType() ?: return null
|
||||||
typeVariable.asBoundType()
|
|
||||||
} ?: return null
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
descriptor.valueParameters.map { parameter ->
|
descriptor.valueParameters.map { parameter ->
|
||||||
@@ -220,7 +218,12 @@ open class BoundTypeCalculatorImpl(
|
|||||||
)
|
)
|
||||||
|
|
||||||
is TypeParameterDescriptor -> {
|
is TypeParameterDescriptor -> {
|
||||||
val containingDeclaration = target.containingDeclaration
|
val containingDeclaration = target.containingDeclaration.let { container ->
|
||||||
|
when (container) {
|
||||||
|
is TypeAliasDescriptor -> container.classDescriptor
|
||||||
|
else -> container
|
||||||
|
} ?: container
|
||||||
|
}
|
||||||
when {
|
when {
|
||||||
containingDeclaration == call?.candidateDescriptor?.original -> {
|
containingDeclaration == call?.candidateDescriptor?.original -> {
|
||||||
val returnTypeVariable = inferenceContext.typeElementToTypeVariable[
|
val returnTypeVariable = inferenceContext.typeElementToTypeVariable[
|
||||||
@@ -240,7 +243,7 @@ open class BoundTypeCalculatorImpl(
|
|||||||
contextBoundType?.isReferenceToClass == true ->
|
contextBoundType?.isReferenceToClass == true ->
|
||||||
contextBoundType.typeParameters.getOrNull(target.index)?.boundType
|
contextBoundType.typeParameters.getOrNull(target.index)?.boundType
|
||||||
|
|
||||||
// `this` or `super` call case
|
// `this`, `super`, or constructor call cases
|
||||||
containingDeclaration == call?.candidateDescriptor.safeAs<ConstructorDescriptor>()?.constructedClass -> {
|
containingDeclaration == call?.candidateDescriptor.safeAs<ConstructorDescriptor>()?.constructedClass -> {
|
||||||
val returnTypeVariable = inferenceContext.typeElementToTypeVariable[
|
val returnTypeVariable = inferenceContext.typeElementToTypeVariable[
|
||||||
call?.call?.typeArguments?.getOrNull(target.index)?.typeReference?.typeElement
|
call?.call?.typeArguments?.getOrNull(target.index)?.typeReference?.typeElement
|
||||||
|
|||||||
@@ -54,8 +54,15 @@ class LiteralBound private constructor(val state: State) : ConstraintBound() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun State.constraintBound(): LiteralBound = when (this) {
|
fun State.constraintBound(): LiteralBound? = when (this) {
|
||||||
State.LOWER -> LiteralBound.LOWER
|
State.LOWER -> LiteralBound.LOWER
|
||||||
State.UPPER -> LiteralBound.UPPER
|
State.UPPER -> LiteralBound.UPPER
|
||||||
State.UNKNOWN -> LiteralBound.UNKNOWN
|
State.UNKNOWN -> LiteralBound.UNKNOWN
|
||||||
|
State.UNUSED -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ConstraintBound.isUnused
|
||||||
|
get() = when (this) {
|
||||||
|
is TypeVariableBound -> typeVariable.state == State.UNUSED
|
||||||
|
is LiteralBound -> state == State.UNUSED
|
||||||
|
}
|
||||||
|
|||||||
+5
-1
@@ -40,7 +40,11 @@ class ConstraintBuilder(
|
|||||||
|
|
||||||
fun KtExpression.isTheSameTypeAs(other: State, priority: ConstraintPriority) {
|
fun KtExpression.isTheSameTypeAs(other: State, priority: ConstraintPriority) {
|
||||||
boundType().label.safeAs<TypeVariableLabel>()?.typeVariable?.let { typeVariable ->
|
boundType().label.safeAs<TypeVariableLabel>()?.typeVariable?.let { typeVariable ->
|
||||||
constraints += EqualsConstraint(typeVariable.constraintBound(), other.constraintBound(), priority)
|
constraints += EqualsConstraint(
|
||||||
|
typeVariable.constraintBound(),
|
||||||
|
other.constraintBound() ?: return@let,
|
||||||
|
priority
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-40
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) {
|
abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) {
|
||||||
@@ -48,11 +47,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
|
|||||||
val typeElement = typeElement ?: return null
|
val typeElement = typeElement ?: return null
|
||||||
val classReference = classReference() ?: NoClassReference
|
val classReference = classReference() ?: NoClassReference
|
||||||
|
|
||||||
val state = when {
|
val state = defaultState ?: classReference.getState(typeElement)
|
||||||
classReference.descriptor?.defaultType?.isUnit() == true -> State.LOWER
|
|
||||||
defaultState != null -> defaultState
|
|
||||||
else -> classReference.getState(typeElement)
|
|
||||||
}
|
|
||||||
val typeArguments =
|
val typeArguments =
|
||||||
if (classReference is DescriptorClassReference) {
|
if (classReference is DescriptorClassReference) {
|
||||||
typeElement.typeArgumentsAsTypes.zip(
|
typeElement.typeArgumentsAsTypes.zip(
|
||||||
@@ -65,22 +60,15 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
|
|||||||
}
|
}
|
||||||
} else emptyList()
|
} else emptyList()
|
||||||
|
|
||||||
return if (state == null) {
|
val typeVariable = TypeElementBasedTypeVariable(
|
||||||
BoundTypeImpl(
|
classReference,
|
||||||
GenericLabel(classReference),
|
typeArguments,
|
||||||
typeArguments
|
typeElement.toData() ?: return null,
|
||||||
)
|
owner,
|
||||||
} else {
|
state
|
||||||
val typeVariable = TypeElementBasedTypeVariable(
|
)
|
||||||
classReference,
|
typeElementToTypeVariable[typeElement] = typeVariable
|
||||||
typeArguments,
|
return typeVariable.asBoundType()
|
||||||
typeElement.toData() ?: return null,
|
|
||||||
owner,
|
|
||||||
state
|
|
||||||
)
|
|
||||||
typeElementToTypeVariable[typeElement] = typeVariable
|
|
||||||
typeVariable.asBoundType()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinType.toBoundType(): BoundType? {
|
fun KotlinType.toBoundType(): BoundType? {
|
||||||
@@ -97,24 +85,18 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
|
|||||||
}
|
}
|
||||||
} else emptyList()
|
} else emptyList()
|
||||||
|
|
||||||
return if (state == null) {
|
|
||||||
BoundTypeImpl(
|
val typeVariable = TypeBasedTypeVariable(
|
||||||
GenericLabel(classReference),
|
classReference,
|
||||||
typeArguments
|
typeArguments,
|
||||||
)
|
this,
|
||||||
} else {
|
state
|
||||||
val typeVariable = TypeBasedTypeVariable(
|
)
|
||||||
classReference,
|
typeBasedTypeVariables += typeVariable
|
||||||
typeArguments,
|
return typeVariable.asBoundType()
|
||||||
this,
|
|
||||||
state
|
|
||||||
)
|
|
||||||
typeBasedTypeVariables += typeVariable
|
|
||||||
typeVariable.asBoundType()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val substitutors = mutableMapOf<ClassDescriptor, ClassSubstitutor>()
|
val substitutors = mutableMapOf<ClassDescriptor, SuperTypesSubstitutor>()
|
||||||
|
|
||||||
fun isOrAsExpression(typeReference: KtTypeReference) {
|
fun isOrAsExpression(typeReference: KtTypeReference) {
|
||||||
val typeElement = typeReference.typeElement ?: return
|
val typeElement = typeReference.typeElement ?: return
|
||||||
@@ -160,7 +142,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
|
|||||||
val descriptor =
|
val descriptor =
|
||||||
expression.resolveToDescriptorIfAny(resolutionFacade) ?: return@forEachDescendantOfType
|
expression.resolveToDescriptorIfAny(resolutionFacade) ?: return@forEachDescendantOfType
|
||||||
substitutors[descriptor] =
|
substitutors[descriptor] =
|
||||||
ClassSubstitutor.createFromKtClass(expression, resolutionFacade) ?: return@forEachDescendantOfType
|
SuperTypesSubstitutor.createFromKtClass(expression, resolutionFacade) ?: return@forEachDescendantOfType
|
||||||
for (typeParameter in expression.typeParameters) {
|
for (typeParameter in expression.typeParameters) {
|
||||||
val typeVariable = typeParameter.resolveToDescriptorIfAny(resolutionFacade)
|
val typeVariable = typeParameter.resolveToDescriptorIfAny(resolutionFacade)
|
||||||
?.safeAs<TypeParameterDescriptor>()
|
?.safeAs<TypeParameterDescriptor>()
|
||||||
@@ -206,5 +188,5 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun ClassReference.getState(typeElement: KtTypeElement?): State?
|
abstract fun ClassReference.getState(typeElement: KtTypeElement?): State
|
||||||
}
|
}
|
||||||
@@ -35,6 +35,7 @@ class DebugPrinter(private val inferenceContext: InferenceContext) {
|
|||||||
State.LOWER -> "L"
|
State.LOWER -> "L"
|
||||||
State.UPPER -> "U"
|
State.UPPER -> "U"
|
||||||
State.UNKNOWN -> "?"
|
State.UNKNOWN -> "?"
|
||||||
|
State.UNUSED -> "$"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BoundType.asString(): String = buildString {
|
fun BoundType.asString(): String = buildString {
|
||||||
@@ -71,11 +72,10 @@ class DebugPrinter(private val inferenceContext: InferenceContext) {
|
|||||||
|
|
||||||
|
|
||||||
private class Namer(inferenceContext: InferenceContext) {
|
private class Namer(inferenceContext: InferenceContext) {
|
||||||
val names = inferenceContext.typeVariables.mapIndexed { index, typeVariable ->
|
private val names = inferenceContext.typeVariables.mapIndexed { index, typeVariable ->
|
||||||
typeVariable to "T$index"
|
typeVariable to "T$index"
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
|
|
||||||
fun name(typeVariable: TypeVariable): String =
|
fun name(typeVariable: TypeVariable): String =
|
||||||
names.getValue(typeVariable)
|
names.getValue(typeVariable)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -19,7 +19,7 @@ data class InferenceContext(
|
|||||||
val typeElementToTypeVariable: Map<KtTypeElement, TypeVariable>,
|
val typeElementToTypeVariable: Map<KtTypeElement, TypeVariable>,
|
||||||
val declarationToTypeVariable: Map<KtNamedDeclaration, TypeVariable>,
|
val declarationToTypeVariable: Map<KtNamedDeclaration, TypeVariable>,
|
||||||
val declarationDescriptorToTypeVariable: Map<DeclarationDescriptor, TypeVariable>,
|
val declarationDescriptorToTypeVariable: Map<DeclarationDescriptor, TypeVariable>,
|
||||||
val classSubstitutions: Map<ClassDescriptor, ClassSubstitutor>
|
val superTypesSubstitutions: Map<ClassDescriptor, SuperTypesSubstitutor>
|
||||||
|
|
||||||
) {
|
) {
|
||||||
fun isInConversionScope(childCandidate: PsiElement) = when (childCandidate) {
|
fun isInConversionScope(childCandidate: PsiElement) = when (childCandidate) {
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ internal class Solver(
|
|||||||
println()
|
println()
|
||||||
println("type variables:")
|
println("type variables:")
|
||||||
for (typeVariable in inferenceContext.typeVariables) {
|
for (typeVariable in inferenceContext.typeVariables) {
|
||||||
println("${typeVariable.name} := ${typeVariable.state}")
|
if (typeVariable.state != State.UNUSED) {
|
||||||
|
println("${typeVariable.name} := ${typeVariable.state}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
println("---------------\n")
|
println("---------------\n")
|
||||||
}
|
}
|
||||||
@@ -33,6 +35,7 @@ internal class Solver(
|
|||||||
|
|
||||||
fun solveConstraints(constraints: List<Constraint>) {
|
fun solveConstraints(constraints: List<Constraint>) {
|
||||||
val mutableConstraints = constraints.toMutableList()
|
val mutableConstraints = constraints.toMutableList()
|
||||||
|
mutableConstraints.filterOutConstraintsWithUnusedState()
|
||||||
var currentStep = ConstraintPriority.values().first()
|
var currentStep = ConstraintPriority.values().first()
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
@@ -144,11 +147,11 @@ internal class Solver(
|
|||||||
val (lower, upper) = constraint
|
val (lower, upper) = constraint
|
||||||
if (lower is TypeVariableBound && lower.typeVariable.isFixed) {
|
if (lower is TypeVariableBound && lower.typeVariable.isFixed) {
|
||||||
somethingChanged = true
|
somethingChanged = true
|
||||||
constraint.subtype = lower.typeVariable.state.constraintBound()
|
constraint.subtype = lower.typeVariable.state.constraintBound() ?: continue
|
||||||
}
|
}
|
||||||
if (upper is TypeVariableBound && upper.typeVariable.isFixed) {
|
if (upper is TypeVariableBound && upper.typeVariable.isFixed) {
|
||||||
somethingChanged = true
|
somethingChanged = true
|
||||||
constraint.supertype = upper.typeVariable.state.constraintBound()
|
constraint.supertype = upper.typeVariable.state.constraintBound() ?: continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,5 +193,14 @@ internal class Solver(
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun MutableList<Constraint>.filterOutConstraintsWithUnusedState() {
|
||||||
|
removeIf { constraint ->
|
||||||
|
when (constraint) {
|
||||||
|
is SubtypeConstraint -> constraint.subtype.isUnused || constraint.supertype.isUnused
|
||||||
|
is EqualsConstraint -> constraint.left.isUnused || constraint.right.isUnused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,14 @@
|
|||||||
package org.jetbrains.kotlin.nj2k.inference.common
|
package org.jetbrains.kotlin.nj2k.inference.common
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
|
// lower state in the terms of subtyping relation,
|
||||||
|
// e.g., for nullability this is not null type as T <: T?
|
||||||
|
// for mutability this is MutableCollection as MutableCollection <: Collection
|
||||||
LOWER,
|
LOWER,
|
||||||
|
// the same as with lower but upper
|
||||||
UPPER,
|
UPPER,
|
||||||
UNKNOWN
|
// the type variable state is needed to be calculated
|
||||||
|
UNKNOWN,
|
||||||
|
// we don't need to infer state of that type variable
|
||||||
|
UNUSED
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.nj2k.inference.common
|
package org.jetbrains.kotlin.nj2k.inference.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
|
||||||
abstract class StateUpdater {
|
abstract class StateUpdater {
|
||||||
@@ -14,12 +15,14 @@ abstract class StateUpdater {
|
|||||||
val deepComparator = Comparator<TypeElementBasedTypeVariable> { o1, o2 ->
|
val deepComparator = Comparator<TypeElementBasedTypeVariable> { o1, o2 ->
|
||||||
if (o1.typeElement.typeElement.isAncestor(o2.typeElement.typeElement)) 1 else -1
|
if (o1.typeElement.typeElement.isAncestor(o2.typeElement.typeElement)) 1 else -1
|
||||||
}
|
}
|
||||||
for (typeVariable in inferenceContext
|
val typeVariablesSortedByDeep = inferenceContext.typeVariables
|
||||||
.typeVariables
|
|
||||||
.filterIsInstance<TypeElementBasedTypeVariable>()
|
.filterIsInstance<TypeElementBasedTypeVariable>()
|
||||||
.sortedWith(deepComparator)
|
.sortedWith(deepComparator)
|
||||||
) {
|
|
||||||
typeVariable.updateState()
|
runWriteAction {
|
||||||
|
for (typeVariable in typeVariablesSortedByDeep) {
|
||||||
|
typeVariable.updateState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -14,12 +14,12 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
|||||||
import org.jetbrains.kotlin.psi.KtTypeElement
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
|
||||||
class ClassSubstitutor(private val superTypes: Map<ClassifierDescriptor, Map<TypeParameterDescriptor, KtTypeElement>>) {
|
class SuperTypesSubstitutor(private val superTypes: Map<ClassifierDescriptor, Map<TypeParameterDescriptor, KtTypeElement>>) {
|
||||||
operator fun get(klass: ClassDescriptor, typeParameter: TypeParameterDescriptor): KtTypeElement? =
|
operator fun get(klass: ClassDescriptor, typeParameter: TypeParameterDescriptor): KtTypeElement? =
|
||||||
superTypes[klass]?.get(typeParameter)
|
superTypes[klass]?.get(typeParameter)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun createFromKtClass(klass: KtClassOrObject, resolutionFacade: ResolutionFacade): ClassSubstitutor? {
|
fun createFromKtClass(klass: KtClassOrObject, resolutionFacade: ResolutionFacade): SuperTypesSubstitutor? {
|
||||||
val superTypes =
|
val superTypes =
|
||||||
klass.superTypeListEntries.map { superType ->
|
klass.superTypeListEntries.map { superType ->
|
||||||
val typeReference = superType.typeReference ?: return null
|
val typeReference = superType.typeReference ?: return null
|
||||||
@@ -31,7 +31,7 @@ class ClassSubstitutor(private val superTypes: Map<ClassifierDescriptor, Map<Typ
|
|||||||
parameter to (argument.typeElement ?: return null)
|
parameter to (argument.typeElement ?: return null)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
}.toMap()
|
}.toMap()
|
||||||
return ClassSubstitutor(superTypes)
|
return SuperTypesSubstitutor(superTypes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-6
@@ -10,10 +10,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.BoundTypeCalculator
|
import org.jetbrains.kotlin.nj2k.inference.common.*
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.ConstraintBuilder
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.ConstraintPriority
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.InferenceContext
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.asAssignment
|
import org.jetbrains.kotlin.psi.psiUtil.asAssignment
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction
|
||||||
@@ -108,8 +105,9 @@ class CommonConstraintsCollector : ConstraintsCollector() {
|
|||||||
contextBoundType = loopRangeBoundType,
|
contextBoundType = loopRangeBoundType,
|
||||||
inferenceContext = inferenceContext
|
inferenceContext = inferenceContext
|
||||||
) ?: return
|
) ?: return
|
||||||
loopParameterTypeVariable.isSubtypeOf(
|
|
||||||
boundType.typeParameters.firstOrNull()?.boundType ?: return,
|
boundType.typeParameters.firstOrNull()?.boundType?.isSubtypeOf(
|
||||||
|
loopParameterTypeVariable.asBoundType(),
|
||||||
ConstraintPriority.ASSIGNMENT
|
ConstraintPriority.ASSIGNMENT
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -131,5 +129,6 @@ class CommonConstraintsCollector : ConstraintsCollector() {
|
|||||||
?.firstOrNull { it.valueParameters.isEmpty() }
|
?.firstOrNull { it.valueParameters.isEmpty() }
|
||||||
?.original
|
?.original
|
||||||
?.returnType
|
?.returnType
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -34,7 +34,7 @@ class FunctionConstraintsCollector(
|
|||||||
val classDescriptor = ktClass.resolveToDescriptorIfAny(resolutionFacade) ?: return
|
val classDescriptor = ktClass.resolveToDescriptorIfAny(resolutionFacade) ?: return
|
||||||
|
|
||||||
val superFunctions = superFunctionsProvider.provideSuperFunctionDescriptors(element) ?: return
|
val superFunctions = superFunctionsProvider.provideSuperFunctionDescriptors(element) ?: return
|
||||||
val substitutor = inferenceContext.classSubstitutions[classDescriptor] ?: return
|
val substitutor = inferenceContext.superTypesSubstitutions[classDescriptor] ?: return
|
||||||
|
|
||||||
for (superFunction in superFunctions) {
|
for (superFunction in superFunctions) {
|
||||||
val superClass = superFunction.containingDeclaration as? ClassDescriptor ?: continue
|
val superClass = superFunction.containingDeclaration as? ClassDescriptor ?: continue
|
||||||
@@ -68,7 +68,7 @@ class FunctionConstraintsCollector(
|
|||||||
typeElement: KtTypeElement,
|
typeElement: KtTypeElement,
|
||||||
superType: KotlinType,
|
superType: KotlinType,
|
||||||
superTypeElement: KtTypeElement?,
|
superTypeElement: KtTypeElement?,
|
||||||
substitutor: ClassSubstitutor,
|
substitutor: SuperTypesSubstitutor,
|
||||||
superClass: ClassDescriptor,
|
superClass: ClassDescriptor,
|
||||||
inferenceContext: InferenceContext
|
inferenceContext: InferenceContext
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -7,14 +7,10 @@ package org.jetbrains.kotlin.nj2k.inference.common
|
|||||||
|
|
||||||
import com.intellij.psi.PsiComment
|
import com.intellij.psi.PsiComment
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.nj2k.*
|
import org.jetbrains.kotlin.nj2k.*
|
||||||
import org.jetbrains.kotlin.psi.KtFunction
|
|
||||||
import org.jetbrains.kotlin.psi.KtTypeElement
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
import org.jetbrains.kotlin.psi.KtTypeProjection
|
import org.jetbrains.kotlin.psi.KtTypeProjection
|
||||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
fun PsiElement.getLabel(): JKElementInfoLabel? =
|
fun PsiElement.getLabel(): JKElementInfoLabel? =
|
||||||
@@ -33,12 +29,12 @@ fun PsiElement.elementInfo(converterContext: NewJ2kConverterContext): List<JKEle
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun KtTypeReference.hasUnknownLabel(context: NewJ2kConverterContext, unknownLabel: JKElementInfo) =
|
inline fun KtTypeReference.hasUnknownLabel(context: NewJ2kConverterContext, isUnknownLabel: (JKTypeInfo) -> Boolean) =
|
||||||
getLabel()?.let { label ->
|
getLabel()?.let { label ->
|
||||||
unknownLabel in context.elementsInfoStorage.getInfoForLabel(label).orEmpty()
|
context.elementsInfoStorage.getInfoForLabel(label)?.any { it.safeAs<JKTypeInfo>()?.let(isUnknownLabel) == true }
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
fun KtTypeElement.hasUnknownLabel(context: NewJ2kConverterContext, unknownLabel: JKElementInfo) =
|
inline fun KtTypeElement.hasUnknownLabel(context: NewJ2kConverterContext, isUnknownLabel: (JKTypeInfo) -> Boolean) =
|
||||||
parent
|
parent
|
||||||
?.safeAs<KtTypeReference>()
|
?.safeAs<KtTypeReference>()
|
||||||
?.hasUnknownLabel(context, unknownLabel) == true
|
?.hasUnknownLabel(context, isUnknownLabel) == true
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
|
|
||||||
|
class CallResolver(private val fqNames: Set<FqName>) {
|
||||||
|
private val shortNames = fqNames.map { it.shortName().identifier }.toSet()
|
||||||
|
|
||||||
|
private fun CallableDescriptor.isMutatorCall(): Boolean {
|
||||||
|
if (fqNameOrNull() in fqNames) return true
|
||||||
|
return overriddenDescriptors.any { it.isMutatorCall() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isNeededCall(expression: KtExpression, resolutionFacade: ResolutionFacade): Boolean {
|
||||||
|
val shortName = when (expression) {
|
||||||
|
is KtCallExpression -> expression.calleeExpression?.text
|
||||||
|
is KtReferenceExpression -> expression.text
|
||||||
|
else -> null
|
||||||
|
} ?: return false
|
||||||
|
if (shortName !in shortNames) return false
|
||||||
|
val call = expression.resolveToCall(resolutionFacade) ?: return false
|
||||||
|
return call.candidateDescriptor.isMutatorCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.BoundType
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.BoundTypeCalculatorImpl
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.BoundTypeEnhancer
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.InferenceContext
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
class MutabilityBoundTypeCalculator(
|
||||||
|
private val resolutionFacade: ResolutionFacade,
|
||||||
|
enhancer: BoundTypeEnhancer
|
||||||
|
) : BoundTypeCalculatorImpl(resolutionFacade, enhancer) {
|
||||||
|
|
||||||
|
private val callResolver = CallResolver(PRESERVING_MUTABILITY_FQ_NAMES)
|
||||||
|
|
||||||
|
override fun interceptCalculateBoundType(inferenceContext: InferenceContext, expression: KtExpression): BoundType? {
|
||||||
|
return when (expression) {
|
||||||
|
is KtQualifiedExpression -> {
|
||||||
|
val selector = expression.selectorExpression ?: return null
|
||||||
|
if (callResolver.isNeededCall(selector, resolutionFacade))
|
||||||
|
expression.receiverExpression.boundType(inferenceContext)
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val PRESERVING_MUTABILITY_FQ_NAMES = setOf(
|
||||||
|
FQ_NAMES.collection.child(Name.identifier("iterator")),
|
||||||
|
FQ_NAMES.list.child(Name.identifier("listIterator")),
|
||||||
|
FQ_NAMES.map.child(Name.identifier("entries")),
|
||||||
|
FQ_NAMES.map.child(Name.identifier("values"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.*
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.isFlexible
|
||||||
|
|
||||||
|
class MutabilityBoundTypeEnhancer : BoundTypeEnhancer() {
|
||||||
|
override fun enhance(
|
||||||
|
expression: KtExpression,
|
||||||
|
boundType: BoundType,
|
||||||
|
inferenceContext: InferenceContext
|
||||||
|
): BoundType = boundType
|
||||||
|
|
||||||
|
override fun enhanceKotlinType(
|
||||||
|
type: KotlinType,
|
||||||
|
boundType: BoundType,
|
||||||
|
allowLowerEnhancement: Boolean,
|
||||||
|
inferenceContext: InferenceContext
|
||||||
|
): BoundType {
|
||||||
|
if (type.isFlexible()) return boundType
|
||||||
|
val fqName = type.constructor.declarationDescriptor?.fqNameOrNull()
|
||||||
|
val enhancement = when {
|
||||||
|
fqName in MutabilityStateUpdater.mutableToImmutable && allowLowerEnhancement -> State.LOWER
|
||||||
|
fqName in MutabilityStateUpdater.immutableToMutable -> State.UPPER
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
return boundType.enhanceWith(enhancement)
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.*
|
||||||
|
|
||||||
|
class MutabilityConstraintBoundProvider : ConstraintBoundProviderImpl() {
|
||||||
|
override fun BoundTypeLabel.constraintBound(): ConstraintBound? = when (this) {
|
||||||
|
is TypeVariableLabel -> typeVariable.constraintBound()
|
||||||
|
is TypeParameterLabel -> null
|
||||||
|
is GenericLabel -> null
|
||||||
|
StarProjectionLabel -> null
|
||||||
|
NullLiteralLabel -> null
|
||||||
|
LiteralLabel -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import com.intellij.psi.CommonClassNames
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.*
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.ConstraintsCollector
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
class MutabilityConstraintsCollector : ConstraintsCollector() {
|
||||||
|
private val callResolver = CallResolver(MUTATOR_CALL_FQ_NAMES)
|
||||||
|
|
||||||
|
override fun ConstraintBuilder.collectConstraints(
|
||||||
|
element: KtElement,
|
||||||
|
boundTypeCalculator: BoundTypeCalculator,
|
||||||
|
inferenceContext: InferenceContext,
|
||||||
|
resolutionFacade: ResolutionFacade
|
||||||
|
) {
|
||||||
|
when (element) {
|
||||||
|
is KtQualifiedExpression -> {
|
||||||
|
val callExpression = element.selectorExpression?.safeAs<KtCallExpression>() ?: return
|
||||||
|
if (callResolver.isNeededCall(callExpression, resolutionFacade)) {
|
||||||
|
element.receiverExpression.isTheSameTypeAs(State.LOWER, ConstraintPriority.USE_AS_RECEIVER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val MUTATOR_CALL_FQ_NAMES = setOf(
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("add")),
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("addAll")),
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("remove")),
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("removeAll")),
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("retainAll")),
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("clear")),
|
||||||
|
FQ_NAMES.mutableCollection.child(Name.identifier("removeIf")),
|
||||||
|
|
||||||
|
FQ_NAMES.mutableList.child(Name.identifier("addAll")),
|
||||||
|
FQ_NAMES.mutableList.child(Name.identifier("set")),
|
||||||
|
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("put")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("remove")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("putAll")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("clear")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("putIfAbsent")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("replace")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("replaceAll")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("computeIfAbsent")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("computeIfPresent")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("compute")),
|
||||||
|
FQ_NAMES.mutableMap.child(Name.identifier("merge")),
|
||||||
|
|
||||||
|
FQ_NAMES.mutableMapEntry.child(Name.identifier("setValue")),
|
||||||
|
|
||||||
|
FQ_NAMES.mutableIterator.child(Name.identifier("remove")),
|
||||||
|
|
||||||
|
FQ_NAMES.mutableListIterator.child(Name.identifier("set")),
|
||||||
|
FQ_NAMES.mutableListIterator.child(Name.identifier("add"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.ClassReference
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.ContextCollector
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.State
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.hasUnknownLabel
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
|
|
||||||
|
class MutabilityContextCollector(
|
||||||
|
resolutionFacade: ResolutionFacade,
|
||||||
|
private val converterContext: NewJ2kConverterContext
|
||||||
|
) : ContextCollector(resolutionFacade) {
|
||||||
|
override fun ClassReference.getState(typeElement: KtTypeElement?): State = when {
|
||||||
|
typeElement == null -> State.UNUSED
|
||||||
|
typeElement.hasUnknownLabel(converterContext) { it.unknownMutability } -> State.UNKNOWN
|
||||||
|
else -> State.UNUSED
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.DefaultStateProvider
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.State
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.TypeVariable
|
||||||
|
|
||||||
|
class MutabilityDefaultStateProvider : DefaultStateProvider() {
|
||||||
|
override fun defaultStateFor(typeVariable: TypeVariable): State =
|
||||||
|
State.UPPER
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.State
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.StateUpdater
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.TypeElementBasedTypeVariable
|
||||||
|
import org.jetbrains.kotlin.psi.KtNullableType
|
||||||
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtUserType
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.SimpleType
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
class MutabilityStateUpdater : StateUpdater() {
|
||||||
|
override fun TypeElementBasedTypeVariable.updateState() = when (state) {
|
||||||
|
State.LOWER -> changeState(toMutable = true)
|
||||||
|
State.UPPER -> changeState(toMutable = false)
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun TypeElementBasedTypeVariable.changeState(toMutable: Boolean) {
|
||||||
|
changeState(typeElement.typeElement, typeElement.type, toMutable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeState(typeElement: KtTypeElement, type: KotlinType, toMutable: Boolean) {
|
||||||
|
if (type !is SimpleType) return
|
||||||
|
val userTypeElement = when (typeElement) {
|
||||||
|
is KtUserType -> typeElement
|
||||||
|
is KtNullableType -> typeElement.innerType as? KtUserType
|
||||||
|
else -> null
|
||||||
|
} ?: return
|
||||||
|
val initialFqName = type.constructor
|
||||||
|
.declarationDescriptor
|
||||||
|
.safeAs<ClassDescriptor>()
|
||||||
|
?.fqNameOrNull()
|
||||||
|
?: return
|
||||||
|
val newFqName = when {
|
||||||
|
!toMutable && initialFqName in mutableToImmutable -> mutableToImmutable[initialFqName]
|
||||||
|
toMutable && initialFqName in immutableToMutable -> immutableToMutable[initialFqName]
|
||||||
|
else -> null
|
||||||
|
} ?: return
|
||||||
|
val factory = KtPsiFactory(typeElement)
|
||||||
|
userTypeElement.referenceExpression?.replace(factory.createSimpleName(newFqName.shortName().identifier))
|
||||||
|
userTypeElement.qualifier.safeAs<KtUserType>()?.replace(factory.createType(newFqName.parent().asString()).typeElement ?: return)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mutableToImmutable = mapOf(
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableIterator to KotlinBuiltIns.FQ_NAMES.iterator,
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableCollection to KotlinBuiltIns.FQ_NAMES.collection,
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableList to KotlinBuiltIns.FQ_NAMES.list,
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableListIterator to KotlinBuiltIns.FQ_NAMES.listIterator,
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableSet to KotlinBuiltIns.FQ_NAMES.set,
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableMap to KotlinBuiltIns.FQ_NAMES.map,
|
||||||
|
KotlinBuiltIns.FQ_NAMES.mutableMapEntry to KotlinBuiltIns.FQ_NAMES.mapEntry
|
||||||
|
)
|
||||||
|
|
||||||
|
val immutableToMutable = mutableToImmutable.map { (key, value) -> value to key }.toMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-13
@@ -30,19 +30,17 @@ class NullabilityBoundTypeEnhancer(private val resolutionFacade: ResolutionFacad
|
|||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
boundType: BoundType,
|
boundType: BoundType,
|
||||||
inferenceContext: InferenceContext
|
inferenceContext: InferenceContext
|
||||||
): BoundType {
|
): BoundType = when {
|
||||||
return when {
|
expression.isNullExpression() ->
|
||||||
expression.isNullExpression() ->
|
WithForcedStateBoundType(boundType, State.UPPER)
|
||||||
WithForcedStateBoundType(boundType, State.UPPER)
|
expression is KtCallExpression -> enhanceCallExpression(expression, boundType, inferenceContext)
|
||||||
expression is KtCallExpression -> enhanceCallExpression(expression, boundType, inferenceContext)
|
expression is KtQualifiedExpression && expression.selectorExpression is KtCallExpression ->
|
||||||
expression is KtQualifiedExpression && expression.selectorExpression is KtCallExpression ->
|
enhanceCallExpression(expression.selectorExpression as KtCallExpression, boundType, inferenceContext)
|
||||||
enhanceCallExpression(expression.selectorExpression as KtCallExpression, boundType, inferenceContext)
|
expression is KtNameReferenceExpression ->
|
||||||
expression is KtNameReferenceExpression ->
|
boundType.enhanceWith(expression.smartCastEnhancement())
|
||||||
boundType.enhanceWith(expression.smartCastEnhancement())
|
expression is KtLambdaExpression ->
|
||||||
expression is KtLambdaExpression ->
|
WithForcedStateBoundType(boundType, State.LOWER)
|
||||||
WithForcedStateBoundType(boundType, State.LOWER)
|
else -> boundType
|
||||||
else -> boundType
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enhanceCallExpression(
|
private fun enhanceCallExpression(
|
||||||
|
|||||||
+4
-5
@@ -7,20 +7,19 @@ package org.jetbrains.kotlin.nj2k.inference.nullability
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||||
import org.jetbrains.kotlin.nj2k.UnknownNullability
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.*
|
import org.jetbrains.kotlin.nj2k.inference.common.*
|
||||||
import org.jetbrains.kotlin.psi.KtNullableType
|
import org.jetbrains.kotlin.psi.KtNullableType
|
||||||
import org.jetbrains.kotlin.psi.KtTypeElement
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|
||||||
|
|
||||||
class NullabilityContextCollector(
|
class NullabilityContextCollector(
|
||||||
resolutionFacade: ResolutionFacade,
|
resolutionFacade: ResolutionFacade,
|
||||||
private val converterContext: NewJ2kConverterContext
|
private val converterContext: NewJ2kConverterContext
|
||||||
) : ContextCollector(resolutionFacade) {
|
) : ContextCollector(resolutionFacade) {
|
||||||
override fun ClassReference.getState(typeElement: KtTypeElement?): State? = when {
|
override fun ClassReference.getState(typeElement: KtTypeElement?): State = when {
|
||||||
|
descriptor?.defaultType?.isUnit() == true -> State.LOWER
|
||||||
typeElement == null -> State.UNKNOWN
|
typeElement == null -> State.UNKNOWN
|
||||||
typeElement.hasUnknownLabel(converterContext, UnknownNullability) -> State.UNKNOWN
|
typeElement.hasUnknownLabel(converterContext) { it.unknownNullability } -> State.UNKNOWN
|
||||||
typeElement is KtNullableType -> State.UPPER
|
typeElement is KtNullableType -> State.UPPER
|
||||||
else -> State.LOWER
|
else -> State.LOWER
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-9
@@ -5,23 +5,18 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.nj2k.inference.nullability
|
package org.jetbrains.kotlin.nj2k.inference.nullability
|
||||||
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.*
|
import org.jetbrains.kotlin.nj2k.inference.common.State
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.StateUpdater
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.TypeElementBasedTypeVariable
|
||||||
import org.jetbrains.kotlin.psi.KtNullableType
|
import org.jetbrains.kotlin.psi.KtNullableType
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.psi.KtTypeElement
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
|
||||||
|
|
||||||
class NullabilityStateUpdater : StateUpdater() {
|
class NullabilityStateUpdater : StateUpdater() {
|
||||||
override fun TypeElementBasedTypeVariable.updateState() = when (state) {
|
override fun TypeElementBasedTypeVariable.updateState() = when (state) {
|
||||||
State.LOWER -> changeState(toNullable = false)
|
State.LOWER -> changeState(toNullable = false)
|
||||||
State.UPPER -> changeState(toNullable = true)
|
State.UPPER -> changeState(toNullable = true)
|
||||||
State.UNKNOWN -> {
|
else -> Unit
|
||||||
if (typeElement is TypeParameterElementData) {
|
|
||||||
changeState(toNullable = false)
|
|
||||||
} else {
|
|
||||||
changeState(toNullable = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TypeElementBasedTypeVariable.changeState(toNullable: Boolean) {
|
private fun TypeElementBasedTypeVariable.changeState(toNullable: Boolean) {
|
||||||
|
|||||||
@@ -245,8 +245,9 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
|
|||||||
),
|
),
|
||||||
runSingleTime = true
|
runSingleTime = true
|
||||||
),
|
),
|
||||||
nullabilityProcessing,
|
NullabilityInferenceProcessing(),
|
||||||
clearUndefinedLabelsProcessing
|
MutabilityInferenceProcessing(),
|
||||||
|
clearUnknownLabelsProcessing
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
NamedPostProcessingGroup(
|
NamedPostProcessingGroup(
|
||||||
@@ -255,7 +256,7 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
|
|||||||
),
|
),
|
||||||
NamedPostProcessingGroup(
|
NamedPostProcessingGroup(
|
||||||
"Shortening fully-qualified references",
|
"Shortening fully-qualified references",
|
||||||
listOf(shortenReferencesProcessing)
|
listOf(ShortenReferenceProcessing())
|
||||||
),
|
),
|
||||||
NamedPostProcessingGroup(
|
NamedPostProcessingGroup(
|
||||||
"Converting POJOs to data classes",
|
"Converting POJOs to data classes",
|
||||||
@@ -285,7 +286,7 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
|
|||||||
"Optimizing imports",
|
"Optimizing imports",
|
||||||
listOf(
|
listOf(
|
||||||
optimizeImportsProcessing,
|
optimizeImportsProcessing,
|
||||||
shortenReferencesProcessing
|
ShortenReferenceProcessing()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
NamedPostProcessingGroup(
|
NamedPostProcessingGroup(
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.postProcessing.processings
|
||||||
|
|
||||||
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
|
import com.intellij.openapi.editor.RangeMarker
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.range
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.BoundTypeCalculatorImpl
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.ByInfoSuperFunctionsProvider
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.ConstraintsCollectorAggregator
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.InferenceFacade
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.CallExpressionConstraintCollector
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.CommonConstraintsCollector
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.FunctionConstraintsCollector
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.mutability.*
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.nullability.*
|
||||||
|
import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
||||||
|
|
||||||
|
abstract class InferenceProcessing : GeneralPostProcessing {
|
||||||
|
final override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
|
||||||
|
val elements = if (rangeMarker != null) {
|
||||||
|
val range = rangeMarker.range ?: return
|
||||||
|
runReadAction { file.elementsInRange(range) }.filterIsInstance<KtElement>()
|
||||||
|
} else listOf(file)
|
||||||
|
val resolutionFacade = runReadAction { file.getResolutionFacade() }
|
||||||
|
|
||||||
|
withContext(EDT) {
|
||||||
|
CommandProcessor.getInstance().runUndoTransparentAction {
|
||||||
|
createInferenceFacade(resolutionFacade, converterContext).runOn(elements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun createInferenceFacade(
|
||||||
|
resolutionFacade: ResolutionFacade,
|
||||||
|
converterContext: NewJ2kConverterContext
|
||||||
|
): InferenceFacade
|
||||||
|
}
|
||||||
|
|
||||||
|
class NullabilityInferenceProcessing : InferenceProcessing() {
|
||||||
|
override fun createInferenceFacade(
|
||||||
|
resolutionFacade: ResolutionFacade,
|
||||||
|
converterContext: NewJ2kConverterContext
|
||||||
|
): InferenceFacade = InferenceFacade(
|
||||||
|
NullabilityContextCollector(resolutionFacade, converterContext),
|
||||||
|
ConstraintsCollectorAggregator(
|
||||||
|
resolutionFacade,
|
||||||
|
NullabilityConstraintBoundProvider(),
|
||||||
|
listOf(
|
||||||
|
CommonConstraintsCollector(),
|
||||||
|
CallExpressionConstraintCollector(),
|
||||||
|
FunctionConstraintsCollector(ByInfoSuperFunctionsProvider(resolutionFacade, converterContext)),
|
||||||
|
NullabilityConstraintsCollector()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
BoundTypeCalculatorImpl(resolutionFacade, NullabilityBoundTypeEnhancer(resolutionFacade)),
|
||||||
|
NullabilityStateUpdater(),
|
||||||
|
NullabilityDefaultStateProvider()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MutabilityInferenceProcessing : InferenceProcessing() {
|
||||||
|
override fun createInferenceFacade(
|
||||||
|
resolutionFacade: ResolutionFacade,
|
||||||
|
converterContext: NewJ2kConverterContext
|
||||||
|
): InferenceFacade = InferenceFacade(
|
||||||
|
MutabilityContextCollector(resolutionFacade, converterContext),
|
||||||
|
ConstraintsCollectorAggregator(
|
||||||
|
resolutionFacade,
|
||||||
|
MutabilityConstraintBoundProvider(),
|
||||||
|
listOf(
|
||||||
|
CommonConstraintsCollector(),
|
||||||
|
CallExpressionConstraintCollector(),
|
||||||
|
FunctionConstraintsCollector(ByInfoSuperFunctionsProvider(resolutionFacade, converterContext)),
|
||||||
|
MutabilityConstraintsCollector()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
MutabilityBoundTypeCalculator(resolutionFacade, MutabilityBoundTypeEnhancer()),
|
||||||
|
MutabilityStateUpdater(),
|
||||||
|
MutabilityDefaultStateProvider()
|
||||||
|
)
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.postProcessing.processings
|
||||||
|
|
||||||
|
import com.intellij.openapi.editor.RangeMarker
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.nj2k.ImportStorage
|
||||||
|
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||||
|
import org.jetbrains.kotlin.nj2k.postProcessing.SimplePostProcessing
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||||
|
|
||||||
|
class ShortenReferenceProcessing : SimplePostProcessing() {
|
||||||
|
private val filter = filter@{ element: PsiElement ->
|
||||||
|
when (element) {
|
||||||
|
is KtQualifiedExpression -> {
|
||||||
|
val fqName = element.selectorExpression?.mainReference?.resolve()?.getKotlinFqName()
|
||||||
|
?: return@filter ShortenReferences.FilterResult.PROCESS
|
||||||
|
if (ImportStorage.isImportNeeded(fqName)) ShortenReferences.FilterResult.PROCESS
|
||||||
|
else ShortenReferences.FilterResult.SKIP
|
||||||
|
}
|
||||||
|
else -> ShortenReferences.FilterResult.PROCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
|
||||||
|
if (rangeMarker != null) {
|
||||||
|
if (rangeMarker.isValid) {
|
||||||
|
ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ShortenReferences.DEFAULT.process(file, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-61
@@ -10,29 +10,12 @@ import com.intellij.psi.PsiComment
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiElementVisitor
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
|
||||||
import org.jetbrains.kotlin.idea.core.util.range
|
import org.jetbrains.kotlin.idea.core.util.range
|
||||||
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
|
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
|
||||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
|
||||||
import org.jetbrains.kotlin.nj2k.ImportStorage
|
|
||||||
import org.jetbrains.kotlin.nj2k.asLabel
|
import org.jetbrains.kotlin.nj2k.asLabel
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.BoundTypeCalculatorImpl
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.ByInfoSuperFunctionsProvider
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.ConstraintsCollectorAggregator
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.InferenceFacade
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.collectors.CallExpressionConstraintCollector
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.collectors.CommonConstraintsCollector
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.common.collectors.FunctionConstraintsCollector
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.NullabilityBoundTypeEnhancer
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.NullabilityConstraintsCollector
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.NullabilityContextCollector
|
|
||||||
import org.jetbrains.kotlin.nj2k.inference.nullability.NullabilityStateUpdater
|
|
||||||
import org.jetbrains.kotlin.nj2k.postProcessing.postProcessing
|
import org.jetbrains.kotlin.nj2k.postProcessing.postProcessing
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|
||||||
|
|
||||||
val formatCodeProcessing =
|
val formatCodeProcessing =
|
||||||
postProcessing { file, rangeMarker, _ ->
|
postProcessing { file, rangeMarker, _ ->
|
||||||
@@ -47,33 +30,7 @@ val formatCodeProcessing =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val nullabilityProcessing =
|
val clearUnknownLabelsProcessing =
|
||||||
postProcessing { file, rangeMarker, converterContext ->
|
|
||||||
val resolutionFacade = file.getResolutionFacade()
|
|
||||||
val inferenceFacade = InferenceFacade(
|
|
||||||
NullabilityContextCollector(resolutionFacade, converterContext),
|
|
||||||
ConstraintsCollectorAggregator(
|
|
||||||
resolutionFacade,
|
|
||||||
NullabilityConstraintBoundProvider(),
|
|
||||||
listOf(
|
|
||||||
CommonConstraintsCollector(),
|
|
||||||
CallExpressionConstraintCollector(),
|
|
||||||
FunctionConstraintsCollector(ByInfoSuperFunctionsProvider(resolutionFacade, converterContext)),
|
|
||||||
NullabilityConstraintsCollector()
|
|
||||||
)
|
|
||||||
),
|
|
||||||
BoundTypeCalculatorImpl(resolutionFacade, NullabilityBoundTypeEnhancer(resolutionFacade)),
|
|
||||||
NullabilityStateUpdater(),
|
|
||||||
NullabilityDefaultStateProvider()
|
|
||||||
)
|
|
||||||
val elements = if (rangeMarker != null) {
|
|
||||||
file.elementsInRange(rangeMarker.range ?: return@postProcessing).filterIsInstance<KtElement>()
|
|
||||||
} else listOf(file)
|
|
||||||
|
|
||||||
inferenceFacade.runOn(elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
val clearUndefinedLabelsProcessing =
|
|
||||||
postProcessing { file, _, _ ->
|
postProcessing { file, _, _ ->
|
||||||
file.clearUndefinedLabels()
|
file.clearUndefinedLabels()
|
||||||
}
|
}
|
||||||
@@ -94,23 +51,6 @@ private fun KtFile.clearUndefinedLabels() {
|
|||||||
comments.forEach { it.delete() }
|
comments.forEach { it.delete() }
|
||||||
}
|
}
|
||||||
|
|
||||||
val shortenReferencesProcessing =
|
|
||||||
postProcessing { file, rangeMarker, _ ->
|
|
||||||
val filter = filter@{ element: PsiElement ->
|
|
||||||
if (element !is KtQualifiedExpression) return@filter ShortenReferences.FilterResult.PROCESS
|
|
||||||
val fqName = element.selectorExpression?.mainReference?.resolve()?.getKotlinFqName()
|
|
||||||
?: return@filter ShortenReferences.FilterResult.PROCESS
|
|
||||||
if (ImportStorage.isImportNeeded(fqName)) ShortenReferences.FilterResult.PROCESS
|
|
||||||
else ShortenReferences.FilterResult.SKIP
|
|
||||||
}
|
|
||||||
if (rangeMarker != null) {
|
|
||||||
if (rangeMarker.isValid) {
|
|
||||||
ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ShortenReferences.DEFAULT.process(file, filter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val optimizeImportsProcessing =
|
val optimizeImportsProcessing =
|
||||||
postProcessing { file, rangeMarker, _ ->
|
postProcessing { file, rangeMarker, _ ->
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
private val JK_ROOT = File("./nj2k/src/org/jetbrains/kotlin/nj2k/tree")
|
||||||
|
|
||||||
|
private val JK_OUT_ROOT = File(JK_ROOT, "visitors")
|
||||||
|
|
||||||
|
private val JK_TREE_FILES = listOf(
|
||||||
|
"declarations.kt",
|
||||||
|
"elements.kt",
|
||||||
|
"expressions.kt",
|
||||||
|
"modifiers.kt",
|
||||||
|
"statements.kt"
|
||||||
|
).map { File(JK_ROOT, it) }
|
||||||
|
|
||||||
|
|
||||||
|
val elementRegex = """(class|object)\s+(JK[\w]+)(\([\w\s:,<>=\(\)\\]+\))?\s*:\s*(JK[a-zA-Z]+)""".toRegex()
|
||||||
|
|
||||||
|
|
||||||
|
data class InterfaceData(val name: String, val extends: String?)
|
||||||
|
|
||||||
|
fun File.interfaceNames() =
|
||||||
|
sequenceOf(this)
|
||||||
|
.map { it.readText() }
|
||||||
|
.flatMap { elementRegex.findAll(it) }
|
||||||
|
.map { match ->
|
||||||
|
InterfaceData(
|
||||||
|
match.groupValues[2],
|
||||||
|
match.groupValues[4].let { if (it == "JKAnnotationMemberValue") "JKTreeElement" else it }
|
||||||
|
)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
|
||||||
|
fun String.safeVarName() = when (this) {
|
||||||
|
"class" -> "klass"
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun genVisitors(
|
||||||
|
interfaceData: List<InterfaceData>,
|
||||||
|
visitorName: String
|
||||||
|
) {
|
||||||
|
val pkg = "package org.jetbrains.kotlin.nj2k.tree.visitors"
|
||||||
|
|
||||||
|
File(JK_OUT_ROOT, "$visitorName.kt").writeText(buildString {
|
||||||
|
appendln(pkg)
|
||||||
|
appendln()
|
||||||
|
appendln("import org.jetbrains.kotlin.nj2k.tree.*")
|
||||||
|
appendln()
|
||||||
|
appendln("abstract class $visitorName {")
|
||||||
|
interfaceData.joinTo(this, separator = "\n") { (name, ext) ->
|
||||||
|
val nameWithoutPrefix = name.removePrefix("JK")
|
||||||
|
val argName = nameWithoutPrefix.decapitalize().safeVarName()
|
||||||
|
val generifyCall = if (name != "JKTreeElement") "= visit${ext?.removePrefix("JK") ?: error(name)}($argName)" else ""
|
||||||
|
val modifier = if (name == "JKTreeElement") "abstract" else "open"
|
||||||
|
"""
|
||||||
|
| $modifier fun visit$nameWithoutPrefix($argName: $name) $generifyCall
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
appendln()
|
||||||
|
appendln("}")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
File(JK_OUT_ROOT, "${visitorName}WithCommentsPrinting.kt").writeText(buildString {
|
||||||
|
appendln(pkg)
|
||||||
|
appendln()
|
||||||
|
appendln("import org.jetbrains.kotlin.nj2k.tree.*")
|
||||||
|
appendln()
|
||||||
|
|
||||||
|
appendln("abstract class ${visitorName}WithCommentsPrinting : $visitorName() {")
|
||||||
|
appendln(
|
||||||
|
"""
|
||||||
|
| abstract fun printLeftNonCodeElements(element: JKNonCodeElementsListOwner)
|
||||||
|
| abstract fun printRightNonCodeElements(element: JKNonCodeElementsListOwner)
|
||||||
|
|
|
||||||
|
""".trimMargin()
|
||||||
|
)
|
||||||
|
|
||||||
|
interfaceData.joinTo(this, separator = "\n\n") { (name, ext) ->
|
||||||
|
val nameWithoutPrefix = name.removePrefix("JK")
|
||||||
|
val argName = nameWithoutPrefix.decapitalize().safeVarName()
|
||||||
|
val arg = "$argName: $name"
|
||||||
|
val rawVisitSuffix = "Raw"
|
||||||
|
val generifyCall = if (name != "JKTreeElement") "= visit${ext!!.removePrefix("JK")}$rawVisitSuffix($argName)" else ""
|
||||||
|
val modifier = if (name == "JKTreeElement") "abstract" else "open"
|
||||||
|
"""
|
||||||
|
| final override fun visit$nameWithoutPrefix($arg) {
|
||||||
|
| printLeftNonCodeElements($argName)
|
||||||
|
| visit$nameWithoutPrefix$rawVisitSuffix($argName)
|
||||||
|
| printRightNonCodeElements($argName)
|
||||||
|
| }
|
||||||
|
|
|
||||||
|
| $modifier fun visit$nameWithoutPrefix$rawVisitSuffix($arg) $generifyCall
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
appendln()
|
||||||
|
appendln("}")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
genVisitors(JK_TREE_FILES.flatMap { it.interfaceNames() }, "JKVisitor")
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.nj2k
|
package org.jetbrains.kotlin.nj2k
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
interface JKElementInfo
|
interface JKElementInfo
|
||||||
|
|
||||||
@@ -16,8 +17,23 @@ data class InternalSuperFunctionInfo(val label: JKElementInfoLabel) : SuperFunct
|
|||||||
|
|
||||||
data class FunctionInfo(val superFunctions: List<SuperFunctionInfo>) : JKElementInfo
|
data class FunctionInfo(val superFunctions: List<SuperFunctionInfo>) : JKElementInfo
|
||||||
|
|
||||||
object UnknownNullability : JKElementInfo
|
enum class JKTypeInfo(val unknownNullability: Boolean, val unknownMutability: Boolean) : JKElementInfo {
|
||||||
object UnknownMutability : JKElementInfo
|
KNOWN_NULLABILITY_KNOWN_MUTABILITY(false, false),
|
||||||
|
UNKNOWN_NULLABILITY_KNOWN_MUTABILITY(true, false),
|
||||||
|
KNOWN_NULLABILITY_UNKNOWN_MUTABILITY(false, true),
|
||||||
|
UNKNOWN_NULLABILITY_UNKNOWN_MUTABILITY(true, true)
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
operator fun invoke(unknownNullability: Boolean, unknownMutability: Boolean) = when {
|
||||||
|
!unknownNullability && !unknownMutability -> KNOWN_NULLABILITY_KNOWN_MUTABILITY
|
||||||
|
unknownNullability && !unknownMutability -> UNKNOWN_NULLABILITY_KNOWN_MUTABILITY
|
||||||
|
!unknownNullability && unknownMutability -> KNOWN_NULLABILITY_UNKNOWN_MUTABILITY
|
||||||
|
else -> UNKNOWN_NULLABILITY_UNKNOWN_MUTABILITY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline class JKElementInfoLabel(val label: String) {
|
inline class JKElementInfoLabel(val label: String) {
|
||||||
fun render(): String = "/*@@$label@@*/"
|
fun render(): String = "/*@@$label@@*/"
|
||||||
@@ -31,22 +47,18 @@ fun String.asLabel(): JKElementInfoLabel? =
|
|||||||
JKElementInfoLabel.LABEL_REGEX.matchEntire(this)?.groupValues?.getOrNull(1)?.let { JKElementInfoLabel(it) }
|
JKElementInfoLabel.LABEL_REGEX.matchEntire(this)?.groupValues?.getOrNull(1)?.let { JKElementInfoLabel(it) }
|
||||||
|
|
||||||
class JKElementInfoStorage {
|
class JKElementInfoStorage {
|
||||||
private val labelToInfo = mutableMapOf<JKElementInfoLabel, List<JKElementInfo>>()
|
private val labelToInfo = mutableMapOf<JKElementInfoLabel, MutableList<JKElementInfo>>()
|
||||||
private val elementToLabel = mutableMapOf<Any, JKElementInfoLabel>()
|
private val elementToLabel = mutableMapOf<Any, JKElementInfoLabel>()
|
||||||
|
|
||||||
fun getOrCreateInfoForElement(element: Any): JKElementInfoLabel =
|
fun getOrCreateInfoForElement(element: Any): JKElementInfoLabel =
|
||||||
elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) }
|
elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) }
|
||||||
|
|
||||||
fun getOrCreateInfoForLabel(label: JKElementInfoLabel): List<JKElementInfo> =
|
|
||||||
labelToInfo.getOrPut(label) { emptyList() }
|
|
||||||
|
|
||||||
fun getInfoForLabel(label: JKElementInfoLabel): List<JKElementInfo>? =
|
fun getInfoForLabel(label: JKElementInfoLabel): List<JKElementInfo>? =
|
||||||
labelToInfo[label]
|
labelToInfo[label]
|
||||||
|
|
||||||
|
|
||||||
fun addEntry(element: Any, info: JKElementInfo) {
|
fun addEntry(element: Any, info: JKElementInfo) {
|
||||||
val label = elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) }
|
val label = elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) }
|
||||||
labelToInfo[label] = labelToInfo[label].orEmpty() + info
|
labelToInfo.getOrPut(label) { SmartList() } += info
|
||||||
elementToLabel[element] = label
|
elementToLabel[element] = label
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +66,8 @@ class JKElementInfoStorage {
|
|||||||
private val charPool = ('a'..'z').toList()
|
private val charPool = ('a'..'z').toList()
|
||||||
private const val generatedStringLength = 6
|
private const val generatedStringLength = 6
|
||||||
|
|
||||||
private fun createRandomString(): String {
|
private fun createRandomString() = (1..generatedStringLength).joinToString("") {
|
||||||
return (1..generatedStringLength)
|
charPool[Random.nextInt(0, charPool.size)].toString()
|
||||||
.map { kotlin.random.Random.nextInt(0, charPool.size) }
|
|
||||||
.map(charPool::get)
|
|
||||||
.joinToString("")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,22 +6,22 @@
|
|||||||
package org.jetbrains.kotlin.nj2k.conversions
|
package org.jetbrains.kotlin.nj2k.conversions
|
||||||
|
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
import com.intellij.psi.impl.light.LightMethod
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor
|
||||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
|
||||||
import org.jetbrains.kotlin.nj2k.*
|
import org.jetbrains.kotlin.nj2k.*
|
||||||
import org.jetbrains.kotlin.nj2k.symbols.JKUniverseMethodSymbol
|
import org.jetbrains.kotlin.nj2k.symbols.JKUniverseMethodSymbol
|
||||||
import org.jetbrains.kotlin.nj2k.tree.*
|
import org.jetbrains.kotlin.nj2k.tree.*
|
||||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKCapturedType
|
import org.jetbrains.kotlin.nj2k.tree.impl.JKCapturedType
|
||||||
import org.jetbrains.kotlin.nj2k.tree.impl.psi
|
import org.jetbrains.kotlin.nj2k.tree.impl.psi
|
||||||
|
import org.jetbrains.kotlin.nj2k.types.JKParametrizedType
|
||||||
|
import org.jetbrains.kotlin.nj2k.types.JKStarProjectionType
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() {
|
class AddElementsInfoConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) {
|
||||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||||
when (element) {
|
when (element) {
|
||||||
is JKTypeElement -> addInfoForTypeElement(element)
|
is JKTypeElement -> addInfoForTypeElement(element)
|
||||||
@@ -33,14 +33,10 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
|
|||||||
|
|
||||||
private fun addInfoForTypeElement(typeElement: JKTypeElement) {
|
private fun addInfoForTypeElement(typeElement: JKTypeElement) {
|
||||||
typeElement.type.forAllInnerTypes { type ->
|
typeElement.type.forAllInnerTypes { type ->
|
||||||
if (type.nullability == Nullability.Default
|
val hasUnknownNullability =
|
||||||
|| type.safeAs<JKCapturedType>()?.wildcardType is JKStarProjectionType
|
type.nullability == Nullability.Default || type.safeAs<JKCapturedType>()?.wildcardType is JKStarProjectionType
|
||||||
) {
|
val hasUnknownMutability = type.isCollectionType
|
||||||
context.elementsInfoStorage.addEntry(type, UnknownNullability)
|
context.elementsInfoStorage.addEntry(type, JKTypeInfo(hasUnknownNullability, hasUnknownMutability))
|
||||||
}
|
|
||||||
if (type.isCollectionType) {
|
|
||||||
context.elementsInfoStorage.addEntry(type, UnknownMutability)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +44,7 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
|
|||||||
val superMethods = function.superMethods() ?: return
|
val superMethods = function.superMethods() ?: return
|
||||||
val superDescriptorsInfo = superMethods.map { superDescriptor ->
|
val superDescriptorsInfo = superMethods.map { superDescriptor ->
|
||||||
val superPsi = superDescriptor.original.findPsi()
|
val superPsi = superDescriptor.original.findPsi()
|
||||||
when (val symbol = context.symbolProvider.symbolsByPsi[superPsi]) {
|
when (val symbol = symbolProvider.symbolsByPsi[superPsi]) {
|
||||||
is JKUniverseMethodSymbol ->
|
is JKUniverseMethodSymbol ->
|
||||||
InternalSuperFunctionInfo(context.elementsInfoStorage.getOrCreateInfoForElement(symbol.target))
|
InternalSuperFunctionInfo(context.elementsInfoStorage.getOrCreateInfoForElement(symbol.target))
|
||||||
else -> ExternalSuperFunctionInfo(superDescriptor)
|
else -> ExternalSuperFunctionInfo(superDescriptor)
|
||||||
@@ -59,8 +55,8 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
|
|||||||
|
|
||||||
private fun JKMethod.superMethods(): Collection<FunctionDescriptor>? {
|
private fun JKMethod.superMethods(): Collection<FunctionDescriptor>? {
|
||||||
val psiMethod = psi<PsiMethod>() ?: return null
|
val psiMethod = psi<PsiMethod>() ?: return null
|
||||||
psiMethod.getJavaMethodDescriptor()?.let { descriptor ->
|
psiMethod.getJavaMethodDescriptor()?.let {
|
||||||
return descriptor.overriddenDescriptors
|
return it.overriddenDescriptors
|
||||||
}
|
}
|
||||||
return psiMethod.findSuperMethods().mapNotNull { superMethod ->
|
return psiMethod.findSuperMethods().mapNotNull { superMethod ->
|
||||||
when (superMethod) {
|
when (superMethod) {
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
|
|||||||
|
|
||||||
private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol {
|
private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol {
|
||||||
if (this is JKUniverseClassSymbol) return this
|
if (this is JKUniverseClassSymbol) return this
|
||||||
|
if (typeElement?.parentOfType<JKInheritanceInfo>() != null) return this
|
||||||
val newFqName = kotlinCollectionClassName()
|
val newFqName = kotlinCollectionClassName()
|
||||||
?: kotlinStandardType()
|
?: kotlinStandardType()
|
||||||
?: fqName
|
?: fqName
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal fun foo(file: File?): List<String> {
|
internal fun foo(file: File?): List<String?>? {
|
||||||
return emptyList()
|
return emptyList<String>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
private fun memberFun(file: File?) {}
|
private fun memberFun(file: File) {}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package to
|
package to
|
||||||
|
|
||||||
fun foo(): String {
|
fun foo(): String? {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package to
|
package to
|
||||||
|
|
||||||
@SomeAnnotation
|
@SomeAnnotation
|
||||||
fun foo(): String {
|
fun foo(): String? {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ class A {
|
|||||||
return JetRefactoringUtil.formatPsiMethod(element as PsiMethod, true, false)
|
return JetRefactoringUtil.formatPsiMethod(element as PsiMethod, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun getDimensionServiceKey(): String {
|
protected fun getDimensionServiceKey(): String? {
|
||||||
return "#org.jetbrains.kotlin.idea.refactoring.safeDelete.KotlinOverridingDialog"
|
return "#org.jetbrains.kotlin.idea.refactoring.safeDelete.KotlinOverridingDialog"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSelected(): ArrayList<UsageInfo> {
|
fun getSelected(): ArrayList<UsageInfo>? {
|
||||||
val result: ArrayList<UsageInfo> = ArrayList<UsageInfo?>()
|
val result: ArrayList<UsageInfo> = ArrayList<UsageInfo>()
|
||||||
for (i in 0 until myChecked.length) {
|
for (i in 0 until myChecked.length) {
|
||||||
if (myChecked.get(i)) {
|
if (myChecked.get(i)) {
|
||||||
result.add(myOverridingMethods.get(i))
|
result.add(myOverridingMethods.get(i))
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ import java.util.ArrayList
|
|||||||
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
bar(ArrayList<String?>())
|
bar(ArrayList<String>())
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,4 @@
|
|||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
|
||||||
fun foo() = ArrayList<String?>()
|
fun foo() = ArrayList<String>()
|
||||||
+1
-1
@@ -3,5 +3,5 @@ import java.util.ArrayList
|
|||||||
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
bar(/*comment*/ArrayList<String?>())
|
bar(/*comment*/ArrayList<String>())
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ import java.util.ArrayList
|
|||||||
|
|
||||||
|
|
||||||
class JavaClass {
|
class JavaClass {
|
||||||
internal fun foo(file: File?, target: List<String?>?) {
|
internal fun foo(file: File?, target: MutableList<String>?) {
|
||||||
val list = ArrayList<String>()
|
val list = ArrayList<String>()
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
list.add(file.name)
|
list.add(file.name)
|
||||||
|
|||||||
+1
-1
@@ -7,4 +7,4 @@ fun test() {
|
|||||||
|
|
||||||
//T0 <: T1 due to 'INITIALIZER'
|
//T0 <: T1 due to 'INITIALIZER'
|
||||||
//T2 <: T4 due to 'INITIALIZER'
|
//T2 <: T4 due to 'INITIALIZER'
|
||||||
//T3 <: T1 due to 'ASSIGNMENT'
|
//T1 <: T3 due to 'ASSIGNMENT'
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class Test {
|
||||||
|
val x: /*T2@*/List</*T1@*/Int> = ArrayList</*T0@*/Int>()/*ArrayList<T0@Int>*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//T1 := T0 due to 'INITIALIZER'
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T1@*/MutableIterator</*T0@*/Int>
|
||||||
|
) {
|
||||||
|
l0/*T1@MutableIterator<T0@Int>*/.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 <: T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
fun a() {
|
||||||
|
val list: /*T2@*/List</*T1@*/Int> = ArrayList</*T0@*/Int>()/*ArrayList<T0@Int>*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//T1 := T0 due to 'INITIALIZER'
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T1@*/MutableCollection</*T0@*/Int>,
|
||||||
|
l1: /*T3@*/MutableCollection</*T2@*/Int>,
|
||||||
|
l2: /*T5@*/MutableCollection</*T4@*/Int>,
|
||||||
|
l3: /*T7@*/MutableCollection</*T6@*/Int>,
|
||||||
|
l4: /*T9@*/MutableCollection</*T8@*/Int>
|
||||||
|
) {
|
||||||
|
l0/*T1@MutableCollection<T0@Int>*/.add(1/*LIT*/)
|
||||||
|
l1/*T3@MutableCollection<T2@Int>*/.addAll(l1/*T3@MutableCollection<T2@Int>*/)
|
||||||
|
l2/*T5@MutableCollection<T4@Int>*/.clear()
|
||||||
|
l3/*T7@MutableCollection<T6@Int>*/.removeAll(l1/*T3@MutableCollection<T2@Int>*/)
|
||||||
|
l4/*T9@MutableCollection<T8@Int>*/.retainAll(l1/*T3@MutableCollection<T2@Int>*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T2 := T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T3 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T4 := T4 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T5 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T6 := T6 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T6 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T7 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T8 := T8 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T8 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T9 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class Nya {
|
||||||
|
private val hashMap: /*T6@*/Map</*T3@*/String, /*T5@*/List</*T4@*/Int>> =
|
||||||
|
HashMap</*T0@*/String, /*T2@*/List</*T1@*/Int>>()/*HashMap<T0@String, T2@MutableList<T1@Int>>*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//T3 := T0 due to 'INITIALIZER'
|
||||||
|
//T4 := T1 due to 'INITIALIZER'
|
||||||
|
//T5 := T2 due to 'INITIALIZER'
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fun a(l0: /*T1@*/MutableList</*T0@*/Int>) {
|
||||||
|
val iterator: /*T3@*/MutableIterator</*T2@*/Int> = l0/*T1@MutableList<T0@Int>*/.iterator()/*T1@MutableList<T0@Int>*/
|
||||||
|
iterator/*T3@MutableIterator<T2@Int>*/.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := T0 due to 'INITIALIZER'
|
||||||
|
//T1 <: T3 due to 'INITIALIZER'
|
||||||
|
//T2 <: T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T3 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
class A {
|
||||||
|
val l: /*T1@*/List</*T0@*/Int>
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T1@*/MutableListIterator</*T0@*/Int>,
|
||||||
|
l1: /*T3@*/MutableListIterator</*T2@*/Int>,
|
||||||
|
l2: /*T5@*/MutableListIterator</*T4@*/Int>
|
||||||
|
) {
|
||||||
|
l0/*T1@MutableListIterator<T0@Int>*/.add(1/*LIT*/)
|
||||||
|
l1/*T3@MutableListIterator<T2@Int>*/.remove()
|
||||||
|
l2/*T5@MutableListIterator<T4@Int>*/.set(1/*LIT*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T2 := T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T3 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T4 := T4 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T5 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T1@*/MutableList</*T0@*/Int>,
|
||||||
|
l1: /*T3@*/MutableList</*T2@*/Int>,
|
||||||
|
l2: /*T5@*/MutableList</*T4@*/Int>,
|
||||||
|
l3: /*T7@*/MutableList</*T6@*/Int>,
|
||||||
|
l4: /*T9@*/MutableList</*T8@*/Int>,
|
||||||
|
l5: /*T11@*/MutableList</*T10@*/Int>,
|
||||||
|
l6: /*T13@*/MutableList</*T12@*/Int>,
|
||||||
|
l7: /*T15@*/MutableList</*T14@*/Int>
|
||||||
|
) {
|
||||||
|
l0/*T1@MutableList<T0@Int>*/.add(1/*LIT*/)
|
||||||
|
l1/*T3@MutableList<T2@Int>*/.addAll(1/*LIT*/, l1/*T3@MutableList<T2@Int>*/)
|
||||||
|
l2/*T5@MutableList<T4@Int>*/.addAll(l1/*T3@MutableList<T2@Int>*/)
|
||||||
|
l3/*T7@MutableList<T6@Int>*/.clear()
|
||||||
|
l4/*T9@MutableList<T8@Int>*/.remove(1/*LIT*/)
|
||||||
|
l5/*T11@MutableList<T10@Int>*/.removeAll(l1/*T3@MutableList<T2@Int>*/)
|
||||||
|
l5/*T11@MutableList<T10@Int>*/.removeAt(0/*LIT*/)
|
||||||
|
l6/*T13@MutableList<T12@Int>*/.retainAll(l1/*T3@MutableList<T2@Int>*/)
|
||||||
|
l7/*T15@MutableList<T14@Int>*/.set(0/*LIT*/, 0/*LIT*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T2 := T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T3 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T4 := T4 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T4 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T5 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T6 := T6 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T7 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T8 := T8 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T9 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T10 := T10 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T10 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T11 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T10 := T10 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T12 := T12 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T12 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T13 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T14 := T14 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T15 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val list: /*T4@*/List</*T3@*/MutableList</*T2@*/Int>> = ArrayList</*T1@*/MutableList</*T0@*/Int>>()/*ArrayList<T1@MutableList<T0@Int>>*/
|
||||||
|
for(l: /*T6@*/MutableList</*T5@*/Int> in list/*T4@MutableList<T3@MutableList<T2@Int>>*/) {
|
||||||
|
l/*T6@MutableList<T5@Int>*/.add(42/*LIT*/)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//T2 := T0 due to 'INITIALIZER'
|
||||||
|
//T3 := T1 due to 'INITIALIZER'
|
||||||
|
//T5 := T5 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T6 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T5 := T2 due to 'ASSIGNMENT'
|
||||||
|
//T3 <: T6 due to 'ASSIGNMENT'
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
fun a() {
|
||||||
|
val list: /*T4@*/List</*T3@*/MutableList</*T2@*/Int>> = ArrayList</*T1@*/MutableList</*T0@*/Int>>()/*ArrayList<T1@MutableList<T0@Int>>*/
|
||||||
|
list/*T4@MutableList<T3@MutableList<T2@Int>>*/.get(0/*LIT*/)/*T3@MutableList<T2@Int>*/.add(1/*LIT*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//T2 := T0 due to 'INITIALIZER'
|
||||||
|
//T3 := T1 due to 'INITIALIZER'
|
||||||
|
//T2 := T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T3 := T3 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T4 <: UPPER due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T3 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T2@*/MutableMap.MutableEntry</*T0@*/Int, /*T1@*/String>
|
||||||
|
) {
|
||||||
|
l0/*T2@MutableEntry<T0@Int, T1@String>*/.setValue(1/*LIT*/, "nya")
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := T1 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T2@*/MutableMap</*T0@*/Int, /*T1@*/String>,
|
||||||
|
l1: /*T5@*/MutableMap</*T3@*/Int, /*T4@*/String>,
|
||||||
|
l2: /*T8@*/MutableMap</*T6@*/Int, /*T7@*/String>,
|
||||||
|
l3: /*T11@*/MutableMap</*T9@*/Int, /*T10@*/String>
|
||||||
|
) {
|
||||||
|
l0/*T2@MutableMap<T0@Int, T1@String>*/.put(1)
|
||||||
|
l1/*T5@MutableMap<T3@Int, T4@String>*/.remove(1/*LIT*/, l1)
|
||||||
|
l2/*T8@MutableMap<T6@Int, T7@String>*/.putAll(l1/*T5@MutableMap<T3@Int, T4@String>*/)
|
||||||
|
l3/*T11@MutableMap<T9@Int, T10@String>*/.clear(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := T1 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T3 := T3 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T4 := T4 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T5 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T6 := T6 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T7 := T7 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T6 := T3 due to 'PARAMETER'
|
||||||
|
//T7 := T4 due to 'PARAMETER'
|
||||||
|
//T5 <: UPPER due to 'PARAMETER'
|
||||||
|
//T8 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T9 := T9 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T10 := T10 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T11 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
fun a(
|
||||||
|
l0: /*T1@*/MutableSet</*T0@*/Int>,
|
||||||
|
l1: /*T3@*/MutableSet</*T2@*/Int>,
|
||||||
|
l2: /*T5@*/MutableSet</*T4@*/Int>,
|
||||||
|
l3: /*T7@*/MutableSet</*T6@*/Int>,
|
||||||
|
l4: /*T9@*/MutableSet</*T8@*/Int>
|
||||||
|
) {
|
||||||
|
l0/*T1@MutableSet<T0@Int>*/.add(1/*LIT*/)
|
||||||
|
l1/*T3@MutableSet<T2@Int>*/.addAll(l1/*T3@MutableSet<T2@Int>*/)
|
||||||
|
l2/*T5@MutableSet<T4@Int>*/.clear()
|
||||||
|
l3/*T7@MutableSet<T6@Int>*/.removeAll(l1/*T3@MutableSet<T2@Int>*/)
|
||||||
|
l4/*T9@MutableSet<T8@Int>*/.retainAll(l1/*T3@MutableSet<T2@Int>*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//T0 := T0 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T2 := T2 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T2 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T3 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T4 := T4 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T5 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T6 := T6 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T6 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T7 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
//T8 := T8 due to 'RECEIVER_PARAMETER'
|
||||||
|
//T8 := T2 due to 'PARAMETER'
|
||||||
|
//T3 <: UPPER due to 'PARAMETER'
|
||||||
|
//T9 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
+1
-1
@@ -4,5 +4,5 @@ fun test(a: /*T1@*/List</*T0@*/Int?>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//T2 <: T0 due to 'ASSIGNMENT'
|
//T0 <: T2 due to 'ASSIGNMENT'
|
||||||
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
//T1 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
|||||||
+5
-5
@@ -1,4 +1,4 @@
|
|||||||
fun bar(map: /*T2@*/HashMap</*T0@*/String?, /*T1@*/Int>, list1: /*T4@*/List</*T3@*/Int?>, list2: /*T6@*/List</*T5@*/String?>) {
|
fun bar(map: /*T2@*/HashMap</*T0@*/String?, /*T1@*/Int>, list1: /*T4@*/List</*T3@*/Int>, list2: /*T6@*/List</*T5@*/String?>) {
|
||||||
for (entry: /*T9@*/MutableMap.MutableEntry</*T7@*/String?, /*T8@*/Int> in map/*T2@HashMap<T0@String, T1@Int>*/.entries/*MutableSet<MutableEntry<T0@String, T1@Int>>*/) {
|
for (entry: /*T9@*/MutableMap.MutableEntry</*T7@*/String?, /*T8@*/Int> in map/*T2@HashMap<T0@String, T1@Int>*/.entries/*MutableSet<MutableEntry<T0@String, T1@Int>>*/) {
|
||||||
val value: /*T10@*/Int = entry/*T9@MutableEntry<T7@String, T8@Int>*/.value/*T8@Int*/
|
val value: /*T10@*/Int = entry/*T9@MutableEntry<T7@String, T8@Int>*/.value/*T8@Int*/
|
||||||
if (entry/*T9@MutableEntry<T7@String, T8@Int>*/.key/*T7@String*/ == null/*LIT*/) {
|
if (entry/*T9@MutableEntry<T7@String, T8@Int>*/.key/*T7@String*/ == null/*LIT*/) {
|
||||||
@@ -21,11 +21,11 @@ fun bar(map: /*T2@*/HashMap</*T0@*/String?, /*T1@*/Int>, list1: /*T4@*/List</*T3
|
|||||||
//T9 := LOWER due to 'USE_AS_RECEIVER'
|
//T9 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
//T7 := UPPER due to 'COMPARE_WITH_NULL'
|
//T7 := UPPER due to 'COMPARE_WITH_NULL'
|
||||||
//T10 := LOWER due to 'USE_AS_RECEIVER'
|
//T10 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
//T0 := T7 due to 'ASSIGNMENT'
|
//T7 := T0 due to 'ASSIGNMENT'
|
||||||
//T1 := T8 due to 'ASSIGNMENT'
|
//T8 := T1 due to 'ASSIGNMENT'
|
||||||
//T11 := LOWER due to 'USE_AS_RECEIVER'
|
//T11 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
//T11 <: T3 due to 'ASSIGNMENT'
|
//T3 <: T11 due to 'ASSIGNMENT'
|
||||||
//T4 := LOWER due to 'USE_AS_RECEIVER'
|
//T4 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
//T12 := UPPER due to 'COMPARE_WITH_NULL'
|
//T12 := UPPER due to 'COMPARE_WITH_NULL'
|
||||||
//T12 <: T5 due to 'ASSIGNMENT'
|
//T5 <: T12 due to 'ASSIGNMENT'
|
||||||
//T6 := LOWER due to 'USE_AS_RECEIVER'
|
//T6 := LOWER due to 'USE_AS_RECEIVER'
|
||||||
|
|||||||
+9
-8
@@ -18,19 +18,19 @@ internal open class B {
|
|||||||
open val fromB1: String
|
open val fromB1: String
|
||||||
get() = ""
|
get() = ""
|
||||||
|
|
||||||
open var fromB2: String
|
open var fromB2: String?
|
||||||
get() = ""
|
get() = ""
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
open var fromB3: String
|
open var fromB3: String?
|
||||||
get() = ""
|
get() = ""
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
open var fromB4: String
|
open var fromB4: String?
|
||||||
get() = ""
|
get() = ""
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
open fun setFromB5(value: String) {}
|
open fun setFromB5(value: String?) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class C(override val something1: Int) : B(), I {
|
internal abstract class C(override val something1: Int) : B(), I {
|
||||||
@@ -59,19 +59,19 @@ internal abstract class C(override val something1: Int) : B(), I {
|
|||||||
override val fromB1: String
|
override val fromB1: String
|
||||||
get() = super.fromB1
|
get() = super.fromB1
|
||||||
|
|
||||||
override var fromB2: String
|
override var fromB2: String?
|
||||||
get() = super.fromB2
|
get() = super.fromB2
|
||||||
set(value) {
|
set(value) {
|
||||||
super.fromB2 = value
|
super.fromB2 = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override var fromB3: String
|
override var fromB3: String?
|
||||||
get() = super.fromB3
|
get() = super.fromB3
|
||||||
set(fromB3) {
|
set(fromB3) {
|
||||||
super.fromB3 = fromB3
|
super.fromB3 = fromB3
|
||||||
}
|
}
|
||||||
|
|
||||||
override var fromB4: String
|
override var fromB4: String?
|
||||||
get() = super.fromB4
|
get() = super.fromB4
|
||||||
set(value) {
|
set(value) {
|
||||||
super.fromB4 = value
|
super.fromB4 = value
|
||||||
@@ -81,7 +81,8 @@ internal abstract class C(override val something1: Int) : B(), I {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setFromB5(value: String) {
|
override fun setFromB5(value: String?) {
|
||||||
super.setFromB5(value)
|
super.setFromB5(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
public class Nya {
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
public Nya(int i) {
|
||||||
|
/*comment before*/
|
||||||
|
this/*1*/./*2*/i/*3*/ = /*4*/i /* comment after*/; // and after again
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
class Nya /*comment before*/(/*1*//*3*/ /*4*/private val i: Int)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
internal class A {
|
internal class A {
|
||||||
var list: List<String?>? = null
|
var list: List<String>? = null
|
||||||
fun foo() {
|
fun foo() {
|
||||||
for (e in list!!) {
|
for (e in list!!) {
|
||||||
println(e)
|
println(e)
|
||||||
|
|||||||
+1
-1
@@ -3,6 +3,6 @@ import java.util.ArrayList
|
|||||||
internal object A {
|
internal object A {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
List::class.java.isAssignableFrom(ArrayList::class.java)
|
MutableList::class.java.isAssignableFrom(ArrayList::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
internal class X(private val list: MutableList<Y>) {
|
internal class X(private val list: List<Y>) {
|
||||||
|
|
||||||
internal inner class Y
|
internal inner class Y
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// ERROR: Operator call corresponds to a dot-qualified call 'value.plus(1)' which is not allowed on a nullable receiver 'value'.
|
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
|
||||||
internal enum class E { A, B, C }
|
internal enum class E { A, B, C }
|
||||||
@@ -15,7 +14,7 @@ internal class A {
|
|||||||
val i = map.entries.iterator().next().key + 1
|
val i = map.entries.iterator().next().key + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bar(list: MutableList<String?>, map: HashMap<String?, Int?>) {
|
fun bar(list: MutableList<String?>, map: HashMap<String, Int>) {
|
||||||
val c = "a"[0]
|
val c = "a"[0]
|
||||||
val b = 10.toByte()
|
val b = 10.toByte()
|
||||||
val i = 10.1.toInt()
|
val i = 10.1.toInt()
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class TestMutableIterator implements Iterator<String> {
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
List<List<Integer>> list = new ArrayList<>();
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
list.get(0).add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
internal var list: List<List<Int>> = ArrayList()
|
||||||
|
fun test() {
|
||||||
|
list[0].add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Owner {
|
||||||
|
public List<String> list = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Updater {
|
||||||
|
public void update(Owner owner) {
|
||||||
|
owner.list.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class Owner {
|
||||||
|
var list: MutableList<String> = ArrayList()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Updater {
|
||||||
|
fun update(owner: Owner) {
|
||||||
|
owner.list.add("")
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -1376,6 +1376,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
|
|||||||
runTest("nj2k/testData/newJ2k/detectProperties/CannotDropOnlySetter.java");
|
runTest("nj2k/testData/newJ2k/detectProperties/CannotDropOnlySetter.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("commentInInitStatement.java")
|
||||||
|
public void testCommentInInitStatement() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/detectProperties/commentInInitStatement.java");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Comments.java")
|
@TestMetadata("Comments.java")
|
||||||
public void testComments() throws Exception {
|
public void testComments() throws Exception {
|
||||||
runTest("nj2k/testData/newJ2k/detectProperties/Comments.java");
|
runTest("nj2k/testData/newJ2k/detectProperties/Comments.java");
|
||||||
@@ -3628,6 +3633,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
|
|||||||
runTest("nj2k/testData/newJ2k/mutableCollections/Iterator2.java");
|
runTest("nj2k/testData/newJ2k/mutableCollections/Iterator2.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("listOfMutableList.java")
|
||||||
|
public void testListOfMutableList() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/mutableCollections/listOfMutableList.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("mutableListInOtherClass.java")
|
||||||
|
public void testMutableListInOtherClass() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.java");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Overrides.java")
|
@TestMetadata("Overrides.java")
|
||||||
public void testOverrides() throws Exception {
|
public void testOverrides() throws Exception {
|
||||||
runTest("nj2k/testData/newJ2k/mutableCollections/Overrides.java");
|
runTest("nj2k/testData/newJ2k/mutableCollections/Overrides.java");
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ abstract class AbstractCommonConstraintCollectorTest : AbstractConstraintCollect
|
|||||||
override fun createInferenceFacade(resolutionFacade: ResolutionFacade): InferenceFacade =
|
override fun createInferenceFacade(resolutionFacade: ResolutionFacade): InferenceFacade =
|
||||||
InferenceFacade(
|
InferenceFacade(
|
||||||
object : ContextCollector(resolutionFacade) {
|
object : ContextCollector(resolutionFacade) {
|
||||||
override fun ClassReference.getState(typeElement: KtTypeElement?): State? =
|
override fun ClassReference.getState(typeElement: KtTypeElement?): State =
|
||||||
State.UNKNOWN
|
State.UNKNOWN
|
||||||
},
|
},
|
||||||
ConstraintsCollectorAggregator(
|
ConstraintsCollectorAggregator(
|
||||||
|
|||||||
Generated
+5
@@ -134,6 +134,11 @@ public class CommonConstraintCollectorTestGenerated extends AbstractCommonConstr
|
|||||||
runTest("nj2k/testData/inference/common/memberCall.kt");
|
runTest("nj2k/testData/inference/common/memberCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("newExpression.kt")
|
||||||
|
public void testNewExpression() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/common/newExpression.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("returnFromLambda.kt")
|
@TestMetadata("returnFromLambda.kt")
|
||||||
public void testReturnFromLambda() throws Exception {
|
public void testReturnFromLambda() throws Exception {
|
||||||
runTest("nj2k/testData/inference/common/returnFromLambda.kt");
|
runTest("nj2k/testData/inference/common/returnFromLambda.kt");
|
||||||
|
|||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.runWriteAction
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.nj2k.descriptorByFileDirective
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.AbstractConstraintCollectorTest
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.*
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.CallExpressionConstraintCollector
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.CommonConstraintsCollector
|
||||||
|
import org.jetbrains.kotlin.nj2k.inference.common.collectors.FunctionConstraintsCollector
|
||||||
|
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
abstract class AbstractMutabilityInferenceTest : AbstractConstraintCollectorTest() {
|
||||||
|
override fun createInferenceFacade(resolutionFacade: ResolutionFacade): InferenceFacade {
|
||||||
|
val typeEnhancer = MutabilityBoundTypeEnhancer()
|
||||||
|
return InferenceFacade(
|
||||||
|
object : ContextCollector(resolutionFacade) {
|
||||||
|
override fun ClassReference.getState(typeElement: KtTypeElement?) =
|
||||||
|
when (descriptor?.fqNameOrNull()) {
|
||||||
|
in MutabilityStateUpdater.mutableToImmutable -> State.UNKNOWN
|
||||||
|
in MutabilityStateUpdater.immutableToMutable -> State.UNKNOWN
|
||||||
|
else -> State.UNUSED
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ConstraintsCollectorAggregator(
|
||||||
|
resolutionFacade,
|
||||||
|
MutabilityConstraintBoundProvider(),
|
||||||
|
listOf(
|
||||||
|
CommonConstraintsCollector(),
|
||||||
|
CallExpressionConstraintCollector(),
|
||||||
|
FunctionConstraintsCollector(ResolveSuperFunctionsProvider(resolutionFacade)),
|
||||||
|
MutabilityConstraintsCollector()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
MutabilityBoundTypeCalculator(resolutionFacade, typeEnhancer),
|
||||||
|
MutabilityStateUpdater(),
|
||||||
|
MutabilityDefaultStateProvider(),
|
||||||
|
renderDebugTypes = true,
|
||||||
|
printDebugConstraints = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KtFile.afterInference(): Unit = runWriteAction {
|
||||||
|
commitAndUnblockDocument()
|
||||||
|
ShortenReferences.DEFAULT.process(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KtFile.prepareFile() = runWriteAction {
|
||||||
|
fun KtTypeReference.updateMutability() {
|
||||||
|
MutabilityStateUpdater.changeState(
|
||||||
|
typeElement ?: return,
|
||||||
|
analyze()[BindingContext.TYPE, this]!!,
|
||||||
|
toMutable = true
|
||||||
|
)
|
||||||
|
for (typeArgument in typeElement!!.typeArgumentsAsTypes) {
|
||||||
|
typeArgument.updateMutability()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (typeReference in collectDescendantsOfType<KtTypeReference>()) {
|
||||||
|
if (typeReference.parent is KtConstructorCalleeExpression) continue
|
||||||
|
typeReference.updateMutability()
|
||||||
|
}
|
||||||
|
deleteComments()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProjectDescriptor() =
|
||||||
|
descriptorByFileDirective(File(testDataPath, fileName()), isAllFilesPresentInTest())
|
||||||
|
}
|
||||||
Generated
+96
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.inference.mutability;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
|
import org.jetbrains.kotlin.test.TargetBackend;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("nj2k/testData/inference/mutability")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public class MutabilityInferenceTestGenerated extends AbstractMutabilityInferenceTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInMutability() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("nj2k/testData/inference/mutability"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("arrayList.kt")
|
||||||
|
public void testArrayList() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/arrayList.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("collectionMutableCalls.kt")
|
||||||
|
public void testCollectionMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/collectionMutableCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("covariance.kt")
|
||||||
|
public void testCovariance() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/covariance.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("iteratorCall.kt")
|
||||||
|
public void testIteratorCall() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/iteratorCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("IteratorMutableCalls.kt")
|
||||||
|
public void testIteratorMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/IteratorMutableCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("list.kt")
|
||||||
|
public void testList() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/list.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("listIteratorMutableCalls.kt")
|
||||||
|
public void testListIteratorMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/listIteratorMutableCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("listMutableCalls.kt")
|
||||||
|
public void testListMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/listMutableCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("listOfListsForEach.kt")
|
||||||
|
public void testListOfListsForEach() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/listOfListsForEach.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("listOfMutableList.kt")
|
||||||
|
public void testListOfMutableList() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/listOfMutableList.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("mapEntryMutableCalls.kt")
|
||||||
|
public void testMapEntryMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/mapEntryMutableCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("mapMutableCalls.kt")
|
||||||
|
public void testMapMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/mapMutableCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("setMutableCalls.kt")
|
||||||
|
public void testSetMutableCalls() throws Exception {
|
||||||
|
runTest("nj2k/testData/inference/mutability/setMutableCalls.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ abstract class AbstractNullabilityInferenceTest : AbstractConstraintCollectorTes
|
|||||||
val typeEnhancer = NullabilityBoundTypeEnhancer(resolutionFacade)
|
val typeEnhancer = NullabilityBoundTypeEnhancer(resolutionFacade)
|
||||||
return InferenceFacade(
|
return InferenceFacade(
|
||||||
object : ContextCollector(resolutionFacade) {
|
object : ContextCollector(resolutionFacade) {
|
||||||
override fun ClassReference.getState(typeElement: KtTypeElement?): State? =
|
override fun ClassReference.getState(typeElement: KtTypeElement?): State =
|
||||||
State.UNKNOWN
|
State.UNKNOWN
|
||||||
},
|
},
|
||||||
ConstraintsCollectorAggregator(
|
ConstraintsCollectorAggregator(
|
||||||
|
|||||||
Reference in New Issue
Block a user