New J2K: use nullable type for unknown for public declarations & prepare for mutability inference

#KT-32518 fixed
This commit is contained in:
Ilya Kirillov
2019-08-29 18:18:39 +03:00
parent 0040490daf
commit c28515be59
128 changed files with 784 additions and 609 deletions
@@ -46,7 +46,7 @@ class KtClassBody : KtElementImplStub<KotlinPlaceHolderStub<KtClassBody>>, KtDec
val properties: List<KtProperty>
get() = getStubOrPsiChildrenAsList(KtStubElementTypes.PROPERTY)
val functions: List<KtFunction>
val functions: List<KtNamedFunction>
get() = getStubOrPsiChildrenAsList(KtStubElementTypes.FUNCTION)
val enumEntries: List<KtEnumEntry>
@@ -36,37 +36,41 @@ interface BoundTypeCalculator {
): BoundType
}
class BoundTypeCalculatorImpl(
open class BoundTypeCalculatorImpl(
private val resolutionFacade: ResolutionFacade,
private val enhancer: BoundTypeEnhancer
) : BoundTypeCalculator {
private val cache = mutableMapOf<KtExpression, BoundType>()
override fun expressionsWithBoundType() = cache.toList()
final override fun expressionsWithBoundType() = cache.toList()
override fun KtExpression.boundType(inferenceContext: InferenceContext): BoundType = cache.getOrPut(this) {
final override fun KtExpression.boundType(inferenceContext: InferenceContext): BoundType = cache.getOrPut(this) {
calculateBoundType(inferenceContext, this)
}
private fun calculateBoundType(inferenceContext: InferenceContext, expression: KtExpression): BoundType = when {
expression.isNullExpression() -> BoundType.NULL
expression is KtParenthesizedExpression -> expression.expression?.boundType(inferenceContext)
expression is KtConstantExpression
|| expression is KtStringTemplateExpression
|| expression.node?.elementType == KtNodeTypes.BOOLEAN_CONSTANT
|| expression is KtBinaryExpression ->
BoundType.LITERAL
expression is KtQualifiedExpression -> expression.toBoundTypeAsQualifiedExpression(inferenceContext)
expression is KtBinaryExpressionWithTypeRHS -> expression.toBoundTypeAsCastExpression(inferenceContext)
expression is KtNameReferenceExpression -> expression.toBoundTypeAsReferenceExpression(inferenceContext)
expression is KtCallExpression -> expression.toBoundTypeAsCallableExpression(null, inferenceContext)
expression is KtLambdaExpression -> expression.toBoundTypeAsLambdaExpression(inferenceContext)
expression is KtLabeledExpression -> expression.baseExpression?.boundType(inferenceContext)
expression is KtIfExpression -> expression.toBoundTypeAsIfExpression(inferenceContext)
else -> null
}?.let { boundType ->
enhancer.enhance(expression, boundType, inferenceContext)
} ?: BoundType.LITERAL
open fun interceptCalculateBoundType(inferenceContext: InferenceContext, expression: KtExpression): BoundType? =
null
private fun calculateBoundType(inferenceContext: InferenceContext, expression: KtExpression): BoundType =
interceptCalculateBoundType(inferenceContext, expression) ?: when {
expression.isNullExpression() -> BoundType.NULL
expression is KtParenthesizedExpression -> expression.expression?.boundType(inferenceContext)
expression is KtConstantExpression
|| expression is KtStringTemplateExpression
|| expression.node?.elementType == KtNodeTypes.BOOLEAN_CONSTANT
|| expression is KtBinaryExpression ->
BoundType.LITERAL
expression is KtQualifiedExpression -> expression.toBoundTypeAsQualifiedExpression(inferenceContext)
expression is KtBinaryExpressionWithTypeRHS -> expression.toBoundTypeAsCastExpression(inferenceContext)
expression is KtNameReferenceExpression -> expression.toBoundTypeAsReferenceExpression(inferenceContext)
expression is KtCallExpression -> expression.toBoundTypeAsCallableExpression(null, inferenceContext)
expression is KtLambdaExpression -> expression.toBoundTypeAsLambdaExpression(inferenceContext)
expression is KtLabeledExpression -> expression.baseExpression?.boundType(inferenceContext)
expression is KtIfExpression -> expression.toBoundTypeAsIfExpression(inferenceContext)
else -> null
}?.let { boundType ->
enhancer.enhance(expression, boundType, inferenceContext)
} ?: BoundType.LITERAL
private fun KtIfExpression.toBoundTypeAsIfExpression(inferenceContext: InferenceContext): BoundType? {
val isNullLiteralPossible = then?.isNullExpression() == true || `else`?.isNullExpression() == true
@@ -166,7 +170,7 @@ class BoundTypeCalculatorImpl(
return selectorExpression.toBoundTypeAsCallableExpression(receiverBoundType, inferenceContext)
}
override fun KotlinType.boundType(
final override fun KotlinType.boundType(
typeVariable: TypeVariable?,
contextBoundType: BoundType?,
call: ResolvedCall<*>?,
@@ -220,8 +224,9 @@ class BoundTypeCalculatorImpl(
when {
containingDeclaration == call?.candidateDescriptor?.original -> {
val returnTypeVariable = inferenceContext.typeElementToTypeVariable[
call.call.typeArguments.getOrNull(target.index)?.typeReference?.typeElement ?: return null
] ?: return null
call.call.typeArguments.getOrNull(target.index)?.typeReference?.typeElement
?: return BoundType.STAR_PROJECTION
] ?: return BoundType.STAR_PROJECTION
BoundTypeImpl(
TypeVariableLabel(returnTypeVariable),
returnTypeVariable.typeParameters
@@ -238,8 +243,9 @@ class BoundTypeCalculatorImpl(
// `this` or `super` call case
containingDeclaration == call?.candidateDescriptor.safeAs<ConstructorDescriptor>()?.constructedClass -> {
val returnTypeVariable = inferenceContext.typeElementToTypeVariable[
call?.call?.typeArguments?.getOrNull(target.index)?.typeReference?.typeElement ?: return null
] ?: return null
call?.call?.typeArguments?.getOrNull(target.index)?.typeReference?.typeElement
?: return BoundType.STAR_PROJECTION
] ?: return BoundType.STAR_PROJECTION
BoundTypeImpl(
TypeVariableLabel(returnTypeVariable),
returnTypeVariable.typeParameters
@@ -54,28 +54,8 @@ class LiteralBound private constructor(val state: State) : ConstraintBound() {
}
}
val TypeVariable.constraintBound: TypeVariableBound
get() = TypeVariableBound(this)
val State.constraintBound: LiteralBound
get() = when (this) {
State.LOWER -> LiteralBound.LOWER
State.UPPER -> LiteralBound.UPPER
State.UNKNOWN -> LiteralBound.UNKNOWN
}
val BoundTypeLabel.constraintBound: ConstraintBound?
get() = when (this) {
is TypeVariableLabel -> typeVariable.constraintBound
is TypeParameterLabel -> null
is GenericLabel -> null
StarProjectionLabel -> null
NullLiteralLabel -> LiteralBound.UPPER
LiteralLabel -> LiteralBound.LOWER
}
val BoundType.constraintBound: ConstraintBound?
get() = when (this) {
is BoundTypeImpl -> label.constraintBound
is WithForcedStateBoundType -> forcedState.constraintBound
}
fun State.constraintBound(): LiteralBound = when (this) {
State.LOWER -> LiteralBound.LOWER
State.UPPER -> LiteralBound.UPPER
State.UNKNOWN -> LiteralBound.UNKNOWN
}
@@ -0,0 +1,22 @@
/*
* 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.common
interface ConstraintBoundProvider {
fun TypeVariable.constraintBound(): TypeVariableBound
fun BoundType.constraintBound(): ConstraintBound?
fun BoundTypeLabel.constraintBound(): ConstraintBound?
}
abstract class ConstraintBoundProviderImpl : ConstraintBoundProvider {
final override fun TypeVariable.constraintBound(): TypeVariableBound =
TypeVariableBound(this)
final override fun BoundType.constraintBound(): ConstraintBound? = when (this) {
is BoundTypeImpl -> label.constraintBound()
is WithForcedStateBoundType -> forcedState.constraintBound()
}
}
@@ -13,8 +13,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@Suppress("unused")
class ConstraintBuilder(
private val inferenceContext: InferenceContext,
private val boundTypeCalculator: BoundTypeCalculator
) : BoundTypeCalculator by boundTypeCalculator {
private val boundTypeCalculator: BoundTypeCalculator,
private val constraintBoundProvider: ConstraintBoundProvider
) : BoundTypeCalculator by boundTypeCalculator, ConstraintBoundProvider by constraintBoundProvider {
private val constraints = mutableListOf<Constraint>()
fun TypeVariable.isSubtypeOf(supertype: BoundType, priority: ConstraintPriority) {
@@ -39,7 +40,7 @@ class ConstraintBuilder(
fun KtExpression.isTheSameTypeAs(other: State, priority: ConstraintPriority) {
boundType().label.safeAs<TypeVariableLabel>()?.typeVariable?.let { typeVariable ->
constraints += EqualsConstraint(typeVariable.constraintBound, other.constraintBound, priority)
constraints += EqualsConstraint(typeVariable.constraintBound(), other.constraintBound(), priority)
}
}
@@ -104,8 +105,8 @@ class ConstraintBuilder(
if (typeVariable !in ignoreTypeVariables && other.typeVariable !in ignoreTypeVariables) {
constraints += EqualsConstraint(
constraintBound ?: return,
other.constraintBound ?: return,
constraintBound() ?: return,
other.constraintBound() ?: return,
priority
)
}
@@ -121,8 +122,8 @@ class ConstraintBuilder(
}
constraints += SubtypeConstraint(
constraintBound ?: return,
supertype.constraintBound ?: return,
constraintBound() ?: return,
supertype.constraintBound() ?: return,
priority
)
}
@@ -14,14 +14,15 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class ConstraintsCollectorAggregator(
private val resolutionFacade: ResolutionFacade,
private val collectors: List<ConstraintsCollector>
private val constraintBoundProvider: ConstraintBoundProvider,
val collectors: List<ConstraintsCollector>
) {
fun collectConstraints(
boundTypeCalculator: BoundTypeCalculator,
inferenceContext: InferenceContext,
elements: List<KtElement>
): List<Constraint> {
val constraintsBuilder = ConstraintBuilder(inferenceContext, boundTypeCalculator)
val constraintsBuilder = ConstraintBuilder(inferenceContext, boundTypeCalculator, constraintBoundProvider)
for (element in elements) {
element.forEachDescendantOfType<KtElement> { innerElement ->
if (innerElement.getStrictParentOfType<KtImportDirective>() != null) return@forEachDescendantOfType
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
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
@@ -29,13 +30,13 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
private fun KtTypeReference.classReference(): ClassReference? =
analyze()[BindingContext.TYPE, this]?.classReference()
private fun KtTypeElement.toData(): TypeElementData {
val typeReference = parent as? KtTypeReference ?: return TypeElementDataImpl(this)
val typeParameterDescriptor = analyze(resolutionFacade)[BindingContext.TYPE, typeReference]
?.constructor
?.declarationDescriptor
?.safeAs<TypeParameterDescriptor>() ?: return TypeElementDataImpl(this)
return TypeParameterElementData(this, typeParameterDescriptor)
private fun KtTypeElement.toData(): TypeElementData? {
val typeReference = parent as? KtTypeReference ?: return null
val type = analyze(resolutionFacade)[BindingContext.TYPE, typeReference] ?: return null
val typeParameterDescriptor = type.constructor
.declarationDescriptor
?.safeAs<TypeParameterDescriptor>() ?: return TypeElementDataImpl(this, type)
return TypeParameterElementData(this, type, typeParameterDescriptor)
}
fun collectTypeVariables(elements: List<KtElement>): InferenceContext {
@@ -43,7 +44,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
val typeElementToTypeVariable = mutableMapOf<KtTypeElement, TypeVariable>()
val typeBasedTypeVariables = mutableListOf<TypeBasedTypeVariable>()
fun KtTypeReference.toBoundType(defaultState: State? = null): BoundType? {
fun KtTypeReference.toBoundType(owner: TypeVariableOwner, defaultState: State? = null): BoundType? {
val typeElement = typeElement ?: return null
val classReference = classReference() ?: NoClassReference
@@ -58,9 +59,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
classReference.descriptor.declaredTypeParameters
) { typeArgument, typeParameter ->
TypeParameter(
if (typeArgument == null) {
BoundTypeImpl(StarProjectionLabel, emptyList())
} else typeArgument.toBoundType() ?: BoundType.STAR_PROJECTION,
typeArgument?.toBoundType(owner) ?: BoundType.STAR_PROJECTION,
typeParameter.variance
)
}
@@ -75,7 +74,8 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
val typeVariable = TypeElementBasedTypeVariable(
classReference,
typeArguments,
typeElement.toData(),
typeElement.toData() ?: return null,
owner,
state
)
typeElementToTypeVariable[typeElement] = typeVariable
@@ -116,6 +116,12 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
val substitutors = mutableMapOf<ClassDescriptor, ClassSubstitutor>()
fun isOrAsExpression(typeReference: KtTypeReference) {
val typeElement = typeReference.typeElement ?: return
val typeVariable = typeReference.toBoundType(OtherTarget)?.typeVariable ?: return
typeElementToTypeVariable[typeElement] = typeVariable
}
for (element in elements) {
element.forEachDescendantOfType<KtExpression> { expression ->
if (expression is KtCallableDeclaration
@@ -124,24 +130,31 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
|| expression is KtNamedFunction)
) run {
val typeReference = expression.typeReference ?: return@run
val typeVariable = typeReference.toBoundType()?.typeVariable ?: return@run
val typeVariable = typeReference.toBoundType(
when (expression) {
is KtParameter -> expression.getStrictParentOfType<KtFunction>()?.let(::FunctionParameter)
is KtFunction -> FunctionReturnType(expression)
is KtProperty -> Property(expression)
else -> null
} ?: OtherTarget
)?.typeVariable ?: return@run
declarationToTypeVariable[expression] = typeVariable
}
if (expression is KtTypeParameterListOwner) {
for (typeParameter in expression.typeParameters) {
typeParameter.extendsBound?.toBoundType(defaultState = State.UPPER)
typeParameter.extendsBound?.toBoundType(OtherTarget, defaultState = State.UPPER)
}
for (constraint in expression.typeConstraints) {
constraint.boundTypeReference?.toBoundType(defaultState = State.UPPER)
constraint.boundTypeReference?.toBoundType(OtherTarget, defaultState = State.UPPER)
}
}
when (expression) {
is KtClass -> {
is KtClassOrObject -> {
for (entry in expression.superTypeListEntries) {
for (argument in entry.typeReference?.typeElement?.typeArgumentsAsTypes ?: continue) {
argument.toBoundType()
argument.toBoundType(OtherTarget)
}
}
val descriptor =
@@ -160,7 +173,7 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
}
is KtCallExpression ->
for (typeArgument in expression.typeArguments) {
typeArgument.typeReference?.toBoundType()
typeArgument.typeReference?.toBoundType(TypeArgument)
}
is KtLambdaExpression -> {
val context = expression.analyze(resolutionFacade)
@@ -169,10 +182,11 @@ abstract class ContextCollector(private val resolutionFacade: ResolutionFacade)
declarationToTypeVariable[expression.functionLiteral] = typeVariable
}
is KtBinaryExpressionWithTypeRHS -> {
val typeReference = expression.right ?: return@forEachDescendantOfType
val typeElement = typeReference.typeElement ?: return@forEachDescendantOfType
val typeVariable = typeReference.toBoundType()?.typeVariable ?: return@forEachDescendantOfType
typeElementToTypeVariable[typeElement] = typeVariable
isOrAsExpression(expression.right ?: return@forEachDescendantOfType)
}
is KtIsExpression -> {
isOrAsExpression(expression.typeReference ?: return@forEachDescendantOfType)
}
}
}
@@ -0,0 +1,10 @@
/*
* 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.common
abstract class DefaultStateProvider {
abstract fun defaultStateFor(typeVariable: TypeVariable): State
}
@@ -14,6 +14,7 @@ class InferenceFacade(
private val constraintsCollectorAggregator: ConstraintsCollectorAggregator,
private val boundTypeCalculator: BoundTypeCalculator,
private val stateUpdater: StateUpdater,
private val defaultStateProvider: DefaultStateProvider,
private val renderDebugTypes: Boolean = false,
private val printDebugConstraints: Boolean = false
) {
@@ -22,7 +23,7 @@ class InferenceFacade(
val constraints = constraintsCollectorAggregator.collectConstraints(boundTypeCalculator, inferenceContext, elements)
val initialConstraints = if (renderDebugTypes) constraints.map { it.copy() } else null
Solver(inferenceContext, printDebugConstraints).solveConstraints(constraints)
Solver(inferenceContext, printDebugConstraints, defaultStateProvider).solveConstraints(constraints)
if (renderDebugTypes) {
with(DebugPrinter(inferenceContext)) {
@@ -5,15 +5,15 @@
package org.jetbrains.kotlin.nj2k.inference.common
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class Solver(
private val analysisContext: InferenceContext,
private val printConstraints: Boolean
private val inferenceContext: InferenceContext,
private val printConstraints: Boolean,
private val defaultStateProvider: DefaultStateProvider
) {
private val printer = DebugPrinter(analysisContext)
private val printer = DebugPrinter(inferenceContext)
private fun List<Constraint>.printDebugInfo(step: Int) =
with(printer) {
@@ -24,7 +24,7 @@ internal class Solver(
}
println()
println("type variables:")
for (typeVariable in analysisContext.typeVariables) {
for (typeVariable in inferenceContext.typeVariables) {
println("${typeVariable.name} := ${typeVariable.state}")
}
println("---------------\n")
@@ -55,9 +55,11 @@ internal class Solver(
}
}
if (!somethingChanged) {
val typeVariable = mutableConstraints.getTypeVariableAsEqualsOrUpperBound()
val typeVariable =
mutableConstraints.getTypeVariableAsEqualsOrUpperBound()
?: inferenceContext.typeVariables.firstOrNull { !it.isFixed }
if (typeVariable != null) {
typeVariable.setStateIfNotFixed(State.LOWER)
typeVariable.setStateIfNotFixed(defaultStateProvider.defaultStateFor(typeVariable))
somethingChanged = true
}
}
@@ -142,11 +144,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()
}
if (upper is TypeVariableBound && upper.typeVariable.isFixed) {
somethingChanged = true
constraint.supertype = upper.typeVariable.state.constraintBound
constraint.supertype = upper.typeVariable.state.constraintBound()
}
}
}
@@ -166,14 +168,27 @@ internal class Solver(
}
private fun List<Constraint>.getTypeVariableAsEqualsOrUpperBound(): TypeVariable? =
asSequence().filterIsInstance<SubtypeConstraint>()
.map { it.supertype }
.firstIsInstanceOrNull<TypeVariableBound>()
?.typeVariable
?: asSequence().filterIsInstance<EqualsConstraint>()
.flatMap { sequenceOf(it.left, it.right) }
.firstIsInstanceOrNull<TypeVariableBound>()
?.typeVariable
private fun List<Constraint>.getTypeVariableAsEqualsOrUpperBound(): TypeVariable? {
for (constraint in this) {
when (constraint) {
is SubtypeConstraint -> {
constraint.supertype.safeAs<TypeVariableBound>()
?.typeVariable
?.takeIf { defaultStateProvider.defaultStateFor(it) == State.LOWER }
?.let { return it }
constraint.subtype.safeAs<TypeVariableBound>()
?.typeVariable
?.takeIf { defaultStateProvider.defaultStateFor(it) == State.UPPER }
?.let { return it }
}
is EqualsConstraint -> {
(constraint.left.safeAs<TypeVariableBound>()
?: constraint.right.safeAs())
?.let { return it.typeVariable }
}
}
}
return null
}
}
@@ -5,6 +5,23 @@
package org.jetbrains.kotlin.nj2k.inference.common
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
abstract class StateUpdater {
abstract fun updateStates(inferenceContext: InferenceContext)
fun updateStates(inferenceContext: InferenceContext) {
if (inferenceContext.typeVariables.isEmpty()) return
val deepComparator = Comparator<TypeElementBasedTypeVariable> { o1, o2 ->
if (o1.typeElement.typeElement.isAncestor(o2.typeElement.typeElement)) 1 else -1
}
for (typeVariable in inferenceContext
.typeVariables
.filterIsInstance<TypeElementBasedTypeVariable>()
.sortedWith(deepComparator)
) {
typeVariable.updateState()
}
}
abstract fun TypeElementBasedTypeVariable.updateState()
}
@@ -96,10 +96,10 @@ class CallExpressionConstraintCollector : ConstraintsCollector() {
BoundTypeImpl(
GenericLabel(NoClassReference),//not important as it just a primitive type
emptyList()
) else parameterBoundType.typeParameters[0].boundType
) else parameterBoundType.typeParameters.getOrNull(0)?.boundType
} else parameterBoundType
arguments.arguments.map { argument ->
parameterBoundTypeConsideringVararg to argument
arguments.arguments.mapNotNull { argument ->
parameterBoundTypeConsideringVararg?.let { it to argument }
}
}
}.flatten()
@@ -6,81 +6,61 @@
package org.jetbrains.kotlin.nj2k.inference.common
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.refactoring.isAbstract
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtTypeElement
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.types.KotlinType
sealed class TypeVariable {
abstract val classReference: ClassReference
abstract val typeParameters: List<TypeParameter>
abstract val owner: TypeVariableOwner
abstract var state: State
}
sealed class TypeVariableOwner
class FunctionParameter(val owner: KtFunction) : TypeVariableOwner()
class FunctionReturnType(val function: KtFunction) : TypeVariableOwner()
class Property(val property: KtProperty) : TypeVariableOwner()
object TypeArgument : TypeVariableOwner()
object OtherTarget : TypeVariableOwner()
sealed class TypeElementData {
abstract val typeElement: KtTypeElement
abstract val type: KotlinType
}
data class TypeElementDataImpl(override val typeElement: KtTypeElement) : TypeElementData()
data class TypeElementDataImpl(
override val typeElement: KtTypeElement,
override val type: KotlinType
) : TypeElementData()
data class TypeParameterElementData(
override val typeElement: KtTypeElement,
override val type: KotlinType,
val typeParameterDescriptor: TypeParameterDescriptor
) : TypeElementData()
data class TypeElementBasedTypeVariable(
class TypeElementBasedTypeVariable(
override val classReference: ClassReference,
override val typeParameters: List<TypeParameter>,
val typeElement: TypeElementData,
override val owner: TypeVariableOwner,
override var state: State
) : TypeVariable() {
) : TypeVariable()
//ignore state as it is mutable
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as TypeElementBasedTypeVariable
if (classReference != other.classReference) return false
if (typeParameters != other.typeParameters) return false
if (typeElement != other.typeElement) return false
return true
}
override fun hashCode(): Int {
var result = classReference.hashCode()
result = 31 * result + typeParameters.hashCode()
result = 31 * result + typeElement.hashCode()
return result
}
}
data class TypeBasedTypeVariable(
class TypeBasedTypeVariable(
override val classReference: ClassReference,
override val typeParameters: List<TypeParameter>,
val type: KotlinType,
override var state: State
) : TypeVariable() {
//ignore state as it is mutable
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as TypeBasedTypeVariable
if (classReference != other.classReference) return false
if (typeParameters != other.typeParameters) return false
if (type != other.type) return false
return true
}
override fun hashCode(): Int {
var result = classReference.hashCode()
result = 31 * result + typeParameters.hashCode()
result = 31 * result + type.hashCode()
return result
}
override val owner = OtherTarget
}
val TypeVariable.isFixed: Boolean
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.nj2k.inference.common
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.nj2k.JKElementInfo
import org.jetbrains.kotlin.nj2k.JKElementInfoLabel
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.asLabel
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.nj2k.*
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtTypeElement
import org.jetbrains.kotlin.psi.KtTypeProjection
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun PsiElement.getLabel(): JKElementInfoLabel? =
@@ -28,3 +31,14 @@ fun PsiElement.elementInfo(converterContext: NewJ2kConverterContext): List<JKEle
getLabel()?.let { label ->
converterContext.elementsInfoStorage.getInfoForLabel(label)
}
private fun KtTypeReference.hasUnknownLabel(context: NewJ2kConverterContext, unknownLabel: JKElementInfo) =
getLabel()?.let { label ->
unknownLabel in context.elementsInfoStorage.getInfoForLabel(label).orEmpty()
} ?: false
fun KtTypeElement.hasUnknownLabel(context: NewJ2kConverterContext, unknownLabel: JKElementInfo) =
parent
?.safeAs<KtTypeReference>()
?.hasUnknownLabel(context, unknownLabel) == true
@@ -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.nullability
import org.jetbrains.kotlin.nj2k.inference.common.*
class NullabilityConstraintBoundProvider : ConstraintBoundProviderImpl() {
override fun BoundTypeLabel.constraintBound(): ConstraintBound? = when (this) {
is TypeVariableLabel -> typeVariable.constraintBound()
is TypeParameterLabel -> null
is GenericLabel -> null
StarProjectionLabel -> null
NullLiteralLabel -> LiteralBound.UPPER
LiteralLabel -> LiteralBound.LOWER
}
}
@@ -17,7 +17,7 @@ class NullabilityConstraintsCollector : ConstraintsCollector() {
boundTypeCalculator: BoundTypeCalculator,
inferenceContext: InferenceContext,
resolutionFacade: ResolutionFacade
) = with(boundTypeCalculator) {
) {
when {
element is KtBinaryExpression &&
(element.left?.isNullExpression() == true
@@ -50,6 +50,5 @@ class NullabilityConstraintsCollector : ConstraintsCollector() {
element.right?.isTheSameTypeAs(State.LOWER, ConstraintPriority.USE_AS_RECEIVER)
}
}
Unit
}
}
@@ -8,10 +8,7 @@ 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.ClassReference
import org.jetbrains.kotlin.nj2k.inference.common.ContextCollector
import org.jetbrains.kotlin.nj2k.inference.common.State
import org.jetbrains.kotlin.nj2k.inference.common.getLabel
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
@@ -21,23 +18,10 @@ class NullabilityContextCollector(
resolutionFacade: ResolutionFacade,
private val converterContext: NewJ2kConverterContext
) : ContextCollector(resolutionFacade) {
override fun ClassReference.getState(typeElement: KtTypeElement?): State? {
val hasUndefinedNullabilityLabel = typeElement
?.parent
?.safeAs<KtTypeReference>()
?.hasUndefinedNullabilityLabel(converterContext)
?: false
return when {
typeElement == null -> State.UNKNOWN
hasUndefinedNullabilityLabel -> State.UNKNOWN
typeElement is KtNullableType -> State.UPPER
else -> State.LOWER
}
override fun ClassReference.getState(typeElement: KtTypeElement?): State? = when {
typeElement == null -> State.UNKNOWN
typeElement.hasUnknownLabel(converterContext, UnknownNullability) -> State.UNKNOWN
typeElement is KtNullableType -> State.UPPER
else -> State.LOWER
}
private fun KtTypeReference.hasUndefinedNullabilityLabel(context: NewJ2kConverterContext) =
getLabel()?.let { label ->
context.elementsInfoStorage.getInfoForLabel(label).orEmpty().contains(UnknownNullability)
} ?: false
}
@@ -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.nullability
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.refactoring.isAbstract
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.nj2k.inference.common.*
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
class NullabilityDefaultStateProvider : DefaultStateProvider() {
override fun defaultStateFor(typeVariable: TypeVariable): State {
if (typeVariable is TypeElementBasedTypeVariable
&& typeVariable.typeElement.type.constructor.declarationDescriptor is TypeParameterDescriptor
) {
return State.LOWER
}
return when (val owner = typeVariable.owner) {
is FunctionParameter -> if (owner.owner.isPrivate()) State.LOWER else State.UPPER
is FunctionReturnType ->
if (owner.function.isAbstract()
|| owner.function.hasModifier(KtTokens.OPEN_KEYWORD)
|| owner.function.bodyExpression == null
) State.UPPER else State.LOWER
is Property -> if (owner.property.isPrivate()
|| !owner.property.isVar
|| !owner.property.isLocal
) State.LOWER else State.UPPER
is TypeArgument -> State.LOWER
OtherTarget -> State.UPPER
}
}
}
@@ -12,27 +12,14 @@ import org.jetbrains.kotlin.psi.KtTypeElement
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
class NullabilityStateUpdater : StateUpdater() {
override fun updateStates(inferenceContext: InferenceContext) {
if (inferenceContext.typeVariables.isEmpty()) return
val deepComparator = Comparator<TypeElementBasedTypeVariable> { o1, o2 ->
if (o1.typeElement.typeElement.isAncestor(o2.typeElement.typeElement)) 1 else -1
}
for (typeVariable in inferenceContext
.typeVariables
.filterIsInstance<TypeElementBasedTypeVariable>()
.sortedWith(deepComparator)
) {
when (typeVariable.state) {
State.LOWER -> typeVariable.changeState(toNullable = false)
State.UPPER -> typeVariable.changeState(toNullable = true)
State.UNKNOWN -> {
if (typeVariable.typeElement is TypeParameterElementData) {
typeVariable.changeState(toNullable = false)
} else {
typeVariable.changeState(toNullable = true)
}
}
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)
}
}
}
@@ -238,6 +238,13 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
NamedPostProcessingGroup(
"Inferring declarations nullability",
listOf(
InspectionLikeProcessingGroup(
processings = listOf(
VarToValProcessing(),
generalInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false))
),
runSingleTime = true
),
nullabilityProcessing,
clearUndefinedLabelsProcessing
)
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.readWriteAccess
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.j2k.getContainingClass
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.asGetterName
@@ -35,8 +37,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.util.isJavaDescriptor
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
@@ -108,7 +112,6 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
}
}
private fun KtElement.forAllUsages(action: (KtElement) -> Unit) {
usages().forEach { action(it.element as KtElement) }
}
@@ -129,13 +132,12 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
val ktGetter = factory.createGetter(body, getter.modifiersText)
ktGetter.filterModifiers()
return property.add(ktGetter).cast<KtPropertyAccessor>().let {
return property.add(ktGetter).cast<KtPropertyAccessor>().also {
if (getter is RealGetter) {
getter.function.forAllUsages { usage ->
usage.getStrictParentOfType<KtCallExpression>()!!.replace(factory.createExpression(getter.name))
}
}
it
}
}
@@ -270,9 +272,15 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
override fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) {
val classes = elements.descendantsOfType<KtClassOrObject>().sortedByInheritance()
for (klass in classes) {
convertClass(klass)
val classes = elements
.descendantsOfType<KtClassOrObject>()
.sortedByInheritance()
val collectingState = CollectingState()
val classesWithPropertiesData = classes.map { klass ->
klass to klass.collectPropertiesData(collectingState)
}
for ((klass, propertiesData) in classesWithPropertiesData) {
convertClass(klass, propertiesData)
}
}
@@ -287,8 +295,82 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
else -> false
}
private fun KtClassOrObject.collectGettersAndSetters(factory: KtPsiFactory): List<PropertyWithAccessors> {
val classDescriptor = resolveToDescriptorIfAny() ?: return emptyList()
private fun calculatePropertyType(getterType: KotlinType?, setterType: KotlinType?): KotlinType? = when {
getterType != null && getterType.isMarkedNullable -> getterType
setterType != null && setterType.isMarkedNullable -> setterType
else -> getterType ?: setterType
}
private fun calculatePropertyType(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? {
val getterType = getter?.resolveToDescriptorIfAny()?.returnType
val setterType = setter?.resolveToDescriptorIfAny()?.valueParameters?.singleOrNull()?.type
return calculatePropertyType(getterType, setterType)
}
private fun calculatePropertyTypeBasedOnSuperDescriptors(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? {
val superGetterType = getter
?.resolveToDescriptorIfAny()
?.overriddenDescriptors
?.firstOrNull()
?.returnType
val superSetterType = setter
?.resolveToDescriptorIfAny()
?.overriddenDescriptors
?.firstOrNull()
?.valueParameters
?.singleOrNull()
?.type
return calculatePropertyType(superGetterType, superSetterType)
}
private fun KtClassOrObject.collectPropertiesData(collectingState: CollectingState): List<PropertyData> {
return declarations
.asSequence()
.mapNotNull { it.asPropertyAccessor() }
.groupBy { it.name.removePrefix("is").decapitalize() }
.values
.mapNotNull { group ->
val realGetter = group.firstIsInstanceOrNull<RealGetter>()
val realSetter = group.firstIsInstanceOrNull<RealSetter>()?.takeIf { setter ->
if (realGetter == null) return@takeIf true
val setterType = setter.function.valueParameters.first().type()
val getterType = realGetter.function.type()
if (setterType == null
|| getterType == null
|| !KotlinTypeChecker.DEFAULT.isSubtypeOf(getterType, setterType)
) {
if (isInterfaceClass()) return@mapNotNull null
false
} else true
}
if (realGetter == null && realSetter == null) return@mapNotNull null
val realProperty = group.firstIsInstanceOrNull<RealProperty>()
val name = realGetter?.name ?: realSetter?.name!!
val superDeclarationOwner = (realGetter?.function ?: realSetter?.function)
?.resolveToDescriptorIfAny()
?.overriddenDescriptors
?.firstOrNull()
?.findPsi()
?.safeAs<KtDeclaration>()
?.containingClassOrObject
collectingState.propertyNameToSuperType[superDeclarationOwner to name]
val type = collectingState.propertyNameToSuperType[superDeclarationOwner to name]
?: calculatePropertyType(
realGetter?.function,
realSetter?.function
) ?: return@mapNotNull null
collectingState.propertyNameToSuperType[this to name] = type
PropertyData(realProperty, realGetter, realSetter, type)
}
}
private fun List<PropertyData>.filterGettersAndSetters(
klass: KtClassOrObject,
factory: KtPsiFactory
): List<PropertyWithAccessors> {
val classDescriptor = klass.resolveToDescriptorIfAny() ?: return emptyList()
val variablesDescriptorsMap =
(listOfNotNull(classDescriptor.getSuperClassNotAny()) + classDescriptor.getSuperInterfaces())
@@ -301,153 +383,135 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
.filterIsInstance<VariableDescriptor>()
.associateBy { it.name.asString() }
return declarations
.asSequence()
.mapNotNull { it.asPropertyAccessor() }
.groupBy { it.name.removePrefix("is").decapitalize() }
.values
.mapNotNull { group ->
val realGetter = group.firstIsInstanceOrNull<RealGetter>()
val realSetter = group.firstIsInstanceOrNull<RealSetter>()?.takeIf { setter ->
if (realGetter == null) return@takeIf true
if (setter.function.valueParameters.first().type()?.makeNotNullable() !=
realGetter.function.type()?.makeNotNullable()
) {
if (isInterfaceClass()) return@mapNotNull null
false
} else true
}
val realProperty = group.firstIsInstanceOrNull<RealProperty>()
if (realGetter == null && realSetter == null) return@mapNotNull null
val name = realGetter?.name ?: realSetter!!.name
val type =
realGetter?.function?.typeReference?.text
?: realSetter?.function?.valueParameters?.first()?.typeReference?.text!!
return mapNotNull { (realProperty, realGetter, realSetter, type) ->
val name = realGetter?.name ?: realSetter!!.name
val typeStringified = type
.takeUnless { it.isError }
?.let {
IdeDescriptorRenderers.SOURCE_CODE.renderType(it)
} ?: realGetter?.function?.typeReference?.text
?: realSetter?.function?.valueParameters?.firstOrNull()?.typeReference?.text!!
if (realSetter != null
&& realGetter != null
&& isInterfaceClass()
&& realSetter.function.hasOverrides() != realGetter.function.hasOverrides()
if (realSetter != null
&& realGetter != null
&& klass.isInterfaceClass()
&& realSetter.function.hasOverrides() != realGetter.function.hasOverrides()
) return@mapNotNull null
if (realSetter != null
&& realGetter != null
&& realSetter.function.hasSuperFunction() != realGetter.function.hasSuperFunction()
) return@mapNotNull null
if (realProperty != null
&& realGetter?.target != null
&& realGetter.target != realProperty.property
&& realProperty.property.hasInitializer()
) return@mapNotNull null
if (realGetter?.function?.hasInvalidSuperDescriptors() == true
|| realSetter?.function?.hasInvalidSuperDescriptors() == true
) return@mapNotNull null
if (realProperty == null) {
if (causesNameConflictInCurrentDeclarationAndItsParents(
name,
classDescriptor.containingDeclaration
)
) return@mapNotNull null
if (realSetter != null
&& realGetter != null
&& realSetter.function.hasSuperFunction() != realGetter.function.hasSuperFunction()
) return@mapNotNull null
if (realProperty != null
&& realGetter?.target != null
&& realGetter.target != realProperty.property
&& realProperty.property.hasInitializer()
) return@mapNotNull null
if (realGetter?.function?.hasInvalidSuperDescriptors() == true
|| realSetter?.function?.hasInvalidSuperDescriptors() == true
) return@mapNotNull null
if (realProperty == null) {
if (causesNameConflictInCurrentDeclarationAndItsParents(
name,
classDescriptor.containingDeclaration
)
) return@mapNotNull null
}
if (realProperty != null && (realGetter != null && realGetter.target == null || realSetter != null && realSetter.target == null)) {
if (!realProperty.property.isPrivate()) return@mapNotNull null
val hasUsages =
realProperty.property.hasUsagesOutsideOf(
containingKtFile,
listOfNotNull(realGetter?.function, realSetter?.function)
)
if (hasUsages) return@mapNotNull null
}
if (realSetter != null && realProperty != null) {
val assignFieldOfOtherInstance = realProperty.property.usages().any { usage ->
val element = usage.safeAs<KtSimpleNameReference>()?.element ?: return@any false
if (!element.readWriteAccess(useResolveForReadWrite = true).isWrite) return@any false
val parent = element.parent
parent is KtQualifiedExpression && !parent.receiverExpression.isReferenceToThis()
}
if (assignFieldOfOtherInstance) return@mapNotNull null
}
if (realGetter != null && realProperty != null) {
val getFieldOfOtherInstanceInGetter = realProperty.property.usages().any { usage ->
val element = usage.safeAs<KtSimpleNameReference>()?.element ?: return@any false
val parent = element.parent
parent is KtQualifiedExpression
&& !parent.receiverExpression.isReferenceToThis()
&& realGetter.function.isAncestor(element)
}
if (getFieldOfOtherInstanceInGetter) return@mapNotNull null
}
val getter = realGetter ?: when {
realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any {
it.safeAs<VariableDescriptor>()?.isVar == true
} == true -> FakeGetter(name, null, "")
variablesDescriptorsMap[name]?.let { variable ->
variable.isVar && variable.containingDeclaration != classDescriptor
} == true ->
FakeGetter(name, factory.createExpression("super.$name"), "")
else -> return@mapNotNull null
}
val mergedProperty =
if (getter is RealGetter
&& getter.target != null
&& getter.target!!.name != getter.name
&& (realSetter == null || realSetter.target != null)
) {
MergedProperty(name, type, realSetter != null, getter.target!!)
} else null
val setter = realSetter ?: when {
realProperty?.property?.isVar == true ->
FakeSetter(name, null, "")
realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any {
it.safeAs<VariableDescriptor>()?.isVar == true
} == true
|| variablesDescriptorsMap[name]?.isVar == true ->
FakeSetter(
name,
factory.createBlock("super.$name = $name"),
""
)
realGetter != null
&& (realProperty != null
&& realProperty.property.visibilityModifierTypeOrDefault() != realGetter.function.visibilityModifierTypeOrDefault()
&& realProperty.property.isVar
|| mergedProperty != null
&& mergedProperty.mergeTo.visibilityModifierTypeOrDefault() != realGetter.function.visibilityModifierTypeOrDefault()
&& mergedProperty.mergeTo.isVar
) ->
FakeSetter(name, null, null)
else -> null
}
val isVar = setter != null
val property = mergedProperty?.copy(isVar = isVar)
?: realProperty?.copy(isVar = isVar)
?: FakeProperty(name, type, isVar)
PropertyWithAccessors(
property,
getter,
setter
)
}
if (realProperty != null && (realGetter != null && realGetter.target == null || realSetter != null && realSetter.target == null)) {
if (!realProperty.property.isPrivate()) return@mapNotNull null
val hasUsages =
realProperty.property.hasUsagesOutsideOf(
klass.containingKtFile,
listOfNotNull(realGetter?.function, realSetter?.function)
)
if (hasUsages) return@mapNotNull null
}
if (realSetter != null && realProperty != null) {
val assignFieldOfOtherInstance = realProperty.property.usages().any { usage ->
val element = usage.safeAs<KtSimpleNameReference>()?.element ?: return@any false
if (!element.readWriteAccess(useResolveForReadWrite = true).isWrite) return@any false
val parent = element.parent
parent is KtQualifiedExpression && !parent.receiverExpression.isReferenceToThis()
}
if (assignFieldOfOtherInstance) return@mapNotNull null
}
if (realGetter != null && realProperty != null) {
val getFieldOfOtherInstanceInGetter = realProperty.property.usages().any { usage ->
val element = usage.safeAs<KtSimpleNameReference>()?.element ?: return@any false
val parent = element.parent
parent is KtQualifiedExpression
&& !parent.receiverExpression.isReferenceToThis()
&& realGetter.function.isAncestor(element)
}
if (getFieldOfOtherInstanceInGetter) return@mapNotNull null
}
val getter = realGetter ?: when {
realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any {
it.safeAs<VariableDescriptor>()?.isVar == true
} == true -> FakeGetter(name, null, "")
variablesDescriptorsMap[name]?.let { variable ->
variable.isVar && variable.containingDeclaration != classDescriptor
} == true ->
FakeGetter(name, factory.createExpression("super.$name"), "")
else -> return@mapNotNull null
}
val mergedProperty =
if (getter is RealGetter
&& getter.target != null
&& getter.target!!.name != getter.name
&& (realSetter == null || realSetter.target != null)
) {
MergedProperty(name, typeStringified, realSetter != null, getter.target!!)
} else null
val setter = realSetter ?: when {
realProperty?.property?.isVar == true ->
FakeSetter(name, null, "")
realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any {
it.safeAs<VariableDescriptor>()?.isVar == true
} == true
|| variablesDescriptorsMap[name]?.isVar == true ->
FakeSetter(
name,
factory.createBlock("super.$name = $name"),
""
)
realGetter != null
&& (realProperty != null
&& realProperty.property.visibilityModifierTypeOrDefault() != realGetter.function.visibilityModifierTypeOrDefault()
&& realProperty.property.isVar
|| mergedProperty != null
&& mergedProperty.mergeTo.visibilityModifierTypeOrDefault() != realGetter.function.visibilityModifierTypeOrDefault()
&& mergedProperty.mergeTo.isVar
) ->
FakeSetter(name, null, null)
else -> null
}
val isVar = setter != null
val property = mergedProperty?.copy(isVar = isVar)
?: realProperty?.copy(isVar = isVar)
?: FakeProperty(name, typeStringified, isVar)
PropertyWithAccessors(
property,
getter,
setter
)
}
}
private fun KtProperty.renameTo(newName: String, factory: KtPsiFactory) {
@@ -466,9 +530,10 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
setName(newName)
}
private fun convertClass(klass: KtClassOrObject) {
private fun convertClass(klass: KtClassOrObject, propertiesData: List<PropertyData>) {
val factory = KtPsiFactory(klass)
val accessors = klass.collectGettersAndSetters(factory)
val accessors = propertiesData.filterGettersAndSetters(klass, factory)
for ((property, getter, setter) in accessors) {
val ktProperty = when (property) {
is RealProperty -> {
@@ -537,6 +602,13 @@ private data class PropertyWithAccessors(
val setter: Setter?
)
private data class PropertyData(
val realProperty: RealProperty?,
val realGetter: RealGetter?,
val realSetter: RealSetter?,
val type: KotlinType
)
private interface PropertyInfo {
val name: String
}
@@ -618,6 +690,10 @@ private data class FakeSetter(
get() = name.fixSetterParameterName()
}
private data class CollectingState(
val propertyNameToSuperType: MutableMap<Pair<KtClassOrObject, String>, KotlinType> = mutableMapOf()
)
private fun String.fixSetterParameterName() =
if (this == KtTokens.FIELD_KEYWORD.value) "value"
else this
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.asAssignment
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierTypeOrDefault
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ConvertToDataClassProcessing : ElementsBasedPostProcessing() {
@@ -64,7 +65,7 @@ class ConvertToDataClassProcessing : ElementsBasedPostProcessing() {
} ?: return@map null
val propertyType = property.type() ?: return@map null
val parameterType = parameter.type() ?: return@map null
if (propertyType != parameterType) return@map null
if (!KotlinTypeChecker.DEFAULT.equalTypes(propertyType, parameterType)) return@map null
parametersUsed += parameter
ConstructorParameterInitialization(property, parameter, assignment)
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.nj2k.postProcessing.resolve
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -55,8 +56,8 @@ class RemoveExplicitPropertyTypeProcessing : ApplicabilityBasedInspectionLikePro
val initializer = element.initializer ?: return false
val withoutExpectedType =
initializer.analyzeInContext(initializer.getResolutionScope()).getType(initializer) ?: return false
val descriptor = element.resolveToDescriptorIfAny() as? CallableDescriptor ?: return false
return withoutExpectedType == descriptor.returnType
val typeBeDescriptor = element.resolveToDescriptorIfAny().safeAs<CallableDescriptor>()?.returnType ?: return false
return KotlinTypeChecker.DEFAULT.equalTypes(withoutExpectedType, typeBeDescriptor)
}
override fun apply(element: KtProperty) {
@@ -54,6 +54,7 @@ val nullabilityProcessing =
NullabilityContextCollector(resolutionFacade, converterContext),
ConstraintsCollectorAggregator(
resolutionFacade,
NullabilityConstraintBoundProvider(),
listOf(
CommonConstraintsCollector(),
CallExpressionConstraintCollector(),
@@ -62,7 +63,8 @@ val nullabilityProcessing =
)
),
BoundTypeCalculatorImpl(resolutionFacade, NullabilityBoundTypeEnhancer(resolutionFacade)),
NullabilityStateUpdater()
NullabilityStateUpdater(),
NullabilityDefaultStateProvider()
)
val elements = if (rangeMarker != null) {
file.elementsInRange(rangeMarker.range ?: return@postProcessing).filterIsInstance<KtElement>()
@@ -14,9 +14,10 @@ sealed class SuperFunctionInfo
data class ExternalSuperFunctionInfo(val descriptor: FunctionDescriptor) : SuperFunctionInfo()
data class InternalSuperFunctionInfo(val label: JKElementInfoLabel) : SuperFunctionInfo()
data class FunctionInfo(val originalDescriptor: FunctionDescriptor, val superFunctions: List<SuperFunctionInfo>) : JKElementInfo
data class FunctionInfo(val superFunctions: List<SuperFunctionInfo>) : JKElementInfo
object UnknownNullability : JKElementInfo
object UnknownMutability : JKElementInfo
inline class JKElementInfoLabel(val label: String) {
fun render(): String = "/*@@$label@@*/"
@@ -6,9 +6,14 @@
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.*
@@ -20,7 +25,7 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
override fun applyToElement(element: JKTreeElement): JKTreeElement {
when (element) {
is JKTypeElement -> addInfoForTypeElement(element)
is JKKtFunction -> addInfoForFunction(element)
is JKMethod -> addInfoForFunction(element)
}
return recurse(element)
@@ -33,24 +38,36 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
) {
context.elementsInfoStorage.addEntry(type, UnknownNullability)
}
if (type.isCollectionType) {
context.elementsInfoStorage.addEntry(type, UnknownMutability)
}
}
}
private fun addInfoForFunction(function: JKKtFunction) {
val psiMethod = function.psi<PsiMethod>() ?: return
val descriptor = psiMethod.getJavaMethodDescriptor() ?: return
val superDescriptorsInfo =
descriptor.overriddenDescriptors.mapNotNull { superDescriptor ->
val superPsi = superDescriptor.original.findPsi()
when (val symbol = context.symbolProvider.symbolsByPsi[superPsi]) {
is JKUniverseMethodSymbol ->
InternalSuperFunctionInfo(
context.elementsInfoStorage.getOrCreateInfoForElement(symbol.target)
)
else -> ExternalSuperFunctionInfo(superDescriptor)
}
private fun addInfoForFunction(function: JKMethod) {
val superMethods = function.superMethods() ?: return
val superDescriptorsInfo = superMethods.map { superDescriptor ->
val superPsi = superDescriptor.original.findPsi()
when (val symbol = context.symbolProvider.symbolsByPsi[superPsi]) {
is JKUniverseMethodSymbol ->
InternalSuperFunctionInfo(context.elementsInfoStorage.getOrCreateInfoForElement(symbol.target))
else -> ExternalSuperFunctionInfo(superDescriptor)
}
context.elementsInfoStorage.addEntry(function, FunctionInfo(descriptor, superDescriptorsInfo))
}
context.elementsInfoStorage.addEntry(function, FunctionInfo(superDescriptorsInfo))
}
private fun JKMethod.superMethods(): Collection<FunctionDescriptor>? {
val psiMethod = psi<PsiMethod>() ?: return null
psiMethod.getJavaMethodDescriptor()?.let { descriptor ->
return descriptor.overriddenDescriptors
}
return psiMethod.findSuperMethods().mapNotNull { superMethod ->
when (superMethod) {
is KtLightMethod -> superMethod.kotlinOrigin?.resolveToDescriptorIfAny()?.safeAs()
else -> superMethod.getJavaMethodDescriptor()
}
}
}
private fun JKType.forAllInnerTypes(action: (JKType) -> Unit) {
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -47,14 +48,13 @@ class StaticMemberAccessConversion(private val context: NewJ2kConverterContext)
)
}
return recurse(element)
}
private fun JKSymbol.isStaticMember(): Boolean {
val target = target
return when (target) {
is PsiModifierListOwner -> target.hasModifier(JvmModifier.STATIC)
is KtElement -> target.parentOfType<KtClassOrObject>()
is KtElement -> target.getStrictParentOfType<KtClassOrObject>()
?.safeAs<KtObjectDeclaration>()
?.isCompanion() == true
is JKTreeElement ->
@@ -22,17 +22,6 @@ import org.jetbrains.kotlin.nj2k.tree.*
import org.jetbrains.kotlin.nj2k.tree.impl.*
class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() {
private val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade {
override val referenceSearcher: ReferenceSearcher
get() = context.converter.converterServices.oldServices.referenceSearcher
override val javaDataFlowAnalyzerFacade: JavaDataFlowAnalyzerFacade
get() = context.converter.converterServices.oldServices.javaDataFlowAnalyzerFacade
override val resolverForConverter: ResolverForConverter
get() = context.converter.converterServices.oldServices.resolverForConverter
override fun inConversionScope(element: PsiElement): Boolean = context.inConversionContext(element)
})
override fun applyToElement(element: JKTreeElement): JKTreeElement {
return when (element) {
is JKTypeElement -> {
@@ -62,8 +51,7 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
}
)
}
val typeParametersCount = classSymbol.expectedTypeParametersCount()
return when (typeParametersCount) {
return when (val typeParametersCount = classSymbol.expectedTypeParametersCount()) {
0 -> this
else -> JKTypeArgumentListImpl(List(typeParametersCount) {
JKTypeElementImpl(
@@ -124,7 +112,7 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol {
if (this is JKUniverseClassSymbol) return this
val newFqName = typeElement?.let { kotlinCollectionClassName(it) }
val newFqName = kotlinCollectionClassName()
?: kotlinStandardType()
?: fqName
return context.symbolProvider.provideClassSymbol(newFqName)
@@ -137,12 +125,8 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
nullability
)
private fun JKClassSymbol.kotlinCollectionClassName(typeElement: JKTypeElement?): String? {
val isStructureMutable = calculateStructureMutability(typeElement)
return if (isStructureMutable) toKotlinMutableTypesMap[fqName]
else toKotlinTypesMap[fqName]
}
private fun JKClassSymbol.kotlinCollectionClassName(): String? =
toKotlinMutableTypesMap[fqName]
private fun JKClassSymbol.kotlinStandardType(): String? {
if (isKtFunction(fqName)) return fqName
@@ -157,16 +141,6 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
)
}
private fun calculateStructureMutability(typeElement: JKTypeElement?): Boolean {
val parent = typeElement?.parent ?: return false
val psi = parent.psi ?: return false
return when (parent) {
is JKVariable -> typeFlavorCalculator.variableMutability(psi as PsiVariable) == Mutability.Mutable
is JKMethod -> typeFlavorCalculator.methodMutability(psi as PsiMethod) == Mutability.Mutable
else -> false
}
}
companion object {
private val ktFunctionRegex = "kotlin\\.jvm\\.functions\\.Function\\d+".toRegex()
private fun isKtFunction(fqName: String) =
@@ -357,11 +357,12 @@ fun JKType.arrayFqName(): String =
else KotlinBuiltIns.FQ_NAMES.array.asString()
fun JKClassSymbol.isArrayType(): Boolean =
fqName in
JKJavaPrimitiveTypeImpl.KEYWORD_TO_INSTANCE.values
.filterIsInstance<JKJavaPrimitiveType>()
.map { PrimitiveType.valueOf(it.jvmPrimitiveType.name).arrayTypeFqName.asString() } +
KotlinBuiltIns.FQ_NAMES.array.asString()
fqName in arrayFqNames
private val arrayFqNames = JKJavaPrimitiveTypeImpl.KEYWORD_TO_INSTANCE.values
.filterIsInstance<JKJavaPrimitiveType>()
.map { PrimitiveType.valueOf(it.jvmPrimitiveType.name).arrayTypeFqName.asString() } +
KotlinBuiltIns.FQ_NAMES.array.asString()
fun JKType.isArrayType() =
when (this) {
@@ -370,6 +371,18 @@ fun JKType.isArrayType() =
else -> false
}
val JKType.isCollectionType: Boolean
get() = safeAs<JKClassType>()?.classReference?.fqName in collectionFqNames
private val collectionFqNames = setOf(
KotlinBuiltIns.FQ_NAMES.mutableIterator.asString(),
KotlinBuiltIns.FQ_NAMES.mutableList.asString(),
KotlinBuiltIns.FQ_NAMES.mutableCollection.asString(),
KotlinBuiltIns.FQ_NAMES.mutableSet.asString(),
KotlinBuiltIns.FQ_NAMES.mutableMap.asString(),
KotlinBuiltIns.FQ_NAMES.mutableMapEntry.asString(),
KotlinBuiltIns.FQ_NAMES.mutableListIterator.asString()
)
fun JKType.arrayInnerType(): JKType? =
when (this) {
@@ -32,6 +32,10 @@ fun String.asSetterName() =
?.decapitalize()
?.escaped()
fun String.isPossiblyGetterOrSetterName() =
asGetterName() != null || asSetterName() != null
private val KEYWORDS = KtTokens.KEYWORDS.types.map { (it as KtKeywordToken).value }.toSet()
fun String.escaped() =
+1 -1
View File
@@ -1,6 +1,6 @@
class Test {
fun foo() {
val ss = Array</*T2@*/Array</*T1@*/String?>>(5/*LIT*/, { arrayOfNulls</*T0@*/String?>(5/*LIT*/)/*Array<T0@String!!U>!!L*/ }/*Function0<Int, T3@Array<T4@String>>!!L*/)
val ss = Array</*T2@*/Array</*T1@*/String?>>(5/*LIT*/, { arrayOfNulls</*T0@*/String>(5/*LIT*/)/*Array<T0@String!!U>!!L*/ }/*Function0<Int, T3@Array<T4@String>>!!L*/)
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
fun test() {
val x: /*T2@*/Array</*T1@*/Int?> = arrayOfNulls</*T0@*/Int?>(10/*LIT*/)/*Array<T0@Int!!U>!!L*/
val x: /*T2@*/Array</*T1@*/Int?> = arrayOfNulls</*T0@*/Int>(10/*LIT*/)/*Array<T0@Int!!U>!!L*/
}
//T1 := UPPER due to 'INITIALIZER'
+2 -2
View File
@@ -1,5 +1,5 @@
open class A<T> {
open fun foo(): /*T3@*/Map</*T0@*/T, /*T2@*/List</*T1@*/T>>? {
open fun foo(): /*T3@*/Map</*T0@*/T, /*T2@*/List</*T1@*/T>?>? {
TODO()
}
@@ -9,7 +9,7 @@ open class A<T> {
}
class B : A</*T10@*/Int>() {
override fun foo(): /*T8@*/Map</*T5@*/Int, /*T7@*/List</*T6@*/Int>>? {
override fun foo(): /*T8@*/Map</*T5@*/Int, /*T7@*/List</*T6@*/Int>?>? {
return null/*NULL!!U*/
}
override fun bar(): /*T9@*/Int {
+1 -1
View File
@@ -1,4 +1,4 @@
fun b(m: /*T2@*/Map</*T0@*/Int, /*T1@*/String>): /*T3@*/String? {
fun b(m: /*T2@*/Map</*T0@*/Int?, /*T1@*/String?>): /*T3@*/String? {
return m/*T2@Map<T0@Int, T1@String>*/.get(42/*LIT*/)/*T1@String!!U*/
}
@@ -1,4 +1,4 @@
fun <T, E, F, S> foo(x: /*T0@*/T, y: /*T2@*/List</*T1@*/E>, z: /*T4@*/List</*T3@*/F>, a: /*T5@*/S) {}
fun <T, E, F, S> foo(x: /*T0@*/T, y: /*T2@*/List</*T1@*/E>?, z: /*T4@*/List</*T3@*/F>?, a: /*T5@*/S) {}
fun bar() {
val lst: /*T8@*/List</*T7@*/Int?> = listOf</*T6@*/Int?>(null/*NULL!!U*/)/*List<T6@Int>!!L*/
+5 -5
View File
@@ -1,6 +1,6 @@
fun notNullParameters(f: /*T3@*/Function2</*T0@*/Int, /*T1@*/Int, /*T2@*/String>) {}
fun nullableParameter(f: /*T7@*/Function2</*T4@*/Int?, /*T5@*/Int, /*T6@*/String>) {}
fun nullableReturnType(f: /*T11@*/Function2</*T8@*/Int, /*T9@*/Int, /*T10@*/String?>) {}
fun notNullParameters(f: /*T3@*/Function2</*T0@*/Int, /*T1@*/Int, /*T2@*/String?>?) {}
fun nullableParameter(f: /*T7@*/Function2</*T4@*/Int?, /*T5@*/Int?, /*T6@*/String?>?) {}
fun nullableReturnType(f: /*T11@*/Function2</*T8@*/Int, /*T9@*/Int?, /*T10@*/String?>?) {}
fun test() {
@@ -8,11 +8,11 @@ fun test() {
if (i/*T12@Int*/ < 10/*LIT*//*LIT*/ && j/*T13@Int*/ > 0/*LIT*//*LIT*//*LIT*/) ""/*LIT*/ else ""/*LIT*/
}/*Function2<T12@Int, T13@Int, T18@String>!!L*/)
nullableParameter({ i: /*T14@*/Int?, j: /*T15@*/Int ->
nullableParameter({ i: /*T14@*/Int?, j: /*T15@*/Int? ->
if (i/*T14@Int*/ == null/*LIT*/) ""/*LIT*/ else ""/*LIT*/
}/*Function2<T14@Int, T15@Int, T19@String>!!L*/)
nullableReturnType({ i: /*T16@*/Int, j: /*T17@*/Int ->
nullableReturnType({ i: /*T16@*/Int, j: /*T17@*/Int? ->
if (i/*T16@Int*/ < 10/*LIT*//*LIT*/) return@nullableReturnType null/*NULL!!U*/
return@nullableReturnType "nya"/*LIT*/
}/*Function2<T16@Int, T17@Int, T20@String>!!L*/)
+1 -1
View File
@@ -7,7 +7,7 @@ import java.util.stream.Stream
fun test(list: /*T1@*/List</*T0@*/String>) {
val x: /*T9@*/List</*T8@*/String> = list/*T1@List<T0@String>*/.stream()/*Stream<T0@String>!!L*/
.map</*T3@*/String>({ x: /*T2@*/String -> x/*T2@String*/ + ""/*LIT*//*LIT*/ }/*Function1<T2@String, T10@String>!!L*/)/*Stream<T3@String>*/
.collect</*T6@*/List</*T5@*/String>, /*T7@*/Any?>(Collectors/*LIT*/.toList</*T4@*/String>()/*Collector<T4@String, Any, MutableList<T4@String>>*/)/*T6@List<T5@String>*/
.collect</*T6@*/List</*T5@*/String>, /*T7@*/Any>(Collectors/*LIT*/.toList</*T4@*/String>()/*Collector<T4@String, Any, MutableList<T4@String>>*/)/*T6@List<T5@String>*/
}
+2 -2
View File
@@ -1,7 +1,7 @@
class Test {
fun foo1(r: /*T2@*/Function1</*T0@*/Int, /*T1@*/String?>) {}
fun foo1(r: /*T2@*/Function1</*T0@*/Int, /*T1@*/String?>?) {}
fun foo() {
foo1({ x: /*T3@*/Int -> ""/*LIT*/ }/*Function1<T3@Int, T5@String>!!L*/)
foo1({ x: /*T3@*/Int? -> ""/*LIT*/ }/*Function1<T3@Int, T5@String>!!L*/)
foo1({ i: /*T4@*/Int ->
if (i/*T4@Int*/ > 1/*LIT*//*LIT*/) {
return@foo1 null/*NULL!!U*/
+2 -2
View File
@@ -1,5 +1,5 @@
fun test(a: /*T1@*/List</*T0@*/Int>) {
for (i: /*T2@*/Int in a/*T1@List<T0@Int>*/) {
fun test(a: /*T1@*/List</*T0@*/Int?>) {
for (i: /*T2@*/Int? in a/*T1@List<T0@Int>*/) {
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
fun bar(map: /*T2@*/HashMap</*T0@*/String?, /*T1@*/Int>, list1: /*T4@*/List</*T3@*/Int>, list2: /*T6@*/List</*T5@*/String?>) {
fun bar(map: /*T2@*/HashMap</*T0@*/String?, /*T1@*/Int>, list1: /*T4@*/List</*T3@*/Int?>, list2: /*T6@*/List</*T5@*/String?>) {
for (entry: /*T9@*/MutableMap.MutableEntry</*T7@*/String?, /*T8@*/Int> in map/*T2@HashMap<T0@String, T1@Int>*/.entries/*MutableSet<MutableEntry<T0@String, T1@Int>>*/) {
val value: /*T10@*/Int = entry/*T9@MutableEntry<T7@String, T8@Int>*/.value/*T8@Int*/
if (entry/*T9@MutableEntry<T7@String, T8@Int>*/.key/*T7@String*/ == null/*LIT*/) {
@@ -1,7 +1,7 @@
fun a(lst: /*T1@*/List</*T0@*/String>) {
val newList: /*T8@*/List</*T7@*/Int> = lst/*T1@List<T0@String>*/
.asSequence</*T2@*/String>()/*Sequence<T2@String>!!L*/
.map</*T4@*/String, /*T5@*/Int>({ x: /*T3@*/String -> 1/*LIT*/ }/*Function1<T3@String, T9@Int>!!L*/)/*Sequence<T5@Int>!!L*/
.map</*T4@*/String, /*T5@*/Int>({ x: /*T3@*/String? -> 1/*LIT*/ }/*Function1<T3@String, T9@Int>!!L*/)/*Sequence<T5@Int>!!L*/
.toList</*T6@*/Int>()/*List<T6@Int>!!L*/
}
@@ -1,5 +1,5 @@
open class A<T> {
open fun foo(): /*T3@*/Map</*T0@*/T, /*T2@*/List</*T1@*/T>> {
open fun foo(): /*T3@*/Map</*T0@*/T, /*T2@*/List</*T1@*/T>?>? {
TODO()
}
@@ -9,7 +9,7 @@ open class A<T> {
}
class B : A</*T9@*/Int>() {
override fun foo(): /*T8@*/Map</*T5@*/Int, /*T7@*/List</*T6@*/Int>> {
override fun foo(): /*T8@*/Map</*T5@*/Int, /*T7@*/List</*T6@*/Int>?>? {
TODO()
}
}
@@ -1,11 +1,11 @@
open class A<T> {
open fun foo(x: /*T1@*/List</*T0@*/T>, y: /*T2@*/Boolean, z: /*T3@*/T) {
open fun foo(x: /*T1@*/List</*T0@*/T>?, y: /*T2@*/Boolean?, z: /*T3@*/T) {
TODO()
}
}
class B : A</*T8@*/Int>() {
override fun foo(x: /*T5@*/List</*T4@*/Int>, y: /*T6@*/Boolean, z: /*T7@*/Int) {
class B : A</*T8@*/Int?>() {
override fun foo(x: /*T5@*/List</*T4@*/Int?>?, y: /*T6@*/Boolean?, z: /*T7@*/Int?) {
TODO()
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ class Test2 {
}
class Handler {
fun postDelayed(r: Runnable, time: Long) {}
fun postDelayed(r: Runnable?, time: Long) {}
}
class Test3 {
@@ -1 +1 @@
val a = arrayOfNulls<Any?>(10)
val a = arrayOfNulls<Any>(10)
@@ -1 +1 @@
val d2 = arrayOfNulls<IntArray?>(5)
val d2 = arrayOfNulls<IntArray>(5)
@@ -1 +1 @@
val d3 = Array(5) { arrayOfNulls<IntArray?>(5) }
val d3 = Array(5) { arrayOfNulls<IntArray>(5) }
+1 -1
View File
@@ -1 +1 @@
val ss = Array(5) { arrayOfNulls<String?>(5) }
val ss = Array(5) { arrayOfNulls<String>(5) }
+1 -1
View File
@@ -1 +1 @@
val sss = Array(5) { Array(5) { arrayOfNulls<String?>(5) } }
val sss = Array(5) { Array(5) { arrayOfNulls<String>(5) } }
+1 -1
View File
@@ -1,6 +1,6 @@
internal class Test {
fun test() {
val i: Int? = Integer.valueOf(100)
val i = Integer.valueOf(100)
val s: Short = 3
val ss = s
}
+2 -2
View File
@@ -1,8 +1,8 @@
package test
class Integer(s: String) {
class Integer(s: String?) {
companion object {
fun valueOf(value: String): Integer {
fun valueOf(value: String?): Integer {
return Integer(value)
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
internal class T {
fun main() {}
fun i(): Int {}
fun s(): String? {}
fun s(): String {}
}
+1 -1
View File
@@ -4,7 +4,7 @@ import java.util.HashMap
internal class Test {
constructor() {}
constructor(s: String) {}
constructor(s: String?) {}
}
internal class User {
@@ -1,2 +1,2 @@
internal open class Base(o: Any, l: Int)
internal open class Base(o: Any?, l: Int)
internal class C(private val string: String) : Base(string, string.length)
@@ -1,8 +1,6 @@
internal class A @JvmOverloads constructor(nested: Nested = Nested(Nested.FIELD)) {
internal class A @JvmOverloads constructor(nested: Nested? = Nested(Nested.FIELD)) {
internal class Nested(p: Int) {
companion object {
const val FIELD = 0
}
}
@@ -1,6 +1,6 @@
import A.Nested
internal class A @JvmOverloads constructor(nested: Nested = Nested(Nested.FIELD)) {
internal class A @JvmOverloads constructor(nested: Nested? = Nested(Nested.FIELD)) {
internal class Nested(p: Int) {
companion object {
const val FIELD = 0
@@ -2,7 +2,7 @@ package pack
import pack.A.Nested
internal class A @JvmOverloads constructor(nested: Nested = Nested(Nested.FIELD)) {
internal class A @JvmOverloads constructor(nested: Nested? = Nested(Nested.FIELD)) {
internal class Nested(p: Int) {
companion object {
const val FIELD = 0
@@ -2,7 +2,7 @@ package pack
import pack.A.Nested
internal class A @JvmOverloads constructor(nested: Nested = Nested(Nested.FIELD)) {
internal class A @JvmOverloads constructor(nested: Nested? = Nested(Nested.FIELD)) {
internal class Nested(p: Int) {
companion object {
const val FIELD = 0
@@ -1,4 +1,4 @@
internal open class Base(nested: Nested) {
internal open class Base(nested: Nested?) {
internal class Nested(p: Int) {
companion object {
const val FIELD = 0
+2 -4
View File
@@ -10,14 +10,12 @@ class Test {
protected var g = 0.toChar()
constructor() {}
constructor(name: String) {
constructor(name: String?) {
myName = foo(name)
}
companion object {
internal fun foo(n: String): String {
internal fun foo(n: String?): String {
return ""
}
}
+2 -2
View File
@@ -1,9 +1,9 @@
internal class C {
fun equals(c: C): Boolean {
fun equals(c: C?): Boolean {
return false
}
fun foo(c1: C, c2: C): Boolean {
fun foo(c1: C, c2: C?): Boolean {
return c1.equals(c2)
}
}
+2 -2
View File
@@ -1,13 +1,13 @@
import java.util.ArrayList
internal class C {
fun foo1(list: MutableList<String>) {
fun foo1(list: MutableList<String?>) {
for (i in list.indices) {
list[i] = "a"
}
}
fun foo2(list: ArrayList<String>) {
fun foo2(list: ArrayList<String?>) {
for (i in list.indices) {
list[i] = "a"
}
+1 -1
View File
@@ -1,5 +1,5 @@
internal class C {
fun foo(list: MutableList<String>) {
fun foo(list: MutableList<String?>) {
for (i in list.indices) {
list[i] = "a"
}
+1 -1
View File
@@ -1,5 +1,5 @@
internal class A {
var list: List<String>? = null
var list: List<String?>? = null
fun foo() {
for (e in list!!) {
println(e)
+1 -1
View File
@@ -1,2 +1,2 @@
val t: T?
val t: T
get() {}
@@ -11,6 +11,6 @@ internal class Test {
fun nya(): Double {
//TODO explicitlly call apply here
return foo(1, FunctionalI<Int?, Double?> { x: Int -> this.toDouble(x) })
return foo(1, FunctionalI<Int, Double> { x: Int -> this.toDouble(x) })
}
}
@@ -14,6 +14,6 @@ internal class Test {
}
fun nya(): Double {
return foo(1, FunctionalI<Int?, Double?> { x: A -> this.toDouble(x) })
return foo(1, FunctionalI<Int, Double> { x: A -> this.toDouble(x) })
}
}
+9 -9
View File
@@ -1,7 +1,7 @@
class Java8Class {
fun foo0(r: Function0<String>) {}
fun foo1(r: Function1<Int, String?>) {}
fun foo2(r: Function2<Int, Int, String>) {}
fun foo0(r: Function0<String?>?) {}
fun foo1(r: Function1<Int, String?>?) {}
fun foo2(r: Function2<Int?, Int?, String?>?) {}
fun helper() {}
fun foo() {
foo0 { "42" }
@@ -10,8 +10,8 @@ class Java8Class {
helper()
"42"
}
foo1 { i: Int -> "42" }
foo1 { i: Int -> "42" }
foo1 { i: Int? -> "42" }
foo1 { i: Int? -> "42" }
foo1 { i: Int ->
helper()
if (i > 1) {
@@ -19,12 +19,12 @@ class Java8Class {
}
"43"
}
foo2 { i: Int, j: Int -> "42" }
foo2 { i: Int, j: Int ->
foo2 { i: Int?, j: Int? -> "42" }
foo2 { i: Int?, j: Int? ->
helper()
"42"
}
val f = label@{ i: Int, k: Int ->
val f: Function2<Int, Int, String> = label@{ i: Int, k: Int? ->
helper()
if (i > 1) {
return@label "42"
@@ -32,7 +32,7 @@ class Java8Class {
"43"
}
val f1 = label@{ i1: Int, k1: Int ->
val f2 = label@{ i2: Int, k2: Int ->
val f2: Function2<Int, Int, String> = label@{ i2: Int, k2: Int? ->
helper()
if (i2 > 1) {
return@label "42"
+1 -1
View File
@@ -1 +1 @@
fun main(): String? {}
fun main(): String {}
+3 -3
View File
@@ -4,7 +4,7 @@ import java.util.stream.Collectors
object TestLambda {
@JvmStatic
fun main(args: Array<String>) {
val names: List<String> = Arrays.asList("A", "B")
val people: List<Person?> = names.stream().map { name: String -> Person(name) }.collect(Collectors.toList())
val names = Arrays.asList("A", "B")
val people = names.stream().map { name: String? -> Person(name) }.collect(Collectors.toList())
}
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
package demo
internal class Test {
fun test(vararg args: Any) {
fun test(vararg args: Any?) {
var args = args
args = arrayOf(1, 2, 3)
args = arrayOf<Int?>(1, 2, 3)
}
}
@@ -1,2 +1,2 @@
internal open class Base(name: String)
internal class One(name: String, second: String?) : Base(name)
internal open class Base(name: String?)
internal class One(name: String?, second: String?) : Base(name)
@@ -1,2 +1,2 @@
internal open class Base(name: String)
internal class One(name: String, private val mySecond: String) : Base(name)
internal open class Base(name: String?)
internal class One(name: String?, private val mySecond: String) : Base(name)
+1 -1
View File
@@ -1,6 +1,6 @@
class TestReturnsArray {
fun strings(n: Int): Array<String?> {
val result = arrayOfNulls<String?>(n)
val result = arrayOfNulls<String>(n)
for (i in 0 until n) {
result[i] = Integer.toString(i)
}
+2 -2
View File
@@ -2,7 +2,7 @@ class TestMutltipleCtorsWithJavadoc
/**
* Javadoc for 1st ctor
* @param x
*/(private val x: String) {
*/(private val x: String?) {
private var y: String? = null
// ---
@@ -14,7 +14,7 @@ class TestMutltipleCtorsWithJavadoc
* @param x
* @param y
*/
constructor(x: String, y: String?) : this(x) {
constructor(x: String?, y: String?) : this(x) {
this.y = y
}
+1 -1
View File
@@ -3,7 +3,7 @@ package test
import java.util.HashMap
class TestPrimitiveFromMap {
fun foo(map: HashMap<String, Int>): Int {
fun foo(map: HashMap<String?, Int?>): Int {
return map["zzz"]!!
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
package test
class TestMapGetAsReceiver {
fun foo(map: Map<String, String>): Int {
fun foo(map: Map<String?, String>): Int {
return map["zzz"]!!.length
}
}
+2 -2
View File
@@ -1,9 +1,9 @@
package test
class TestValReassign(private val s1: String) {
class TestValReassign(private val s1: String?) {
private var s2: String? = null
constructor(s1: String, s2: String?) : this(s1) {
constructor(s1: String?, s2: String?) : this(s1) {
this.s2 = s2
}
+2 -2
View File
@@ -3,13 +3,13 @@ class TestToStringReturnsNullable {
var string: String? = null
}
open class Ctor(string: String) : Base() {
open class Ctor(string: String?) : Base() {
init {
this.string = string
}
}
class Derived(string: String) : Ctor(string) {
class Derived(string: String?) : Ctor(string) {
override fun toString(): String {
return string!!
}
+1 -1
View File
@@ -6,7 +6,7 @@ class TestJavaExpectedTypeInference {
fun test(node: DefaultMutableTreeNode) {
val e: Enumeration<DefaultMutableTreeNode> = node.children()
while (e.hasMoreElements()) {
val child: DefaultMutableTreeNode = e.nextElement()
val child = e.nextElement()
val name = child.userObject as String
println(name)
}
+2 -2
View File
@@ -1,11 +1,11 @@
import java.util.ArrayList
internal interface FooInterface {
fun foo(): ArrayList<out Foo.SomeClass>?
fun foo(): ArrayList<out Foo.SomeClass?>?
}
class Foo : FooInterface {
override fun foo(): ArrayList<SomeClass>? {
override fun foo(): ArrayList<SomeClass?>? {
return null
}
+1 -1
View File
@@ -5,6 +5,6 @@ internal class Test {
fun context() {
val items: MutableList<Double> = ArrayList()
items.add(1.0)
items.forEach(Consumer { o: Double -> println(o) })
items.forEach(Consumer { o: Double? -> println(o) })
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
internal class X(private val list: List<Y>) {
internal class X(private val list: MutableList<Y>) {
internal inner class Y
}
+1 -3
View File
@@ -1,12 +1,10 @@
package demo
internal class Test {
fun putInt(i: Int) {}
fun putInt(i: Int?) {}
fun test() {
val b: Byte = 10
putInt(b.toInt())
val b2: Byte = 10
putInt(b2.toInt())
}
+1 -2
View File
@@ -1,8 +1,7 @@
package demo
internal class Test {
fun putInt(i: Int) {}
fun putInt(i: Int?) {}
fun test() {
val i = 10
putInt(i)
+1 -1
View File
@@ -1,6 +1,6 @@
package demo
internal class Test(i: Int) {
internal class Test(i: Int?) {
fun test() {
val i = 10
Test(i)
+1 -1
View File
@@ -13,7 +13,7 @@ internal object FileRead {
val fstream = FileInputStream(File("file.txt"))
val `in` = DataInputStream(fstream)
val br = BufferedReader(InputStreamReader(`in`))
var strLine: String
var strLine: String?
while (br.readLine().also { strLine = it } != null) {
println(strLine)
}
+2 -2
View File
@@ -8,9 +8,9 @@ internal object One {
var myContainer = Container()
}
internal class StringContainer(s: String)
internal class StringContainer(s: String?)
internal class Test {
fun putString(s: String) {}
fun putString(s: String?) {}
fun test() {
putString(One.myContainer.myString)
StringContainer(One.myContainer.myString)
+3 -3
View File
@@ -2,12 +2,12 @@ object ArrayNullable {
@JvmStatic
fun main(args: Array<String>) {
val notNull = 0
val a1 = arrayOfNulls<Int?>(2)
val a1 = arrayOfNulls<Int>(2)
a1[0] = null
a1[1] = notNull
println(a1[0])
println(a1[1])
val a2 = arrayOfNulls<Int?>(2)
val a2 = arrayOfNulls<Int>(2)
a2[0] = nullable()
a2[1] = notNull
println(a2[0])
@@ -21,4 +21,4 @@ object ArrayNullable {
fun nullable(): Int? {
return if (System.getProperty("user.home").length > 20) null else 1
}
}
}
+3 -3
View File
@@ -2,12 +2,12 @@ import java.util.stream.Collectors
internal class Test {
fun main(lst: List<String>) {
val toList: List<String> = lst.stream().collect(Collectors.toList())
val toSet: Set<String> = lst.stream().collect(Collectors.toSet())
val toList = lst.stream().collect(Collectors.toList())
val toSet = lst.stream().collect(Collectors.toSet())
val count = lst.stream().count()
val anyMatch = lst.stream().anyMatch { v: String -> v.isEmpty() }
val allMatch = lst.stream().allMatch { v: String -> v.isEmpty() }
val noneMatch = lst.stream().noneMatch { v: String -> v.isEmpty() }
lst.stream().forEach { v: String -> println(v) }
lst.stream().forEach { v: String? -> println(v) }
}
}
+6 -6
View File
@@ -4,23 +4,23 @@ import java.util.stream.Stream
internal class Test {
fun main(lst: List<String>) {
val streamOfList: List<String> = lst.stream()
val streamOfList = lst.stream()
.map { x: String -> x + "e" }
.collect(Collectors.toList())
val streamOfElements: List<Int> = Stream.of(1, 2, 3)
val streamOfElements = Stream.of(1, 2, 3)
.map { x: Int -> x + 1 }
.collect(Collectors.toList())
val array = arrayOf(1, 2, 3)
val streamOfArray: List<Int> = Arrays.stream(array)
val streamOfArray = Arrays.stream(array)
.map { x: Int -> x + 1 }
.collect(Collectors.toList())
val streamOfArray2: List<Int> = Stream.of(*array)
val streamOfArray2 = Stream.of(*array)
.map { x: Int -> x + 1 }
.collect(Collectors.toList())
val streamIterate: List<Int> = Stream.iterate(2, { v: Int -> v * 2 })
val streamIterate = Stream.iterate(2, { v: Int -> v * 2 })
.map { x: Int -> x + 1 }
.collect(Collectors.toList())
val streamGenerate: List<Int> = Stream.generate { 42 }
val streamGenerate = Stream.generate { 42 }
.map { x: Int -> x + 1 }
.collect(Collectors.toList())
}
@@ -3,7 +3,7 @@ import java.util.stream.Stream
internal class Test {
fun main(lst: List<String?>?) {
val stream: Stream<Int> = Stream.of(1)
val list: List<Int> = stream.collect(Collectors.toList())
val stream = Stream.of(1)
val list = stream.collect(Collectors.toList())
}
}
+2 -2
View File
@@ -3,11 +3,11 @@ import java.util.stream.Collectors
internal class Test {
fun main(lst: List<Int>) {
val newLst: List<Int> = /*before list*/lst/*after list*/.stream/*before stream*/()/* after stream*/
val newLst = /*before list*/lst/*after list*/.stream/*before stream*/()/* after stream*/
.filter { x: Int -> x > 10 }
.map { x: Int -> x + 2 }/*some comment*/.distinct/*another comment*/()/* one more comment */.sorted()/*another one comment*/
.sorted(Comparator.naturalOrder())
.peek { x: Int -> println(x) }.limit(1)
.peek { x: Int? -> println(x) }.limit(1)
.skip(42)/*skipped*/
/*collecting one*/.collect/*collecting two */(Collectors.toList())/* cool */
}
+2 -2
View File
@@ -3,14 +3,14 @@ import java.util.stream.Stream
internal class Test {
fun main() {
val activities: List<String> = Stream.of("12")
val activities = Stream.of("12")
.map { v: String -> v + "nya" }
.filter { v: String? -> v != null }
.flatMap { v: String ->
Stream.of(v)
.flatMap { s: String -> Stream.of(s) }
}.filter { v: String ->
val name: String = v.javaClass.name
val name = v.javaClass.name
if (name == "name") {
return@filter false
}
+2 -2
View File
@@ -3,13 +3,13 @@ import java.util.stream.Collectors
internal class Test {
fun main(lst: List<Int>) {
val newLst: List<Int> = lst.stream()
val newLst = lst.stream()
.filter { x: Int -> x > 10 }
.map { x: Int -> x + 2 }
.distinct()
.sorted()
.sorted(Comparator.naturalOrder())
.peek { x: Int -> println(x) }
.peek { x: Int? -> println(x) }
.limit(1)
.skip(42)
.collect(Collectors.toList())
+1 -1
View File
@@ -4,7 +4,7 @@ import java.util.ArrayList
class ForEach {
fun test() {
val xs = ArrayList<Any>()
val ys: MutableList<Any> = LinkedList<Any?>()
val ys: MutableList<Any> = LinkedList<Any>()
for (x in xs) {
ys.add(x)
}
+1 -1
View File
@@ -4,7 +4,7 @@ import java.util.ArrayList
class Lists {
fun test() {
val xs: MutableList<Any?> = ArrayList()
val ys: MutableList<Any?> = LinkedList<Any?>()
val ys: MutableList<Any?> = LinkedList<Any>()
val zs = ArrayList<Any?>()
xs.add(null)
ys.add(null)
+1 -3
View File
@@ -9,10 +9,8 @@ internal class A {
private val d8 = 1.0
private val d9 = 1.0
private val x = 1 / (1.0 + 0)
fun foo1(d: Double) {}
fun foo2(d: Double) {}
fun foo2(d: Double?) {}
fun bar() {
foo1(1.0)
foo1(1.0)
+1 -3
View File
@@ -9,10 +9,8 @@ internal class A {
private val f8 = +1f
private val f9 = 1f
private val f10 = 1f
fun foo1(f: Float) {}
fun foo2(f: Float) {}
fun foo2(f: Float?) {}
fun bar() {
foo1(1f)
foo2(1f)
+1 -3
View File
@@ -7,10 +7,8 @@ internal class A {
private val l6 = -123456789101112
private val l7: Long = +1
private val l8 = +1L
fun foo1(l: Long) {}
fun foo2(l: Long) {}
fun foo2(l: Long?) {}
fun bar() {
foo1(1)
foo1(1L)

Some files were not shown because too many files have changed in this diff Show More