From f61bb5aa39948d5d5d66f52aadf23a970c639ec9 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 2 Sep 2019 18:56:50 +0300 Subject: [PATCH] New J2K: implement mutability inference in post-processing #KT-24293 fixed #KT-19603 fixed --- .../kotlin/generators/tests/GenerateTests.kt | 4 + .../generators/tests/GenerateTests.kt.183 | 4 + .../generators/tests/GenerateTests.kt.as34 | 4 + .../generators/tests/GenerateTests.kt.as35 | 4 + .../generators/tests/GenerateTests.kt.as36 | 4 + .../inference/common/BoundTypeCalculator.kt | 13 ++- .../nj2k/inference/common/Constraint.kt | 9 +- .../inference/common/ConstraintBuilder.kt | 6 +- .../nj2k/inference/common/ContextCollector.kt | 62 ++++------ .../nj2k/inference/common/DebugPrinter.kt | 4 +- .../nj2k/inference/common/InferenceContext.kt | 2 +- .../kotlin/nj2k/inference/common/Solver.kt | 18 ++- .../kotlin/nj2k/inference/common/State.kt | 9 +- .../nj2k/inference/common/StateUpdater.kt | 11 +- ...ubstitutor.kt => SuperTypesSubstitutor.kt} | 6 +- .../collectors/CommonConstraintsCollector.kt | 11 +- .../FunctionConstraintsCollector.kt | 4 +- .../kotlin/nj2k/inference/common/utils.kt | 12 +- .../nj2k/inference/mutability/CallResolver.kt | 36 ++++++ .../MutabilityBoundTypeCalculator.kt | 47 ++++++++ .../mutability/MutabilityBoundTypeEnhancer.kt | 36 ++++++ .../MutabilityConstraintBoundProvider.kt | 19 +++ .../MutabilityConstraintsCollector.kt | 72 ++++++++++++ .../mutability/MutabilityContextCollector.kt | 25 ++++ .../MutabilityDefaultStateProvider.kt | 15 +++ .../mutability/MutabilityStateUpdater.kt | 68 +++++++++++ .../NullabilityBoundTypeEnhancer.kt | 24 ++-- .../NullabilityContextCollector.kt | 9 +- .../nullability/NullabilityStateUpdater.kt | 13 +-- .../nj2k/postProcessing/J2kPostProcessor.kt | 9 +- .../processings/InferenceProcessing.kt | 94 +++++++++++++++ .../processings/ShortenReferenceProcessing.kt | 41 +++++++ .../postProcessing/processings/processings.kt | 62 +--------- .../GenerateJKTreeVisitorAndTransformer.kt | 110 ++++++++++++++++++ .../kotlin/nj2k/JKElementInfoStorage.kt | 37 +++--- .../conversions/AddElementsInfoConversion.kt | 24 ++-- .../nj2k/conversions/TypeMappingConversion.kt | 1 + .../testData/copyPaste/AddImports.expected.kt | 4 +- .../AddImportsWithExplicitImports.expected.kt | 2 +- .../MethodWithNoAnnotation.expected.kt | 2 +- .../MethodWithOnlyOneAnnotation.expected.kt | 2 +- .../SeveralMethodsSample.expected.kt | 6 +- .../AsExpression.expected.kt | 2 +- .../AsExpressionBody.expected.kt | 2 +- .../copyPastePlainText/KT13529_1.expected.kt | 2 +- .../PostProcessing.expected.kt | 2 +- nj2k/testData/inference/common/forLoop.kt | 2 +- .../inference/common/newExpression.kt | 5 + .../mutability/IteratorMutableCalls.kt | 8 ++ .../inference/mutability/arrayList.kt | 7 ++ .../mutability/collectionMutableCalls.kt | 30 +++++ .../inference/mutability/covariance.kt | 8 ++ .../inference/mutability/iteratorCall.kt | 10 ++ nj2k/testData/inference/mutability/list.kt | 4 + .../mutability/listIteratorMutableCalls.kt | 16 +++ .../inference/mutability/listMutableCalls.kt | 46 ++++++++ .../mutability/listOfListsForEach.kt | 15 +++ .../inference/mutability/listOfMutableList.kt | 14 +++ .../mutability/mapEntryMutableCalls.kt | 9 ++ .../inference/mutability/mapMutableCalls.kt | 27 +++++ .../inference/mutability/setMutableCalls.kt | 30 +++++ .../inference/nullability/loopIterator.kt | 2 +- nj2k/testData/inference/nullability/loops.kt | 10 +- .../newJ2k/detectProperties/Overrides.kt | 17 +-- .../commentInInitStatement.java | 8 ++ .../commentInInitStatement.kt | 1 + .../foreachStatement/nullableIterable.kt | 2 +- nj2k/testData/newJ2k/issues/kt-15791.kt | 2 +- nj2k/testData/newJ2k/issues/kt-5294.kt | 3 +- .../specialBuiltinMembers.kt | 3 +- .../implementMutableIterator.java | 17 +++ .../mutableCollections/listOfMutableList.java | 11 ++ .../mutableCollections/listOfMutableList.kt | 8 ++ .../mutableListInOtherClass.java | 12 ++ .../mutableListInOtherClass.kt | 11 ++ ...otlinConverterSingleFileTestGenerated.java | 15 +++ .../AbstractCommonConstraintCollectorTest.kt | 2 +- ...ommonConstraintCollectorTestGenerated.java | 5 + .../AbstractMutabilityInferenceTest.kt | 83 +++++++++++++ .../MutabilityInferenceTestGenerated.java | 96 +++++++++++++++ .../AbstractNullabilityInferenceTest.kt | 2 +- 81 files changed, 1263 insertions(+), 231 deletions(-) rename nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/{ClassSubstitutor.kt => SuperTypesSubstitutor.kt} (88%) create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/CallResolver.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeCalculator.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeEnhancer.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintBoundProvider.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintsCollector.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityContextCollector.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityDefaultStateProvider.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityStateUpdater.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt create mode 100644 nj2k/src/org/jetbrains/kotlin/nj2k/GenerateJKTreeVisitorAndTransformer.kt create mode 100644 nj2k/testData/inference/common/newExpression.kt create mode 100644 nj2k/testData/inference/mutability/IteratorMutableCalls.kt create mode 100644 nj2k/testData/inference/mutability/arrayList.kt create mode 100644 nj2k/testData/inference/mutability/collectionMutableCalls.kt create mode 100644 nj2k/testData/inference/mutability/covariance.kt create mode 100644 nj2k/testData/inference/mutability/iteratorCall.kt create mode 100644 nj2k/testData/inference/mutability/list.kt create mode 100644 nj2k/testData/inference/mutability/listIteratorMutableCalls.kt create mode 100644 nj2k/testData/inference/mutability/listMutableCalls.kt create mode 100644 nj2k/testData/inference/mutability/listOfListsForEach.kt create mode 100644 nj2k/testData/inference/mutability/listOfMutableList.kt create mode 100644 nj2k/testData/inference/mutability/mapEntryMutableCalls.kt create mode 100644 nj2k/testData/inference/mutability/mapMutableCalls.kt create mode 100644 nj2k/testData/inference/mutability/setMutableCalls.kt create mode 100644 nj2k/testData/newJ2k/detectProperties/commentInInitStatement.java create mode 100644 nj2k/testData/newJ2k/detectProperties/commentInInitStatement.kt create mode 100644 nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java create mode 100644 nj2k/testData/newJ2k/mutableCollections/listOfMutableList.java create mode 100644 nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt create mode 100644 nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.java create mode 100644 nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.kt create mode 100644 nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/AbstractMutabilityInferenceTest.kt create mode 100644 nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityInferenceTestGenerated.java diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 1d3c26e633f..3af2fb0c9df 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -143,6 +143,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest 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.noarg.AbstractBlackBoxCodegenTestForNoArg import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg @@ -1062,6 +1063,9 @@ fun main(args: Array) { testClass { model("inference/nullability") } + testClass { + model("inference/mutability") + } testClass { model("copyPaste", pattern = """^([^\.]+)\.java$""") } diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.183 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.183 index 61d1777aa1d..1f4d76382ce 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.183 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.183 @@ -161,6 +161,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest 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.noarg.AbstractBlackBoxCodegenTestForNoArg import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg @@ -1005,6 +1006,9 @@ fun main(args: Array) { testClass { model("inference/nullability") } + testClass { + model("inference/mutability") + } testClass { model("copyPaste", pattern = """^([^\.]+)\.java$""") } diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 index 7ef4a5ffa7e..74ee01ad823 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as34 @@ -145,6 +145,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest 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.noarg.AbstractBlackBoxCodegenTestForNoArg import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg @@ -969,6 +970,9 @@ fun main(args: Array) { testClass { model("inference/nullability") } + testClass { + model("inference/mutability") + } testClass { model("copyPaste", pattern = """^([^\.]+)\.java$""") } diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as35 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as35 index b219945b688..3424c6d9b71 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as35 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as35 @@ -145,6 +145,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest 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.noarg.AbstractBlackBoxCodegenTestForNoArg import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg @@ -965,6 +966,9 @@ fun main(args: Array) { testClass { model("inference/nullability") } + testClass { + model("inference/mutability") + } testClass { model("copyPaste", pattern = """^([^\.]+)\.java$""") } diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as36 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as36 index b219945b688..3424c6d9b71 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as36 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as36 @@ -145,6 +145,7 @@ import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest 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.noarg.AbstractBlackBoxCodegenTestForNoArg import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg @@ -965,6 +966,9 @@ fun main(args: Array) { testClass { model("inference/nullability") } + testClass { + model("inference/mutability") + } testClass { model("copyPaste", pattern = """^([^\.]+)\.java$""") } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/BoundTypeCalculator.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/BoundTypeCalculator.kt index f4f111a20c6..496c2e3a7df 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/BoundTypeCalculator.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/BoundTypeCalculator.kt @@ -88,9 +88,7 @@ open class BoundTypeCalculatorImpl( valueParameters.map { parameter -> parameter.typeReference?.typeElement?.let { typeElement -> inferenceContext.typeElementToTypeVariable[typeElement] - }?.let { typeVariable -> - typeVariable.asBoundType() - } ?: return null + }?.asBoundType() ?: return null } } else { descriptor.valueParameters.map { parameter -> @@ -220,7 +218,12 @@ open class BoundTypeCalculatorImpl( ) is TypeParameterDescriptor -> { - val containingDeclaration = target.containingDeclaration + val containingDeclaration = target.containingDeclaration.let { container -> + when (container) { + is TypeAliasDescriptor -> container.classDescriptor + else -> container + } ?: container + } when { containingDeclaration == call?.candidateDescriptor?.original -> { val returnTypeVariable = inferenceContext.typeElementToTypeVariable[ @@ -240,7 +243,7 @@ open class BoundTypeCalculatorImpl( contextBoundType?.isReferenceToClass == true -> contextBoundType.typeParameters.getOrNull(target.index)?.boundType - // `this` or `super` call case + // `this`, `super`, or constructor call cases containingDeclaration == call?.candidateDescriptor.safeAs()?.constructedClass -> { val returnTypeVariable = inferenceContext.typeElementToTypeVariable[ call?.call?.typeArguments?.getOrNull(target.index)?.typeReference?.typeElement diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Constraint.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Constraint.kt index df4d4adbf74..41e84ff32ba 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Constraint.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Constraint.kt @@ -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.UPPER -> LiteralBound.UPPER State.UNKNOWN -> LiteralBound.UNKNOWN + State.UNUSED -> null } + +val ConstraintBound.isUnused + get() = when (this) { + is TypeVariableBound -> typeVariable.state == State.UNUSED + is LiteralBound -> state == State.UNUSED + } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ConstraintBuilder.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ConstraintBuilder.kt index 80d42d9f585..c0f9c6ccae6 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ConstraintBuilder.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ConstraintBuilder.kt @@ -40,7 +40,11 @@ class ConstraintBuilder( fun KtExpression.isTheSameTypeAs(other: State, priority: ConstraintPriority) { boundType().label.safeAs()?.typeVariable?.let { typeVariable -> - constraints += EqualsConstraint(typeVariable.constraintBound(), other.constraintBound(), priority) + constraints += EqualsConstraint( + typeVariable.constraintBound(), + other.constraintBound() ?: return@let, + priority + ) } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ContextCollector.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ContextCollector.kt index 5dd85ce4708..d7bf744c9b1 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ContextCollector.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ContextCollector.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.addToStdlib.safeAs abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) { @@ -48,11 +47,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) val typeElement = typeElement ?: return null val classReference = classReference() ?: NoClassReference - val state = when { - classReference.descriptor?.defaultType?.isUnit() == true -> State.LOWER - defaultState != null -> defaultState - else -> classReference.getState(typeElement) - } + val state = defaultState ?: classReference.getState(typeElement) val typeArguments = if (classReference is DescriptorClassReference) { typeElement.typeArgumentsAsTypes.zip( @@ -65,22 +60,15 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) } } else emptyList() - return if (state == null) { - BoundTypeImpl( - GenericLabel(classReference), - typeArguments - ) - } else { - val typeVariable = TypeElementBasedTypeVariable( - classReference, - typeArguments, - typeElement.toData() ?: return null, - owner, - state - ) - typeElementToTypeVariable[typeElement] = typeVariable - typeVariable.asBoundType() - } + val typeVariable = TypeElementBasedTypeVariable( + classReference, + typeArguments, + typeElement.toData() ?: return null, + owner, + state + ) + typeElementToTypeVariable[typeElement] = typeVariable + return typeVariable.asBoundType() } fun KotlinType.toBoundType(): BoundType? { @@ -97,24 +85,18 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) } } else emptyList() - return if (state == null) { - BoundTypeImpl( - GenericLabel(classReference), - typeArguments - ) - } else { - val typeVariable = TypeBasedTypeVariable( - classReference, - typeArguments, - this, - state - ) - typeBasedTypeVariables += typeVariable - typeVariable.asBoundType() - } + + val typeVariable = TypeBasedTypeVariable( + classReference, + typeArguments, + this, + state + ) + typeBasedTypeVariables += typeVariable + return typeVariable.asBoundType() } - val substitutors = mutableMapOf() + val substitutors = mutableMapOf() fun isOrAsExpression(typeReference: KtTypeReference) { val typeElement = typeReference.typeElement ?: return @@ -160,7 +142,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade) val descriptor = expression.resolveToDescriptorIfAny(resolutionFacade) ?: return@forEachDescendantOfType substitutors[descriptor] = - ClassSubstitutor.createFromKtClass(expression, resolutionFacade) ?: return@forEachDescendantOfType + SuperTypesSubstitutor.createFromKtClass(expression, resolutionFacade) ?: return@forEachDescendantOfType for (typeParameter in expression.typeParameters) { val typeVariable = typeParameter.resolveToDescriptorIfAny(resolutionFacade) ?.safeAs() @@ -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 } \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/DebugPrinter.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/DebugPrinter.kt index 156dad087e5..4578a0b7cf6 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/DebugPrinter.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/DebugPrinter.kt @@ -35,6 +35,7 @@ class DebugPrinter(private val inferenceContext: InferenceContext) { State.LOWER -> "L" State.UPPER -> "U" State.UNKNOWN -> "?" + State.UNUSED -> "$" } fun BoundType.asString(): String = buildString { @@ -71,11 +72,10 @@ class DebugPrinter(private val 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" }.toMap() - fun name(typeVariable: TypeVariable): String = names.getValue(typeVariable) } \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceContext.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceContext.kt index a2b715a1077..19a7e8fd212 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceContext.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceContext.kt @@ -19,7 +19,7 @@ data class InferenceContext( val typeElementToTypeVariable: Map, val declarationToTypeVariable: Map, val declarationDescriptorToTypeVariable: Map, - val classSubstitutions: Map + val superTypesSubstitutions: Map ) { fun isInConversionScope(childCandidate: PsiElement) = when (childCandidate) { diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Solver.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Solver.kt index b3009a59e24..ab3d666972e 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Solver.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/Solver.kt @@ -25,7 +25,9 @@ internal class Solver( println() println("type variables:") for (typeVariable in inferenceContext.typeVariables) { - println("${typeVariable.name} := ${typeVariable.state}") + if (typeVariable.state != State.UNUSED) { + println("${typeVariable.name} := ${typeVariable.state}") + } } println("---------------\n") } @@ -33,6 +35,7 @@ internal class Solver( fun solveConstraints(constraints: List) { val mutableConstraints = constraints.toMutableList() + mutableConstraints.filterOutConstraintsWithUnusedState() var currentStep = ConstraintPriority.values().first() var i = 0 @@ -144,11 +147,11 @@ internal class Solver( val (lower, upper) = constraint if (lower is TypeVariableBound && lower.typeVariable.isFixed) { somethingChanged = true - constraint.subtype = lower.typeVariable.state.constraintBound() + constraint.subtype = lower.typeVariable.state.constraintBound() ?: continue } if (upper is TypeVariableBound && upper.typeVariable.isFixed) { somethingChanged = true - constraint.supertype = upper.typeVariable.state.constraintBound() + constraint.supertype = upper.typeVariable.state.constraintBound() ?: continue } } } @@ -190,5 +193,14 @@ internal class Solver( } return null } + + private fun MutableList.filterOutConstraintsWithUnusedState() { + removeIf { constraint -> + when (constraint) { + is SubtypeConstraint -> constraint.subtype.isUnused || constraint.supertype.isUnused + is EqualsConstraint -> constraint.left.isUnused || constraint.right.isUnused + } + } + } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/State.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/State.kt index c9aa2906c18..06cadb150b3 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/State.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/State.kt @@ -6,7 +6,14 @@ package org.jetbrains.kotlin.nj2k.inference.common 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, + // the same as with lower but 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 } \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/StateUpdater.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/StateUpdater.kt index 77755c99187..aa6f0dbb921 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/StateUpdater.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/StateUpdater.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.nj2k.inference.common +import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.psiUtil.isAncestor abstract class StateUpdater { @@ -14,12 +15,14 @@ abstract class StateUpdater { val deepComparator = Comparator { o1, o2 -> if (o1.typeElement.typeElement.isAncestor(o2.typeElement.typeElement)) 1 else -1 } - for (typeVariable in inferenceContext - .typeVariables + val typeVariablesSortedByDeep = inferenceContext.typeVariables .filterIsInstance() .sortedWith(deepComparator) - ) { - typeVariable.updateState() + + runWriteAction { + for (typeVariable in typeVariablesSortedByDeep) { + typeVariable.updateState() + } } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ClassSubstitutor.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/SuperTypesSubstitutor.kt similarity index 88% rename from nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ClassSubstitutor.kt rename to nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/SuperTypesSubstitutor.kt index 13083b0de25..28b548007cf 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/ClassSubstitutor.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/SuperTypesSubstitutor.kt @@ -14,12 +14,12 @@ import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtTypeElement import org.jetbrains.kotlin.resolve.BindingContext -class ClassSubstitutor(private val superTypes: Map>) { +class SuperTypesSubstitutor(private val superTypes: Map>) { operator fun get(klass: ClassDescriptor, typeParameter: TypeParameterDescriptor): KtTypeElement? = superTypes[klass]?.get(typeParameter) companion object { - fun createFromKtClass(klass: KtClassOrObject, resolutionFacade: ResolutionFacade): ClassSubstitutor? { + fun createFromKtClass(klass: KtClassOrObject, resolutionFacade: ResolutionFacade): SuperTypesSubstitutor? { val superTypes = klass.superTypeListEntries.map { superType -> val typeReference = superType.typeReference ?: return null @@ -31,7 +31,7 @@ class ClassSubstitutor(private val superTypes: Map Boolean) = getLabel()?.let { label -> - unknownLabel in context.elementsInfoStorage.getInfoForLabel(label).orEmpty() + context.elementsInfoStorage.getInfoForLabel(label)?.any { it.safeAs()?.let(isUnknownLabel) == true } } ?: false -fun KtTypeElement.hasUnknownLabel(context: NewJ2kConverterContext, unknownLabel: JKElementInfo) = +inline fun KtTypeElement.hasUnknownLabel(context: NewJ2kConverterContext, isUnknownLabel: (JKTypeInfo) -> Boolean) = parent ?.safeAs() - ?.hasUnknownLabel(context, unknownLabel) == true + ?.hasUnknownLabel(context, isUnknownLabel) == true diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/CallResolver.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/CallResolver.kt new file mode 100644 index 00000000000..384d96bc08a --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/CallResolver.kt @@ -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) { + 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() + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeCalculator.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeCalculator.kt new file mode 100644 index 00000000000..150629fe9d1 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeCalculator.kt @@ -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")) + ) + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeEnhancer.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeEnhancer.kt new file mode 100644 index 00000000000..b44d0c0a339 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityBoundTypeEnhancer.kt @@ -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) + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintBoundProvider.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintBoundProvider.kt new file mode 100644 index 00000000000..7ddb5d8c323 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintBoundProvider.kt @@ -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 + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintsCollector.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintsCollector.kt new file mode 100644 index 00000000000..c6532805b70 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityConstraintsCollector.kt @@ -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() ?: 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")) + ) + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityContextCollector.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityContextCollector.kt new file mode 100644 index 00000000000..dba40ef6277 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityContextCollector.kt @@ -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 + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityDefaultStateProvider.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityDefaultStateProvider.kt new file mode 100644 index 00000000000..6145cb6543b --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityDefaultStateProvider.kt @@ -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 +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityStateUpdater.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityStateUpdater.kt new file mode 100644 index 00000000000..04ed9eaa51b --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityStateUpdater.kt @@ -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() + ?.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()?.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() + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityBoundTypeEnhancer.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityBoundTypeEnhancer.kt index c80ddf041cf..31ac5f97d52 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityBoundTypeEnhancer.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityBoundTypeEnhancer.kt @@ -30,19 +30,17 @@ class NullabilityBoundTypeEnhancer(private val resolutionFacade: ResolutionFacad expression: KtExpression, boundType: BoundType, inferenceContext: InferenceContext - ): BoundType { - return when { - expression.isNullExpression() -> - WithForcedStateBoundType(boundType, State.UPPER) - expression is KtCallExpression -> enhanceCallExpression(expression, boundType, inferenceContext) - expression is KtQualifiedExpression && expression.selectorExpression is KtCallExpression -> - enhanceCallExpression(expression.selectorExpression as KtCallExpression, boundType, inferenceContext) - expression is KtNameReferenceExpression -> - boundType.enhanceWith(expression.smartCastEnhancement()) - expression is KtLambdaExpression -> - WithForcedStateBoundType(boundType, State.LOWER) - else -> boundType - } + ): BoundType = when { + expression.isNullExpression() -> + WithForcedStateBoundType(boundType, State.UPPER) + expression is KtCallExpression -> enhanceCallExpression(expression, boundType, inferenceContext) + expression is KtQualifiedExpression && expression.selectorExpression is KtCallExpression -> + enhanceCallExpression(expression.selectorExpression as KtCallExpression, boundType, inferenceContext) + expression is KtNameReferenceExpression -> + boundType.enhanceWith(expression.smartCastEnhancement()) + expression is KtLambdaExpression -> + WithForcedStateBoundType(boundType, State.LOWER) + else -> boundType } private fun enhanceCallExpression( diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityContextCollector.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityContextCollector.kt index 633b9703ef7..93f453a5169 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityContextCollector.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityContextCollector.kt @@ -7,20 +7,19 @@ package org.jetbrains.kotlin.nj2k.inference.nullability import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.UnknownNullability import org.jetbrains.kotlin.nj2k.inference.common.* import org.jetbrains.kotlin.psi.KtNullableType import org.jetbrains.kotlin.psi.KtTypeElement -import org.jetbrains.kotlin.psi.KtTypeReference -import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.kotlin.types.typeUtil.isUnit class NullabilityContextCollector( resolutionFacade: ResolutionFacade, private val converterContext: NewJ2kConverterContext ) : 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.hasUnknownLabel(converterContext, UnknownNullability) -> State.UNKNOWN + typeElement.hasUnknownLabel(converterContext) { it.unknownNullability } -> State.UNKNOWN typeElement is KtNullableType -> State.UPPER else -> State.LOWER } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityStateUpdater.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityStateUpdater.kt index baa42b66b82..e10d55b4b96 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityStateUpdater.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/nullability/NullabilityStateUpdater.kt @@ -5,23 +5,18 @@ 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.KtPsiFactory import org.jetbrains.kotlin.psi.KtTypeElement -import org.jetbrains.kotlin.psi.psiUtil.isAncestor class NullabilityStateUpdater : StateUpdater() { override fun TypeElementBasedTypeVariable.updateState() = when (state) { State.LOWER -> changeState(toNullable = false) State.UPPER -> changeState(toNullable = true) - State.UNKNOWN -> { - if (typeElement is TypeParameterElementData) { - changeState(toNullable = false) - } else { - changeState(toNullable = true) - } - } + else -> Unit } private fun TypeElementBasedTypeVariable.changeState(toNullable: Boolean) { diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt index e335b359a01..541c84b8efe 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt @@ -245,8 +245,9 @@ private val processings: List = listOf( ), runSingleTime = true ), - nullabilityProcessing, - clearUndefinedLabelsProcessing + NullabilityInferenceProcessing(), + MutabilityInferenceProcessing(), + clearUnknownLabelsProcessing ) ), NamedPostProcessingGroup( @@ -255,7 +256,7 @@ private val processings: List = listOf( ), NamedPostProcessingGroup( "Shortening fully-qualified references", - listOf(shortenReferencesProcessing) + listOf(ShortenReferenceProcessing()) ), NamedPostProcessingGroup( "Converting POJOs to data classes", @@ -285,7 +286,7 @@ private val processings: List = listOf( "Optimizing imports", listOf( optimizeImportsProcessing, - shortenReferencesProcessing + ShortenReferenceProcessing() ) ), NamedPostProcessingGroup( diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt new file mode 100644 index 00000000000..11308411677 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt @@ -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() + } 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() + ) +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt new file mode 100644 index 00000000000..d7019f48050 --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt index b58f3412268..363cbb5f71f 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt @@ -10,29 +10,12 @@ import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor 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.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.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.psi.* import org.jetbrains.kotlin.psi.psiUtil.elementsInRange -import org.jetbrains.kotlin.utils.addToStdlib.safeAs val formatCodeProcessing = postProcessing { file, rangeMarker, _ -> @@ -47,33 +30,7 @@ val formatCodeProcessing = } } -val nullabilityProcessing = - 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() - } else listOf(file) - - inferenceFacade.runOn(elements) - } - -val clearUndefinedLabelsProcessing = +val clearUnknownLabelsProcessing = postProcessing { file, _, _ -> file.clearUndefinedLabels() } @@ -94,23 +51,6 @@ private fun KtFile.clearUndefinedLabels() { 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 = postProcessing { file, rangeMarker, _ -> diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/GenerateJKTreeVisitorAndTransformer.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/GenerateJKTreeVisitorAndTransformer.kt new file mode 100644 index 00000000000..fe1a5d1743b --- /dev/null +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/GenerateJKTreeVisitorAndTransformer.kt @@ -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, + 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") +} + diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt index 24710c0a60d..87627ac520f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt @@ -6,7 +6,8 @@ package org.jetbrains.kotlin.nj2k import org.jetbrains.kotlin.descriptors.FunctionDescriptor - +import org.jetbrains.kotlin.utils.SmartList +import kotlin.random.Random interface JKElementInfo @@ -16,8 +17,23 @@ data class InternalSuperFunctionInfo(val label: JKElementInfoLabel) : SuperFunct data class FunctionInfo(val superFunctions: List) : JKElementInfo -object UnknownNullability : JKElementInfo -object UnknownMutability : JKElementInfo +enum class JKTypeInfo(val unknownNullability: Boolean, val unknownMutability: Boolean) : 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) { fun render(): String = "/*@@$label@@*/" @@ -31,22 +47,18 @@ fun String.asLabel(): JKElementInfoLabel? = JKElementInfoLabel.LABEL_REGEX.matchEntire(this)?.groupValues?.getOrNull(1)?.let { JKElementInfoLabel(it) } class JKElementInfoStorage { - private val labelToInfo = mutableMapOf>() + private val labelToInfo = mutableMapOf>() private val elementToLabel = mutableMapOf() fun getOrCreateInfoForElement(element: Any): JKElementInfoLabel = elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) } - fun getOrCreateInfoForLabel(label: JKElementInfoLabel): List = - labelToInfo.getOrPut(label) { emptyList() } - fun getInfoForLabel(label: JKElementInfoLabel): List? = labelToInfo[label] - fun addEntry(element: Any, info: JKElementInfo) { val label = elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) } - labelToInfo[label] = labelToInfo[label].orEmpty() + info + labelToInfo.getOrPut(label) { SmartList() } += info elementToLabel[element] = label } @@ -54,11 +66,8 @@ class JKElementInfoStorage { private val charPool = ('a'..'z').toList() private const val generatedStringLength = 6 - private fun createRandomString(): String { - return (1..generatedStringLength) - .map { kotlin.random.Random.nextInt(0, charPool.size) } - .map(charPool::get) - .joinToString("") + private fun createRandomString() = (1..generatedStringLength).joinToString("") { + charPool[Random.nextInt(0, charPool.size)].toString() } } } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt index d4b60bf37d7..899127334ed 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt @@ -6,22 +6,22 @@ package org.jetbrains.kotlin.nj2k.conversions import com.intellij.psi.PsiMethod -import com.intellij.psi.impl.light.LightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor import org.jetbrains.kotlin.j2k.ast.Nullability 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.symbols.JKUniverseMethodSymbol import org.jetbrains.kotlin.nj2k.tree.* import org.jetbrains.kotlin.nj2k.tree.impl.JKCapturedType 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 -class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() { +class AddElementsInfoConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { override fun applyToElement(element: JKTreeElement): JKTreeElement { when (element) { is JKTypeElement -> addInfoForTypeElement(element) @@ -33,14 +33,10 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R private fun addInfoForTypeElement(typeElement: JKTypeElement) { typeElement.type.forAllInnerTypes { type -> - if (type.nullability == Nullability.Default - || type.safeAs()?.wildcardType is JKStarProjectionType - ) { - context.elementsInfoStorage.addEntry(type, UnknownNullability) - } - if (type.isCollectionType) { - context.elementsInfoStorage.addEntry(type, UnknownMutability) - } + val hasUnknownNullability = + type.nullability == Nullability.Default || type.safeAs()?.wildcardType is JKStarProjectionType + val hasUnknownMutability = type.isCollectionType + context.elementsInfoStorage.addEntry(type, JKTypeInfo(hasUnknownNullability, hasUnknownMutability)) } } @@ -48,7 +44,7 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R val superMethods = function.superMethods() ?: return val superDescriptorsInfo = superMethods.map { superDescriptor -> val superPsi = superDescriptor.original.findPsi() - when (val symbol = context.symbolProvider.symbolsByPsi[superPsi]) { + when (val symbol = symbolProvider.symbolsByPsi[superPsi]) { is JKUniverseMethodSymbol -> InternalSuperFunctionInfo(context.elementsInfoStorage.getOrCreateInfoForElement(symbol.target)) else -> ExternalSuperFunctionInfo(superDescriptor) @@ -59,8 +55,8 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R private fun JKMethod.superMethods(): Collection? { val psiMethod = psi() ?: return null - psiMethod.getJavaMethodDescriptor()?.let { descriptor -> - return descriptor.overriddenDescriptors + psiMethod.getJavaMethodDescriptor()?.let { + return it.overriddenDescriptors } return psiMethod.findSuperMethods().mapNotNull { superMethod -> when (superMethod) { diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt index 35b5cf7c5ab..6bd150c8268 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt @@ -112,6 +112,7 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol { if (this is JKUniverseClassSymbol) return this + if (typeElement?.parentOfType() != null) return this val newFqName = kotlinCollectionClassName() ?: kotlinStandardType() ?: fqName diff --git a/nj2k/testData/copyPaste/AddImports.expected.kt b/nj2k/testData/copyPaste/AddImports.expected.kt index 492bad518cb..da92b99c283 100644 --- a/nj2k/testData/copyPaste/AddImports.expected.kt +++ b/nj2k/testData/copyPaste/AddImports.expected.kt @@ -1,5 +1,5 @@ import java.io.File -internal fun foo(file: File?): List { - return emptyList() +internal fun foo(file: File?): List? { + return emptyList() } diff --git a/nj2k/testData/copyPaste/AddImportsWithExplicitImports.expected.kt b/nj2k/testData/copyPaste/AddImportsWithExplicitImports.expected.kt index c695294a680..1589bce4b00 100644 --- a/nj2k/testData/copyPaste/AddImportsWithExplicitImports.expected.kt +++ b/nj2k/testData/copyPaste/AddImportsWithExplicitImports.expected.kt @@ -1,7 +1,7 @@ import java.io.File class C { - private fun memberFun(file: File?) {} + private fun memberFun(file: File) {} companion object { @JvmStatic diff --git a/nj2k/testData/copyPaste/MethodWithNoAnnotation.expected.kt b/nj2k/testData/copyPaste/MethodWithNoAnnotation.expected.kt index 475b62a40fb..2ab3e845206 100644 --- a/nj2k/testData/copyPaste/MethodWithNoAnnotation.expected.kt +++ b/nj2k/testData/copyPaste/MethodWithNoAnnotation.expected.kt @@ -1,5 +1,5 @@ package to -fun foo(): String { +fun foo(): String? { return "" } diff --git a/nj2k/testData/copyPaste/MethodWithOnlyOneAnnotation.expected.kt b/nj2k/testData/copyPaste/MethodWithOnlyOneAnnotation.expected.kt index 148b68695cb..995184411c7 100644 --- a/nj2k/testData/copyPaste/MethodWithOnlyOneAnnotation.expected.kt +++ b/nj2k/testData/copyPaste/MethodWithOnlyOneAnnotation.expected.kt @@ -1,6 +1,6 @@ package to @SomeAnnotation -fun foo(): String { +fun foo(): String? { return "" } diff --git a/nj2k/testData/copyPaste/SeveralMethodsSample.expected.kt b/nj2k/testData/copyPaste/SeveralMethodsSample.expected.kt index bc04269bcd9..d2ca93d2031 100644 --- a/nj2k/testData/copyPaste/SeveralMethodsSample.expected.kt +++ b/nj2k/testData/copyPaste/SeveralMethodsSample.expected.kt @@ -23,12 +23,12 @@ class A { return JetRefactoringUtil.formatPsiMethod(element as PsiMethod, true, false) } - protected fun getDimensionServiceKey(): String { + protected fun getDimensionServiceKey(): String? { return "#org.jetbrains.kotlin.idea.refactoring.safeDelete.KotlinOverridingDialog" } - fun getSelected(): ArrayList { - val result: ArrayList = ArrayList() + fun getSelected(): ArrayList? { + val result: ArrayList = ArrayList() for (i in 0 until myChecked.length) { if (myChecked.get(i)) { result.add(myOverridingMethods.get(i)) diff --git a/nj2k/testData/copyPastePlainText/AsExpression.expected.kt b/nj2k/testData/copyPastePlainText/AsExpression.expected.kt index ca296477dba..65fc3b8bb1b 100644 --- a/nj2k/testData/copyPastePlainText/AsExpression.expected.kt +++ b/nj2k/testData/copyPastePlainText/AsExpression.expected.kt @@ -3,5 +3,5 @@ import java.util.ArrayList fun foo() { - bar(ArrayList()) + bar(ArrayList()) } \ No newline at end of file diff --git a/nj2k/testData/copyPastePlainText/AsExpressionBody.expected.kt b/nj2k/testData/copyPastePlainText/AsExpressionBody.expected.kt index a435466eaaf..fa4a1e80add 100644 --- a/nj2k/testData/copyPastePlainText/AsExpressionBody.expected.kt +++ b/nj2k/testData/copyPastePlainText/AsExpressionBody.expected.kt @@ -2,4 +2,4 @@ import java.util.ArrayList -fun foo() = ArrayList() \ No newline at end of file +fun foo() = ArrayList() \ No newline at end of file diff --git a/nj2k/testData/copyPastePlainText/KT13529_1.expected.kt b/nj2k/testData/copyPastePlainText/KT13529_1.expected.kt index 06692dc2f82..a042bb2ee7d 100644 --- a/nj2k/testData/copyPastePlainText/KT13529_1.expected.kt +++ b/nj2k/testData/copyPastePlainText/KT13529_1.expected.kt @@ -3,5 +3,5 @@ import java.util.ArrayList fun foo() { - bar(/*comment*/ArrayList()) + bar(/*comment*/ArrayList()) } \ No newline at end of file diff --git a/nj2k/testData/copyPastePlainText/PostProcessing.expected.kt b/nj2k/testData/copyPastePlainText/PostProcessing.expected.kt index 2b3d6cad61e..44cd0814484 100644 --- a/nj2k/testData/copyPastePlainText/PostProcessing.expected.kt +++ b/nj2k/testData/copyPastePlainText/PostProcessing.expected.kt @@ -5,7 +5,7 @@ import java.util.ArrayList class JavaClass { - internal fun foo(file: File?, target: List?) { + internal fun foo(file: File?, target: MutableList?) { val list = ArrayList() if (file != null) { list.add(file.name) diff --git a/nj2k/testData/inference/common/forLoop.kt b/nj2k/testData/inference/common/forLoop.kt index dad6ea0a54c..320e4651c21 100644 --- a/nj2k/testData/inference/common/forLoop.kt +++ b/nj2k/testData/inference/common/forLoop.kt @@ -7,4 +7,4 @@ fun test() { //T0 <: T1 due to 'INITIALIZER' //T2 <: T4 due to 'INITIALIZER' -//T3 <: T1 due to 'ASSIGNMENT' +//T1 <: T3 due to 'ASSIGNMENT' diff --git a/nj2k/testData/inference/common/newExpression.kt b/nj2k/testData/inference/common/newExpression.kt new file mode 100644 index 00000000000..46e44d25dbb --- /dev/null +++ b/nj2k/testData/inference/common/newExpression.kt @@ -0,0 +1,5 @@ +class Test { + val x: /*T2@*/List = ArrayList()/*ArrayList*/ +} + +//T1 := T0 due to 'INITIALIZER' diff --git a/nj2k/testData/inference/mutability/IteratorMutableCalls.kt b/nj2k/testData/inference/mutability/IteratorMutableCalls.kt new file mode 100644 index 00000000000..121c91fff6d --- /dev/null +++ b/nj2k/testData/inference/mutability/IteratorMutableCalls.kt @@ -0,0 +1,8 @@ +fun a( + l0: /*T1@*/MutableIterator +) { + l0/*T1@MutableIterator*/.remove() +} + +//T0 <: T0 due to 'RECEIVER_PARAMETER' +//T1 := LOWER due to 'USE_AS_RECEIVER' diff --git a/nj2k/testData/inference/mutability/arrayList.kt b/nj2k/testData/inference/mutability/arrayList.kt new file mode 100644 index 00000000000..80ffe70219f --- /dev/null +++ b/nj2k/testData/inference/mutability/arrayList.kt @@ -0,0 +1,7 @@ +import java.util.ArrayList + +fun a() { + val list: /*T2@*/List = ArrayList()/*ArrayList*/ +} + +//T1 := T0 due to 'INITIALIZER' diff --git a/nj2k/testData/inference/mutability/collectionMutableCalls.kt b/nj2k/testData/inference/mutability/collectionMutableCalls.kt new file mode 100644 index 00000000000..3b381e0a617 --- /dev/null +++ b/nj2k/testData/inference/mutability/collectionMutableCalls.kt @@ -0,0 +1,30 @@ +fun a( + l0: /*T1@*/MutableCollection, + l1: /*T3@*/MutableCollection, + l2: /*T5@*/MutableCollection, + l3: /*T7@*/MutableCollection, + l4: /*T9@*/MutableCollection +) { + l0/*T1@MutableCollection*/.add(1/*LIT*/) + l1/*T3@MutableCollection*/.addAll(l1/*T3@MutableCollection*/) + l2/*T5@MutableCollection*/.clear() + l3/*T7@MutableCollection*/.removeAll(l1/*T3@MutableCollection*/) + l4/*T9@MutableCollection*/.retainAll(l1/*T3@MutableCollection*/) +} + +//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' diff --git a/nj2k/testData/inference/mutability/covariance.kt b/nj2k/testData/inference/mutability/covariance.kt new file mode 100644 index 00000000000..2b871a1770c --- /dev/null +++ b/nj2k/testData/inference/mutability/covariance.kt @@ -0,0 +1,8 @@ +class Nya { + private val hashMap: /*T6@*/Map> = + HashMap>()/*HashMap>*/ +} + +//T3 := T0 due to 'INITIALIZER' +//T4 := T1 due to 'INITIALIZER' +//T5 := T2 due to 'INITIALIZER' diff --git a/nj2k/testData/inference/mutability/iteratorCall.kt b/nj2k/testData/inference/mutability/iteratorCall.kt new file mode 100644 index 00000000000..efcceeddf13 --- /dev/null +++ b/nj2k/testData/inference/mutability/iteratorCall.kt @@ -0,0 +1,10 @@ +fun a(l0: /*T1@*/MutableList) { + val iterator: /*T3@*/MutableIterator = l0/*T1@MutableList*/.iterator()/*T1@MutableList*/ + iterator/*T3@MutableIterator*/.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' diff --git a/nj2k/testData/inference/mutability/list.kt b/nj2k/testData/inference/mutability/list.kt new file mode 100644 index 00000000000..c4c540bd4dd --- /dev/null +++ b/nj2k/testData/inference/mutability/list.kt @@ -0,0 +1,4 @@ +class A { + val l: /*T1@*/List +} + diff --git a/nj2k/testData/inference/mutability/listIteratorMutableCalls.kt b/nj2k/testData/inference/mutability/listIteratorMutableCalls.kt new file mode 100644 index 00000000000..68a0164cd66 --- /dev/null +++ b/nj2k/testData/inference/mutability/listIteratorMutableCalls.kt @@ -0,0 +1,16 @@ +fun a( + l0: /*T1@*/MutableListIterator, + l1: /*T3@*/MutableListIterator, + l2: /*T5@*/MutableListIterator +) { + l0/*T1@MutableListIterator*/.add(1/*LIT*/) + l1/*T3@MutableListIterator*/.remove() + l2/*T5@MutableListIterator*/.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' diff --git a/nj2k/testData/inference/mutability/listMutableCalls.kt b/nj2k/testData/inference/mutability/listMutableCalls.kt new file mode 100644 index 00000000000..87dfbd15f97 --- /dev/null +++ b/nj2k/testData/inference/mutability/listMutableCalls.kt @@ -0,0 +1,46 @@ +fun a( + l0: /*T1@*/MutableList, + l1: /*T3@*/MutableList, + l2: /*T5@*/MutableList, + l3: /*T7@*/MutableList, + l4: /*T9@*/MutableList, + l5: /*T11@*/MutableList, + l6: /*T13@*/MutableList, + l7: /*T15@*/MutableList +) { + l0/*T1@MutableList*/.add(1/*LIT*/) + l1/*T3@MutableList*/.addAll(1/*LIT*/, l1/*T3@MutableList*/) + l2/*T5@MutableList*/.addAll(l1/*T3@MutableList*/) + l3/*T7@MutableList*/.clear() + l4/*T9@MutableList*/.remove(1/*LIT*/) + l5/*T11@MutableList*/.removeAll(l1/*T3@MutableList*/) + l5/*T11@MutableList*/.removeAt(0/*LIT*/) + l6/*T13@MutableList*/.retainAll(l1/*T3@MutableList*/) + l7/*T15@MutableList*/.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' diff --git a/nj2k/testData/inference/mutability/listOfListsForEach.kt b/nj2k/testData/inference/mutability/listOfListsForEach.kt new file mode 100644 index 00000000000..8396a9fc10d --- /dev/null +++ b/nj2k/testData/inference/mutability/listOfListsForEach.kt @@ -0,0 +1,15 @@ +import java.util.ArrayList + +fun test() { + val list: /*T4@*/List> = ArrayList>()/*ArrayList>*/ + for(l: /*T6@*/MutableList in list/*T4@MutableList>*/) { + l/*T6@MutableList*/.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' diff --git a/nj2k/testData/inference/mutability/listOfMutableList.kt b/nj2k/testData/inference/mutability/listOfMutableList.kt new file mode 100644 index 00000000000..e37cf6b722a --- /dev/null +++ b/nj2k/testData/inference/mutability/listOfMutableList.kt @@ -0,0 +1,14 @@ +import java.util.ArrayList + +fun a() { + val list: /*T4@*/List> = ArrayList>()/*ArrayList>*/ + list/*T4@MutableList>*/.get(0/*LIT*/)/*T3@MutableList*/.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' diff --git a/nj2k/testData/inference/mutability/mapEntryMutableCalls.kt b/nj2k/testData/inference/mutability/mapEntryMutableCalls.kt new file mode 100644 index 00000000000..17f7c9cffae --- /dev/null +++ b/nj2k/testData/inference/mutability/mapEntryMutableCalls.kt @@ -0,0 +1,9 @@ +fun a( + l0: /*T2@*/MutableMap.MutableEntry +) { + l0/*T2@MutableEntry*/.setValue(1/*LIT*/, "nya") +} + +//T0 := T0 due to 'RECEIVER_PARAMETER' +//T1 := T1 due to 'RECEIVER_PARAMETER' +//T2 := LOWER due to 'USE_AS_RECEIVER' diff --git a/nj2k/testData/inference/mutability/mapMutableCalls.kt b/nj2k/testData/inference/mutability/mapMutableCalls.kt new file mode 100644 index 00000000000..c829bee7480 --- /dev/null +++ b/nj2k/testData/inference/mutability/mapMutableCalls.kt @@ -0,0 +1,27 @@ +fun a( + l0: /*T2@*/MutableMap, + l1: /*T5@*/MutableMap, + l2: /*T8@*/MutableMap, + l3: /*T11@*/MutableMap +) { + l0/*T2@MutableMap*/.put(1) + l1/*T5@MutableMap*/.remove(1/*LIT*/, l1) + l2/*T8@MutableMap*/.putAll(l1/*T5@MutableMap*/) + l3/*T11@MutableMap*/.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' diff --git a/nj2k/testData/inference/mutability/setMutableCalls.kt b/nj2k/testData/inference/mutability/setMutableCalls.kt new file mode 100644 index 00000000000..2973c1d1907 --- /dev/null +++ b/nj2k/testData/inference/mutability/setMutableCalls.kt @@ -0,0 +1,30 @@ +fun a( + l0: /*T1@*/MutableSet, + l1: /*T3@*/MutableSet, + l2: /*T5@*/MutableSet, + l3: /*T7@*/MutableSet, + l4: /*T9@*/MutableSet +) { + l0/*T1@MutableSet*/.add(1/*LIT*/) + l1/*T3@MutableSet*/.addAll(l1/*T3@MutableSet*/) + l2/*T5@MutableSet*/.clear() + l3/*T7@MutableSet*/.removeAll(l1/*T3@MutableSet*/) + l4/*T9@MutableSet*/.retainAll(l1/*T3@MutableSet*/) +} + +//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' diff --git a/nj2k/testData/inference/nullability/loopIterator.kt b/nj2k/testData/inference/nullability/loopIterator.kt index b205d62cae1..146d126f258 100644 --- a/nj2k/testData/inference/nullability/loopIterator.kt +++ b/nj2k/testData/inference/nullability/loopIterator.kt @@ -4,5 +4,5 @@ fun test(a: /*T1@*/List) { } } -//T2 <: T0 due to 'ASSIGNMENT' +//T0 <: T2 due to 'ASSIGNMENT' //T1 := LOWER due to 'USE_AS_RECEIVER' diff --git a/nj2k/testData/inference/nullability/loops.kt b/nj2k/testData/inference/nullability/loops.kt index 661c1bc2a6e..fdad0ec70fc 100644 --- a/nj2k/testData/inference/nullability/loops.kt +++ b/nj2k/testData/inference/nullability/loops.kt @@ -1,4 +1,4 @@ -fun bar(map: /*T2@*/HashMap, list1: /*T4@*/List, list2: /*T6@*/List) { +fun bar(map: /*T2@*/HashMap, list1: /*T4@*/List, list2: /*T6@*/List) { for (entry: /*T9@*/MutableMap.MutableEntry in map/*T2@HashMap*/.entries/*MutableSet>*/) { val value: /*T10@*/Int = entry/*T9@MutableEntry*/.value/*T8@Int*/ if (entry/*T9@MutableEntry*/.key/*T7@String*/ == null/*LIT*/) { @@ -21,11 +21,11 @@ fun bar(map: /*T2@*/HashMap, list1: /*T4@*/List? = null + var list: List? = null fun foo() { for (e in list!!) { println(e) diff --git a/nj2k/testData/newJ2k/issues/kt-15791.kt b/nj2k/testData/newJ2k/issues/kt-15791.kt index 45e8ebf72ad..6e38706404c 100644 --- a/nj2k/testData/newJ2k/issues/kt-15791.kt +++ b/nj2k/testData/newJ2k/issues/kt-15791.kt @@ -3,6 +3,6 @@ import java.util.ArrayList internal object A { @JvmStatic fun main(args: Array) { - List::class.java.isAssignableFrom(ArrayList::class.java) + MutableList::class.java.isAssignableFrom(ArrayList::class.java) } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/issues/kt-5294.kt b/nj2k/testData/newJ2k/issues/kt-5294.kt index be64ffaa7cb..d5baa90f4cd 100644 --- a/nj2k/testData/newJ2k/issues/kt-5294.kt +++ b/nj2k/testData/newJ2k/issues/kt-5294.kt @@ -1,4 +1,5 @@ -internal class X(private val list: MutableList) { +internal class X(private val list: List) { internal inner class Y + } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/methodCallExpression/specialBuiltinMembers.kt b/nj2k/testData/newJ2k/methodCallExpression/specialBuiltinMembers.kt index d65726ef927..1cd5ab3eea2 100644 --- a/nj2k/testData/newJ2k/methodCallExpression/specialBuiltinMembers.kt +++ b/nj2k/testData/newJ2k/methodCallExpression/specialBuiltinMembers.kt @@ -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 internal enum class E { A, B, C } @@ -15,7 +14,7 @@ internal class A { val i = map.entries.iterator().next().key + 1 } - fun bar(list: MutableList, map: HashMap) { + fun bar(list: MutableList, map: HashMap) { val c = "a"[0] val b = 10.toByte() val i = 10.1.toInt() diff --git a/nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java b/nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java new file mode 100644 index 00000000000..07e7a5c7ed8 --- /dev/null +++ b/nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java @@ -0,0 +1,17 @@ +import java.util.Iterator; + +public class TestMutableIterator implements Iterator { + @Override + public boolean hasNext() { + return false; + } + + @Override + public String next() { + return null; + } + + @Override + public void remove() { + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.java b/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.java new file mode 100644 index 00000000000..e3ff48e067d --- /dev/null +++ b/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.java @@ -0,0 +1,11 @@ +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class Test { + List> list = new ArrayList<>(); + + public void test() { + list.get(0).add(1) + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt b/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt new file mode 100644 index 00000000000..14c3802c195 --- /dev/null +++ b/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt @@ -0,0 +1,8 @@ +import java.util.ArrayList + +class Test { + internal var list: List> = ArrayList() + fun test() { + list[0].add(1) + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.java b/nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.java new file mode 100644 index 00000000000..8b0ac6447b1 --- /dev/null +++ b/nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.java @@ -0,0 +1,12 @@ +import java.util.ArrayList; +import java.util.List; + +public class Owner { + public List list = new ArrayList<>(); +} + +public class Updater { + public void update(Owner owner) { + owner.list.add(""); + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.kt b/nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.kt new file mode 100644 index 00000000000..0716cbf30c0 --- /dev/null +++ b/nj2k/testData/newJ2k/mutableCollections/mutableListInOtherClass.kt @@ -0,0 +1,11 @@ +import java.util.ArrayList + +class Owner { + var list: MutableList = ArrayList() +} + +class Updater { + fun update(owner: Owner) { + owner.list.add("") + } +} diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java index 329ee967723..3363095fcca 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java @@ -1376,6 +1376,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew 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") public void testComments() throws Exception { runTest("nj2k/testData/newJ2k/detectProperties/Comments.java"); @@ -3628,6 +3633,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew 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") public void testOverrides() throws Exception { runTest("nj2k/testData/newJ2k/mutableCollections/Overrides.java"); diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/AbstractCommonConstraintCollectorTest.kt b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/AbstractCommonConstraintCollectorTest.kt index 7f3e92b1511..d413122bcb4 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/AbstractCommonConstraintCollectorTest.kt +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/AbstractCommonConstraintCollectorTest.kt @@ -17,7 +17,7 @@ abstract class AbstractCommonConstraintCollectorTest : AbstractConstraintCollect override fun createInferenceFacade(resolutionFacade: ResolutionFacade): InferenceFacade = InferenceFacade( object : ContextCollector(resolutionFacade) { - override fun ClassReference.getState(typeElement: KtTypeElement?): State? = + override fun ClassReference.getState(typeElement: KtTypeElement?): State = State.UNKNOWN }, ConstraintsCollectorAggregator( diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/CommonConstraintCollectorTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/CommonConstraintCollectorTestGenerated.java index 42eb3a6058d..af41271a913 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/CommonConstraintCollectorTestGenerated.java +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/common/CommonConstraintCollectorTestGenerated.java @@ -134,6 +134,11 @@ public class CommonConstraintCollectorTestGenerated extends AbstractCommonConstr 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") public void testReturnFromLambda() throws Exception { runTest("nj2k/testData/inference/common/returnFromLambda.kt"); diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/AbstractMutabilityInferenceTest.kt b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/AbstractMutabilityInferenceTest.kt new file mode 100644 index 00000000000..ec64ebbe081 --- /dev/null +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/AbstractMutabilityInferenceTest.kt @@ -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()) { + if (typeReference.parent is KtConstructorCalleeExpression) continue + typeReference.updateMutability() + } + deleteComments() + } + + override fun getProjectDescriptor() = + descriptorByFileDirective(File(testDataPath, fileName()), isAllFilesPresentInTest()) +} \ No newline at end of file diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityInferenceTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityInferenceTestGenerated.java new file mode 100644 index 00000000000..d8f0a57cc6f --- /dev/null +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/mutability/MutabilityInferenceTestGenerated.java @@ -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"); + } +} diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/nullability/AbstractNullabilityInferenceTest.kt b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/nullability/AbstractNullabilityInferenceTest.kt index cf5a2eabbb5..fa9487876f4 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/nullability/AbstractNullabilityInferenceTest.kt +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/inference/nullability/AbstractNullabilityInferenceTest.kt @@ -26,7 +26,7 @@ abstract class AbstractNullabilityInferenceTest : AbstractConstraintCollectorTes val typeEnhancer = NullabilityBoundTypeEnhancer(resolutionFacade) return InferenceFacade( object : ContextCollector(resolutionFacade) { - override fun ClassReference.getState(typeElement: KtTypeElement?): State? = + override fun ClassReference.getState(typeElement: KtTypeElement?): State = State.UNKNOWN }, ConstraintsCollectorAggregator(