New J2K: use nullable type for unknown for public declarations & prepare for mutability inference
#KT-32518 fixed
This commit is contained in:
@@ -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>
|
||||
|
||||
+33
-27
@@ -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
|
||||
}
|
||||
|
||||
+22
@@ -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()
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+36
-22
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -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
|
||||
}
|
||||
+2
-1
@@ -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()
|
||||
}
|
||||
+3
-3
@@ -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()
|
||||
|
||||
+27
-47
@@ -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
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.inference.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
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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
|
||||
}
|
||||
}
|
||||
+6
-22
@@ -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
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.inference.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
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-21
@@ -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
|
||||
)
|
||||
|
||||
+232
-156
@@ -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
|
||||
|
||||
+2
-1
@@ -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)
|
||||
}
|
||||
|
||||
+3
-2
@@ -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) {
|
||||
|
||||
+3
-1
@@ -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,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
@@ -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'
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1 +1 @@
|
||||
val d2 = arrayOfNulls<IntArray?>(5)
|
||||
val d2 = arrayOfNulls<IntArray>(5)
|
||||
+1
-1
@@ -1 +1 @@
|
||||
val d3 = Array(5) { arrayOfNulls<IntArray?>(5) }
|
||||
val d3 = Array(5) { arrayOfNulls<IntArray>(5) }
|
||||
+1
-1
@@ -1 +1 @@
|
||||
val ss = Array(5) { arrayOfNulls<String?>(5) }
|
||||
val ss = Array(5) { arrayOfNulls<String>(5) }
|
||||
+1
-1
@@ -1 +1 @@
|
||||
val sss = Array(5) { Array(5) { arrayOfNulls<String?>(5) } }
|
||||
val sss = Array(5) { Array(5) { arrayOfNulls<String>(5) } }
|
||||
+1
-1
@@ -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
@@ -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
@@ -1,5 +1,5 @@
|
||||
internal class T {
|
||||
fun main() {}
|
||||
fun i(): Int {}
|
||||
fun s(): String? {}
|
||||
fun s(): String {}
|
||||
}
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -1 +1 @@
|
||||
fun main(): String? {}
|
||||
fun main(): String {}
|
||||
+3
-3
@@ -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
@@ -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)
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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())
|
||||
|
||||
Vendored
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user