J2K: replace overloads with optional parameters not only for constructors but for methods too
This commit is contained in:
@@ -49,8 +49,12 @@ class ClassBodyConverter(private val psiClass: PsiClass,
|
|||||||
public fun convertBody(): ClassBody {
|
public fun convertBody(): ClassBody {
|
||||||
processAccessorsToDrop()
|
processAccessorsToDrop()
|
||||||
|
|
||||||
|
val overloadReducer = OverloadReducer(psiClass.getMethods().filter { it !in membersToRemove } /* do not allow OverloadReducer to use accessors converted to properties */,
|
||||||
|
isOpenClass,
|
||||||
|
converter.referenceSearcher)
|
||||||
|
|
||||||
val constructorConverter = if (psiClass.getName() != null && !isObject)
|
val constructorConverter = if (psiClass.getName() != null && !isObject)
|
||||||
ConstructorConverter(psiClass, converter, fieldCorrections)
|
ConstructorConverter(psiClass, converter, fieldCorrections, overloadReducer)
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
||||||
@@ -59,8 +63,9 @@ class ClassBodyConverter(private val psiClass: PsiClass,
|
|||||||
if (element is PsiMember) {
|
if (element is PsiMember) {
|
||||||
if (element is PsiAnnotationMethod) continue // converted in convertAnnotationType()
|
if (element is PsiAnnotationMethod) continue // converted in convertAnnotationType()
|
||||||
if (isObject && element.isConstructor()) continue // no constructor in object
|
if (isObject && element.isConstructor()) continue // no constructor in object
|
||||||
|
if (element is PsiMethod && overloadReducer.shouldDropMethod(element)) continue
|
||||||
|
|
||||||
val converted = converter.convertMember(element, membersToRemove, constructorConverter)
|
val converted = converter.convertMember(element, membersToRemove, constructorConverter, overloadReducer)
|
||||||
if (converted != null) {
|
if (converted != null) {
|
||||||
convertedMembers.put(element, converted)
|
convertedMembers.put(element, converted)
|
||||||
}
|
}
|
||||||
@@ -88,7 +93,7 @@ class ClassBodyConverter(private val psiClass: PsiClass,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ClassBody(null, null, convertedMembers.values().toList(), emptyList(), lBrace, rBrace)
|
return ClassBody(null, null, convertedMembers.values().toList(), emptyList(), lBrace, rBrace, overloadReducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
val useCompanionObject = shouldGenerateCompanionObject(convertedMembers)
|
val useCompanionObject = shouldGenerateCompanionObject(convertedMembers)
|
||||||
@@ -123,14 +128,15 @@ class ClassBodyConverter(private val psiClass: PsiClass,
|
|||||||
primaryConstructorSignature = null // no "()" after class name is needed in this case
|
primaryConstructorSignature = null // no "()" after class name is needed in this case
|
||||||
}
|
}
|
||||||
|
|
||||||
return ClassBody(primaryConstructorSignature, constructorConverter?.baseClassParams, members, companionObjectMembers, lBrace, rBrace)
|
return ClassBody(primaryConstructorSignature, constructorConverter?.baseClassParams, members, companionObjectMembers, lBrace, rBrace, overloadReducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Converter.convertMember(member: PsiMember,
|
private fun Converter.convertMember(member: PsiMember,
|
||||||
membersToRemove: MutableSet<PsiMember>,
|
membersToRemove: MutableSet<PsiMember>,
|
||||||
constructorConverter: ConstructorConverter?): Member? {
|
constructorConverter: ConstructorConverter?,
|
||||||
|
overloadReducer: OverloadReducer): Member? {
|
||||||
return when (member) {
|
return when (member) {
|
||||||
is PsiMethod -> convertMethod(member, membersToRemove, constructorConverter, isOpenClass)
|
is PsiMethod -> convertMethod(member, membersToRemove, constructorConverter, overloadReducer, isOpenClass)
|
||||||
is PsiField -> convertField(member, fieldCorrections[member])
|
is PsiField -> convertField(member, fieldCorrections[member])
|
||||||
is PsiClass -> convertClass(member)
|
is PsiClass -> convertClass(member)
|
||||||
is PsiClassInitializer -> convertInitializer(member)
|
is PsiClassInitializer -> convertInitializer(member)
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ import java.util.HashSet
|
|||||||
class ConstructorConverter(
|
class ConstructorConverter(
|
||||||
private val psiClass: PsiClass,
|
private val psiClass: PsiClass,
|
||||||
private val converter: Converter,
|
private val converter: Converter,
|
||||||
private val fieldCorrections: Map<PsiField, FieldCorrectionInfo>
|
private val fieldCorrections: Map<PsiField, FieldCorrectionInfo>,
|
||||||
|
private val overloadReducer: OverloadReducer
|
||||||
) {
|
) {
|
||||||
private val constructors = psiClass.getConstructors()
|
private val constructors = psiClass.getConstructors().asList()
|
||||||
|
|
||||||
private val toTargetConstructorMap = buildToTargetConstructorMap()
|
private val toTargetConstructorMap = buildToTargetConstructorMap()
|
||||||
|
|
||||||
@@ -43,29 +44,12 @@ class ConstructorConverter(
|
|||||||
val candidates = constructors.filter { it !in toTargetConstructorMap }
|
val candidates = constructors.filter { it !in toTargetConstructorMap }
|
||||||
if (candidates.size() != 1) return null // there should be only one constructor which does not call other constructor
|
if (candidates.size() != 1) return null // there should be only one constructor which does not call other constructor
|
||||||
val primary = candidates.single()
|
val primary = candidates.single()
|
||||||
if (toTargetConstructorMap.values().any() { it.constructor != primary }) return null // all other constructors call our candidate (directly or indirectly)
|
if (toTargetConstructorMap.values().any() { it != primary }) return null // all other constructors call our candidate (directly or indirectly)
|
||||||
return primary
|
return primary
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TargetConstructorInfo(
|
private fun buildToTargetConstructorMap(): Map<PsiMethod, PsiMethod> {
|
||||||
/**
|
val toTargetConstructorMap = HashMap<PsiMethod, PsiMethod>()
|
||||||
* Target constructor (one which is finally invoked by this one)
|
|
||||||
*/
|
|
||||||
val constructor: PsiMethod,
|
|
||||||
/**
|
|
||||||
* Is not null if this constructor is equivalent to the target constructor with a few last parameters having default values
|
|
||||||
*/
|
|
||||||
val parameterDefaults: List<PsiExpression>?)
|
|
||||||
|
|
||||||
private val constructorsToDrop = HashSet<PsiMethod>()
|
|
||||||
private val lastParamDefaults = HashMap<PsiMethod, ArrayList<PsiExpression>>() // defaults for a few last parameters in reverse order
|
|
||||||
|
|
||||||
init {
|
|
||||||
dropConstructorsForDefaultValues()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildToTargetConstructorMap(): Map<PsiMethod, TargetConstructorInfo> {
|
|
||||||
val toTargetConstructorMap = HashMap<PsiMethod, TargetConstructorInfo>()
|
|
||||||
for (constructor in constructors) {
|
for (constructor in constructors) {
|
||||||
val firstStatement = constructor.getBody()?.getStatements()?.firstOrNull()
|
val firstStatement = constructor.getBody()?.getStatements()?.firstOrNull()
|
||||||
val methodCall = (firstStatement as? PsiExpressionStatement)?.getExpression() as? PsiMethodCallExpression
|
val methodCall = (firstStatement as? PsiExpressionStatement)?.getExpression() as? PsiMethodCallExpression
|
||||||
@@ -74,25 +58,11 @@ class ConstructorConverter(
|
|||||||
if (refExpr.getCanonicalText() == "this") {
|
if (refExpr.getCanonicalText() == "this") {
|
||||||
val target = refExpr.resolve() as? PsiMethod
|
val target = refExpr.resolve() as? PsiMethod
|
||||||
if (target != null && target.isConstructor()) {
|
if (target != null && target.isConstructor()) {
|
||||||
var parameterDefaults = calcTargetParameterDefaults(constructor, target, methodCall)
|
val finalTarget = toTargetConstructorMap[target] ?: target
|
||||||
|
toTargetConstructorMap[constructor] = finalTarget
|
||||||
val finalTargetInfo = toTargetConstructorMap[target]
|
|
||||||
if (finalTargetInfo != null && parameterDefaults != null) {
|
|
||||||
parameterDefaults = if (finalTargetInfo.parameterDefaults != null)
|
|
||||||
parameterDefaults!! + finalTargetInfo.parameterDefaults
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
|
||||||
val finalTarget = finalTargetInfo?.constructor ?: target
|
|
||||||
|
|
||||||
toTargetConstructorMap[constructor] = TargetConstructorInfo(finalTarget, parameterDefaults)
|
|
||||||
for (entry in toTargetConstructorMap.entrySet()) {
|
for (entry in toTargetConstructorMap.entrySet()) {
|
||||||
if (entry.value.constructor == constructor) {
|
if (entry.value == constructor) {
|
||||||
val newParameterDefaults = if (parameterDefaults != null)
|
entry.setValue(finalTarget)
|
||||||
entry.value.parameterDefaults?.plus(parameterDefaults!!)
|
|
||||||
else
|
|
||||||
null
|
|
||||||
entry.setValue(TargetConstructorInfo(finalTarget, newParameterDefaults))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,61 +72,6 @@ class ConstructorConverter(
|
|||||||
return toTargetConstructorMap
|
return toTargetConstructorMap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calcTargetParameterDefaults(constructor: PsiMethod, target: PsiMethod, targetCall: PsiMethodCallExpression): List<PsiExpression>? {
|
|
||||||
if (constructor.getBody()!!.getStatements().size() != 1) return null // constructor's body should consist of only "this(...)"
|
|
||||||
val parameters = constructor.getParameterList().getParameters()
|
|
||||||
val targetParameters = target.getParameterList().getParameters()
|
|
||||||
if (parameters.size() >= targetParameters.size()) return null
|
|
||||||
val args = targetCall.getArgumentList().getExpressions()
|
|
||||||
if (args.size() != targetParameters.size()) return null // incorrect code
|
|
||||||
|
|
||||||
for (i in parameters.indices) {
|
|
||||||
val parameter = parameters[i]
|
|
||||||
val targetParameter = targetParameters[i]
|
|
||||||
if (parameter.getName() != targetParameter.getName() || parameter.getType() != targetParameter.getType()) return null
|
|
||||||
val arg = args[i]
|
|
||||||
if (arg !is PsiReferenceExpression || arg.resolve() != parameter) return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return args.drop(parameters.size())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dropConstructorsForDefaultValues() {
|
|
||||||
val dropCandidates = toTargetConstructorMap
|
|
||||||
.filter {
|
|
||||||
it.value.parameterDefaults != null
|
|
||||||
&& it.key.accessModifier() == it.value.constructor.accessModifier()
|
|
||||||
&& it.key.getModifierList().getAnnotations().isEmpty() /* do not drop constructors with annotations */
|
|
||||||
}
|
|
||||||
.map { it.key }
|
|
||||||
.sortBy { -it.getParameterList().getParametersCount() } // we will try to drop them starting from ones with more parameters
|
|
||||||
|
|
||||||
@DropCandidatesLoop
|
|
||||||
for (constructor in dropCandidates) {
|
|
||||||
val paramCount = constructor.getParameterList().getParametersCount()
|
|
||||||
val targetInfo = toTargetConstructorMap[constructor]!!
|
|
||||||
val targetConstructor = targetInfo.constructor
|
|
||||||
val targetParamCount = targetConstructor.getParameterList().getParametersCount()
|
|
||||||
assert(paramCount < targetParamCount)
|
|
||||||
val defaults = targetInfo.parameterDefaults!!
|
|
||||||
assert(defaults.size() == targetParamCount - paramCount)
|
|
||||||
|
|
||||||
val targetDefaults = lastParamDefaults.getOrPut(targetConstructor, { ArrayList() })
|
|
||||||
|
|
||||||
for (i in defaults.indices) {
|
|
||||||
val default = defaults[defaults.size() - i - 1]
|
|
||||||
if (i < targetDefaults.size()) { // default for this parameter has already been assigned
|
|
||||||
if (targetDefaults[i].getText() != default.getText()) continue@DropCandidatesLoop
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
targetDefaults.add(default)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructorsToDrop.add(constructor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var baseClassParams: List<DeferredElement<Expression>>? = if (constructors.isEmpty()) emptyList() else null
|
public var baseClassParams: List<DeferredElement<Expression>>? = if (constructors.isEmpty()) emptyList() else null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -169,10 +84,9 @@ class ConstructorConverter(
|
|||||||
convertPrimaryConstructor(annotations, modifiers, membersToRemove, postProcessBody)
|
convertPrimaryConstructor(annotations, modifiers, membersToRemove, postProcessBody)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (constructor in constructorsToDrop) return null
|
if (overloadReducer.shouldDropMethod(constructor)) return null
|
||||||
|
|
||||||
val params = convertParameterList(constructor, converter,
|
val params = converter.convertParameterList(constructor, overloadReducer)
|
||||||
{ parameter, default -> converter.convertParameter(parameter, defaultValue = default) })
|
|
||||||
|
|
||||||
val thisOrSuper = findThisOrSuperCall(constructor)
|
val thisOrSuper = findThisOrSuperCall(constructor)
|
||||||
val thisOrSuperDeferred = if (thisOrSuper != null)
|
val thisOrSuperDeferred = if (thisOrSuper != null)
|
||||||
@@ -193,14 +107,6 @@ class ConstructorConverter(
|
|||||||
|
|
||||||
SecondaryConstructor(annotations, modifiers, params, converter.deferredElement(::convertBody), thisOrSuperDeferred)
|
SecondaryConstructor(annotations, modifiers, params, converter.deferredElement(::convertBody), thisOrSuperDeferred)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.parameterList.parameters.any { it.defaultValue != null }) {
|
|
||||||
result.annotations += Annotations(listOf(Annotation(Identifier("overloads").assignNoPrototype(),
|
|
||||||
listOf(),
|
|
||||||
brackets = result is PrimaryConstructor,
|
|
||||||
newLineAfter = false).assignNoPrototype())).assignNoPrototype()
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,53 +194,34 @@ class ConstructorConverter(
|
|||||||
baseClassParams = emptyList()
|
baseClassParams = emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val parameterList = convertParameterList(primaryConstructor,
|
val parameterList = correctedConverter.convertParameterList(
|
||||||
correctedConverter,
|
primaryConstructor,
|
||||||
{ parameter, default ->
|
overloadReducer,
|
||||||
if (!parameterToField.containsKey(parameter)) {
|
{ parameter, default ->
|
||||||
correctedConverter.convertParameter(parameter, defaultValue = default)
|
if (!parameterToField.containsKey(parameter)) {
|
||||||
}
|
correctedConverter.convertParameter(parameter, defaultValue = default)
|
||||||
else {
|
}
|
||||||
val (field, type) = parameterToField[parameter]!!
|
else {
|
||||||
val fieldCorrection = fieldCorrections[field]
|
val (field, type) = parameterToField[parameter]!!
|
||||||
val name = fieldCorrection?.identifier ?: field.declarationIdentifier()
|
val fieldCorrection = fieldCorrections[field]
|
||||||
val accessModifiers = if (fieldCorrection != null)
|
val name = fieldCorrection?.identifier ?: field.declarationIdentifier()
|
||||||
Modifiers(listOf()).with(fieldCorrection.access).assignNoPrototype()
|
val accessModifiers = if (fieldCorrection != null)
|
||||||
else
|
Modifiers(listOf()).with(fieldCorrection.access).assignNoPrototype()
|
||||||
converter.convertModifiers(field).filter { it in ACCESS_MODIFIERS }
|
else
|
||||||
Parameter(name,
|
converter.convertModifiers(field).filter { it in ACCESS_MODIFIERS }
|
||||||
type,
|
Parameter(name,
|
||||||
if (isVal(converter.referenceSearcher, field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
type,
|
||||||
converter.convertAnnotations(parameter) + converter.convertAnnotations(field),
|
if (isVal(converter.referenceSearcher, field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
||||||
accessModifiers,
|
converter.convertAnnotations(parameter) + converter.convertAnnotations(field),
|
||||||
default).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
|
accessModifiers,
|
||||||
}
|
default).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
|
||||||
},
|
}
|
||||||
correctCodeConverter = { correct() })
|
},
|
||||||
|
correctCodeConverter = { correct() })
|
||||||
|
|
||||||
return PrimaryConstructor(annotations, modifiers, parameterList, converter.deferredElement(bodyGenerator)).assignPrototype(primaryConstructor)
|
return PrimaryConstructor(annotations, modifiers, parameterList, converter.deferredElement(bodyGenerator)).assignPrototype(primaryConstructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertParameterList(
|
|
||||||
constructor: PsiMethod,
|
|
||||||
converter: Converter,
|
|
||||||
convertParameter: (parameter: PsiParameter, default: DeferredElement<Expression>?) -> Parameter,
|
|
||||||
correctCodeConverter: CodeConverter.() -> CodeConverter = { this }
|
|
||||||
): ParameterList {
|
|
||||||
val parameterList = constructor.getParameterList()
|
|
||||||
val params = parameterList.getParameters()
|
|
||||||
val defaults = lastParamDefaults[constructor] ?: emptyList<PsiExpression>()
|
|
||||||
return ParameterList(params.indices.map { i ->
|
|
||||||
val parameter = params[i]
|
|
||||||
val indexFromEnd = params.size() - i - 1
|
|
||||||
val defaultValue = if (indexFromEnd < defaults.size())
|
|
||||||
converter.deferredElement { codeConverter -> codeConverter.correctCodeConverter().convertExpression(defaults[indexFromEnd], parameter.getType()) }
|
|
||||||
else
|
|
||||||
null
|
|
||||||
convertParameter(parameter, defaultValue)
|
|
||||||
}).assignPrototype(parameterList)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? {
|
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? {
|
||||||
val body = constructor.getBody() ?: return null
|
val body = constructor.getBody() ?: return null
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.j2k
|
package org.jetbrains.kotlin.j2k
|
||||||
|
|
||||||
import com.google.common.collect.Multimap
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.CommonClassNames.*
|
import com.intellij.psi.CommonClassNames.*
|
||||||
@@ -32,6 +31,7 @@ import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
|
|||||||
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessingExpressionConverter
|
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessingExpressionConverter
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.*
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions.*
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
class Converter private(
|
class Converter private(
|
||||||
private val elementToConvert: PsiElement,
|
private val elementToConvert: PsiElement,
|
||||||
@@ -62,7 +62,9 @@ class Converter private(
|
|||||||
public fun create(elementToConvert: PsiElement, settings: ConverterSettings, inConversionScope: (PsiElement) -> Boolean,
|
public fun create(elementToConvert: PsiElement, settings: ConverterSettings, inConversionScope: (PsiElement) -> Boolean,
|
||||||
referenceSearcher: ReferenceSearcher, resolverForConverter: ResolverForConverter,
|
referenceSearcher: ReferenceSearcher, resolverForConverter: ResolverForConverter,
|
||||||
usageProcessingsCollector: (UsageProcessing) -> Unit): Converter {
|
usageProcessingsCollector: (UsageProcessing) -> Unit): Converter {
|
||||||
return Converter(elementToConvert, settings, inConversionScope, referenceSearcher, resolverForConverter, CommonState(usageProcessingsCollector), PersonalState(null))
|
return Converter(elementToConvert, settings, inConversionScope,
|
||||||
|
CachingReferenceSearcher(referenceSearcher),
|
||||||
|
resolverForConverter, CommonState(usageProcessingsCollector), PersonalState(null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +100,7 @@ class Converter private(
|
|||||||
private fun convertTopElement(element: PsiElement): Element? = when (element) {
|
private fun convertTopElement(element: PsiElement): Element? = when (element) {
|
||||||
is PsiJavaFile -> convertFile(element)
|
is PsiJavaFile -> convertFile(element)
|
||||||
is PsiClass -> convertClass(element)
|
is PsiClass -> convertClass(element)
|
||||||
is PsiMethod -> convertMethod(element, null, null, false)
|
is PsiMethod -> convertMethod(element, null, null, null, false)
|
||||||
is PsiField -> convertField(element, null)
|
is PsiField -> convertField(element, null)
|
||||||
is PsiStatement -> createDefaultCodeConverter().convertStatement(element)
|
is PsiStatement -> createDefaultCodeConverter().convertStatement(element)
|
||||||
is PsiExpression -> createDefaultCodeConverter().convertExpression(element)
|
is PsiExpression -> createDefaultCodeConverter().convertExpression(element)
|
||||||
@@ -274,7 +276,8 @@ class Converter private(
|
|||||||
|
|
||||||
// to convert fields and nested types - they are not allowed in Kotlin but we convert them and let user refactor code
|
// to convert fields and nested types - they are not allowed in Kotlin but we convert them and let user refactor code
|
||||||
var classBody = ClassBodyConverter(psiClass, this, isOpenClass = false, isObject = false).convertBody()
|
var classBody = ClassBodyConverter(psiClass, this, isOpenClass = false, isObject = false).convertBody()
|
||||||
classBody = ClassBody(constructorSignature, classBody.baseClassParams, classBody.members, classBody.companionObjectMembers, classBody.lBrace, classBody.rBrace)
|
classBody = ClassBody(constructorSignature, classBody.baseClassParams, classBody.members,
|
||||||
|
classBody.companionObjectMembers, classBody.lBrace, classBody.rBrace, classBody.overloadReducer)
|
||||||
|
|
||||||
val annotationAnnotation = Annotation(Identifier("annotation").assignNoPrototype(), listOf(), false, false).assignNoPrototype()
|
val annotationAnnotation = Annotation(Identifier("annotation").assignNoPrototype(), listOf(), false, false).assignNoPrototype()
|
||||||
return Class(psiClass.declarationIdentifier(),
|
return Class(psiClass.declarationIdentifier(),
|
||||||
@@ -348,10 +351,13 @@ class Converter private(
|
|||||||
return if (convertedType == initializerType) null else convertedType
|
return if (convertedType == initializerType) null else convertedType
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun convertMethod(method: PsiMethod,
|
public fun convertMethod(
|
||||||
membersToRemove: MutableSet<PsiMember>?,
|
method: PsiMethod,
|
||||||
constructorConverter: ConstructorConverter?,
|
membersToRemove: MutableSet<PsiMember>?,
|
||||||
isInOpenClass: Boolean): Member? {
|
constructorConverter: ConstructorConverter?,
|
||||||
|
overloadReducer: OverloadReducer?,
|
||||||
|
isInOpenClass: Boolean
|
||||||
|
): FunctionLike? {
|
||||||
val returnType = typeConverter.convertMethodReturnType(method)
|
val returnType = typeConverter.convertMethodReturnType(method)
|
||||||
|
|
||||||
val annotations = convertAnnotations(method) + convertThrows(method)
|
val annotations = convertAnnotations(method) + convertThrows(method)
|
||||||
@@ -401,7 +407,8 @@ class Converter private(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var params = convertParameterList(method.getParameterList())
|
var params = convertParameterList(method, overloadReducer)
|
||||||
|
|
||||||
val typeParameterList = convertTypeParameterList(method.getTypeParameterList())
|
val typeParameterList = convertTypeParameterList(method.getTypeParameterList())
|
||||||
var body = deferredElement { codeConverter: CodeConverter ->
|
var body = deferredElement { codeConverter: CodeConverter ->
|
||||||
val body = codeConverter.withMethodReturnType(method.getReturnType()).convertBlock(method.getBody())
|
val body = codeConverter.withMethodReturnType(method.getReturnType()).convertBlock(method.getBody())
|
||||||
@@ -410,7 +417,17 @@ class Converter private(
|
|||||||
Function(method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, body, containingClass?.isInterface() ?: false)
|
Function(method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, body, containingClass?.isInterface() ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return function?.assignPrototype(method)
|
if (function == null) return null
|
||||||
|
|
||||||
|
if (function.parameterList.parameters.any { it.defaultValue != null }) {
|
||||||
|
function.annotations += Annotations(
|
||||||
|
listOf(Annotation(Identifier("overloads").assignNoPrototype(),
|
||||||
|
listOf(),
|
||||||
|
brackets = function is PrimaryConstructor,
|
||||||
|
newLineAfter = false).assignNoPrototype())).assignNoPrototype()
|
||||||
|
}
|
||||||
|
|
||||||
|
return function.assignPrototype(method)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -507,14 +524,13 @@ class Converter private(
|
|||||||
private fun convertToNotNullableTypes(types: Array<out PsiType?>): List<Type>
|
private fun convertToNotNullableTypes(types: Array<out PsiType?>): List<Type>
|
||||||
= types.map { typeConverter.convertType(it, Nullability.NotNull) }
|
= types.map { typeConverter.convertType(it, Nullability.NotNull) }
|
||||||
|
|
||||||
private fun convertParameterList(parameterList: PsiParameterList): ParameterList
|
public fun convertParameter(
|
||||||
= ParameterList(parameterList.getParameters().map { convertParameter(it) }).assignPrototype(parameterList)
|
parameter: PsiParameter,
|
||||||
|
nullability: Nullability = Nullability.Default,
|
||||||
public fun convertParameter(parameter: PsiParameter,
|
varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None,
|
||||||
nullability: Nullability = Nullability.Default,
|
modifiers: Modifiers = Modifiers.Empty,
|
||||||
varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None,
|
defaultValue: DeferredElement<Expression>? = null
|
||||||
modifiers: Modifiers = Modifiers.Empty,
|
): Parameter {
|
||||||
defaultValue: DeferredElement<Expression>? = null): Parameter {
|
|
||||||
var type = typeConverter.convertVariableType(parameter)
|
var type = typeConverter.convertVariableType(parameter)
|
||||||
when (nullability) {
|
when (nullability) {
|
||||||
Nullability.NotNull -> type = type.toNotNullType()
|
Nullability.NotNull -> type = type.toNotNullType()
|
||||||
@@ -555,6 +571,27 @@ class Converter private(
|
|||||||
val annotation = Annotation(Identifier("throws").assignNoPrototype(), arguments, false, true)
|
val annotation = Annotation(Identifier("throws").assignNoPrototype(), arguments, false, true)
|
||||||
return Annotations(listOf(annotation.assignPrototype(throwsList))).assignPrototype(throwsList)
|
return Annotations(listOf(annotation.assignPrototype(throwsList))).assignPrototype(throwsList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CachingReferenceSearcher(private val searcher: ReferenceSearcher) : ReferenceSearcher by searcher {
|
||||||
|
private val hasInheritorsCached = HashMap<PsiClass, Boolean>()
|
||||||
|
private val hasOverridesCached = HashMap<PsiMethod, Boolean>()
|
||||||
|
|
||||||
|
override fun hasInheritors(`class`: PsiClass): Boolean {
|
||||||
|
val cached = hasInheritorsCached[`class`]
|
||||||
|
if (cached != null) return cached
|
||||||
|
val result = searcher.hasInheritors(`class`)
|
||||||
|
hasInheritorsCached[`class`] = result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasOverrides(method: PsiMethod): Boolean {
|
||||||
|
val cached = hasOverridesCached[method]
|
||||||
|
if (cached != null) return cached
|
||||||
|
val result = searcher.hasOverrides(method)
|
||||||
|
hasOverridesCached[method] = result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val PRIMITIVE_TYPE_CONVERSIONS: Map<String, String> = mapOf(
|
val PRIMITIVE_TYPE_CONVERSIONS: Map<String, String> = mapOf(
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.j2k
|
||||||
|
|
||||||
|
import com.intellij.psi.*
|
||||||
|
import org.jetbrains.kotlin.j2k.ast.*
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.HashMap
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
class OverloadReducer(
|
||||||
|
private val methods: Collection<PsiMethod>,
|
||||||
|
private val isOpenClass: Boolean,
|
||||||
|
private val referenceSearcher: ReferenceSearcher
|
||||||
|
) {
|
||||||
|
private val methodToLastParameterDefaults = HashMap<PsiMethod, ArrayList<PsiExpression>>()
|
||||||
|
private val methodsToDrop = HashSet<PsiMethod>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val map = buildOverloadEquivalenceMap()
|
||||||
|
dropOverloadsForDefaultValues(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun shouldDropMethod(method: PsiMethod): Boolean = method in methodsToDrop
|
||||||
|
|
||||||
|
public fun parameterDefault(method: PsiMethod, parameterIndex: Int): PsiExpression? {
|
||||||
|
val defaults = methodToLastParameterDefaults[method] ?: return null
|
||||||
|
val index = method.getParameterList().getParametersCount() - parameterIndex - 1
|
||||||
|
return if (index < defaults.size()) defaults[index] else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EquivalentOverloadInfo(
|
||||||
|
/**
|
||||||
|
* Target method (one which is finally invoked by this one)
|
||||||
|
*/
|
||||||
|
val method: PsiMethod,
|
||||||
|
/**
|
||||||
|
* This method is equivalent to the target method with a few last parameters having default values
|
||||||
|
*/
|
||||||
|
val parameterDefaults: List<PsiExpression>)
|
||||||
|
|
||||||
|
private fun buildOverloadEquivalenceMap(): Map<PsiMethod, EquivalentOverloadInfo> {
|
||||||
|
val overloadGroups = methods
|
||||||
|
.groupBy { listOf(if (it.isConstructor()) null else it.getName(),
|
||||||
|
it.accessModifier(),
|
||||||
|
it.getReturnType(),
|
||||||
|
it.hasModifierProperty(PsiModifier.STATIC),
|
||||||
|
getAnnotationsFingerprint(it)) }
|
||||||
|
.values()
|
||||||
|
.filter { it.size() > 1 }
|
||||||
|
.map { it.filterNot { shouldSkipOverload(it) } }
|
||||||
|
.filter { it.size() > 1 }
|
||||||
|
|
||||||
|
val map = HashMap<PsiMethod, EquivalentOverloadInfo>()
|
||||||
|
for (group in overloadGroups) {
|
||||||
|
for (method in group) {
|
||||||
|
val overloadInfo = findEquivalentOverload(method, group) ?: continue
|
||||||
|
|
||||||
|
val furtherOverloadInfo = map[overloadInfo.method]
|
||||||
|
val resultOverloadInfo = if (furtherOverloadInfo != null) {
|
||||||
|
EquivalentOverloadInfo(furtherOverloadInfo.method, overloadInfo.parameterDefaults + furtherOverloadInfo.parameterDefaults)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
overloadInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
map[method] = resultOverloadInfo
|
||||||
|
for (entry in map.entrySet()) {
|
||||||
|
if (entry.value.method == method) {
|
||||||
|
val newParameterDefaults = entry.value.parameterDefaults + resultOverloadInfo.parameterDefaults
|
||||||
|
entry.setValue(EquivalentOverloadInfo(resultOverloadInfo.method, newParameterDefaults))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldSkipOverload(method: PsiMethod): Boolean {
|
||||||
|
if (method.isConstructor()) return false
|
||||||
|
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) return true
|
||||||
|
if (method.hasModifierProperty(PsiModifier.NATIVE)) return true
|
||||||
|
if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) return true
|
||||||
|
if (method.getHierarchicalMethodSignature().getSuperSignatures().isNotEmpty()) return true
|
||||||
|
if (isOpenClass && referenceSearcher.hasOverrides(method)) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findEquivalentOverload(method: PsiMethod, overloads: Collection<PsiMethod>): EquivalentOverloadInfo? {
|
||||||
|
val statement = method.getBody()?.getStatements()?.singleOrNull() ?: return null
|
||||||
|
|
||||||
|
val methodCall = when (statement) {
|
||||||
|
is PsiExpressionStatement -> statement.getExpression()
|
||||||
|
is PsiReturnStatement -> statement.getReturnValue()
|
||||||
|
else -> null
|
||||||
|
} as? PsiMethodCallExpression ?: return null
|
||||||
|
|
||||||
|
val expectedMethodName = if (method.isConstructor()) "this" else method.getName()
|
||||||
|
val refExpr = methodCall.getMethodExpression()
|
||||||
|
if (refExpr.isQualified() || refExpr.getReferenceName() != expectedMethodName) return null
|
||||||
|
|
||||||
|
val target = refExpr.resolve() as? PsiMethod ?: return null
|
||||||
|
if (target !in overloads) return null
|
||||||
|
|
||||||
|
val parameterDefaults = calcTargetParameterDefaults(method, target, methodCall) ?: return null
|
||||||
|
return EquivalentOverloadInfo(target, parameterDefaults)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calcTargetParameterDefaults(method: PsiMethod, target: PsiMethod, targetCall: PsiMethodCallExpression): List<PsiExpression>? {
|
||||||
|
val parameters = method.getParameterList().getParameters()
|
||||||
|
val targetParameters = target.getParameterList().getParameters()
|
||||||
|
if (parameters.size() >= targetParameters.size()) return null
|
||||||
|
val args = targetCall.getArgumentList().getExpressions()
|
||||||
|
if (args.size() != targetParameters.size()) return null // incorrect code
|
||||||
|
|
||||||
|
for (i in parameters.indices) {
|
||||||
|
val parameter = parameters[i]
|
||||||
|
val targetParameter = targetParameters[i]
|
||||||
|
if (parameter.getName() != targetParameter.getName() || parameter.getType() != targetParameter.getType()) return null
|
||||||
|
val arg = args[i]
|
||||||
|
if (arg !is PsiReferenceExpression || arg.resolve() != parameter) return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return args.drop(parameters.size())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dropOverloadsForDefaultValues(equivalenceMap: Map<PsiMethod, EquivalentOverloadInfo>) {
|
||||||
|
val dropCandidates = equivalenceMap
|
||||||
|
.map { it.key }
|
||||||
|
.sortBy { -it.getParameterList().getParametersCount() } // we will try to drop them starting from ones with more parameters
|
||||||
|
|
||||||
|
@DropCandidatesLoop
|
||||||
|
for (method in dropCandidates) {
|
||||||
|
val paramCount = method.getParameterList().getParametersCount()
|
||||||
|
val targetInfo = equivalenceMap[method]!!
|
||||||
|
val targetParamCount = targetInfo.method.getParameterList().getParametersCount()
|
||||||
|
assert(paramCount < targetParamCount)
|
||||||
|
val defaults = targetInfo.parameterDefaults
|
||||||
|
assert(defaults.size() == targetParamCount - paramCount)
|
||||||
|
|
||||||
|
val targetDefaults = methodToLastParameterDefaults.getOrPut(targetInfo.method, { ArrayList() })
|
||||||
|
|
||||||
|
for (i in defaults.indices) {
|
||||||
|
val default = defaults[defaults.size() - i - 1]
|
||||||
|
if (i < targetDefaults.size()) { // default for this parameter has already been assigned
|
||||||
|
if (targetDefaults[i].getText() != default.getText()) continue@DropCandidatesLoop
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
targetDefaults.add(default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
methodsToDrop.add(method)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAnnotationsFingerprint(method: PsiMethod): Any {
|
||||||
|
return method.getModifierList().getAnnotations().map { it.getText() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Converter.convertParameterList(
|
||||||
|
method: PsiMethod,
|
||||||
|
overloadReducer: OverloadReducer?,
|
||||||
|
convertParameter: (parameter: PsiParameter, default: DeferredElement<Expression>?) -> Parameter = { parameter, default -> convertParameter(parameter, defaultValue = default) },
|
||||||
|
correctCodeConverter: CodeConverter.() -> CodeConverter = { this }
|
||||||
|
): ParameterList {
|
||||||
|
val parameterList = method.getParameterList()
|
||||||
|
val params = parameterList.getParameters()
|
||||||
|
return ParameterList(params.indices.map { i ->
|
||||||
|
val parameter = params[i]
|
||||||
|
val defaultValue = overloadReducer?.parameterDefault(method, i)
|
||||||
|
val defaultValueConverted = if (defaultValue != null)
|
||||||
|
deferredElement { codeConverter -> codeConverter.correctCodeConverter().convertExpression(defaultValue, parameter.getType()) }
|
||||||
|
else
|
||||||
|
null
|
||||||
|
convertParameter(parameter, defaultValueConverted)
|
||||||
|
}).assignPrototype(parameterList)
|
||||||
|
}
|
||||||
@@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.j2k.ast
|
package org.jetbrains.kotlin.j2k.ast
|
||||||
|
|
||||||
import org.jetbrains.kotlin.j2k.*
|
import com.intellij.psi.PsiExpression
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import org.jetbrains.kotlin.j2k.CodeBuilder
|
||||||
|
import org.jetbrains.kotlin.j2k.OverloadReducer
|
||||||
|
import org.jetbrains.kotlin.j2k.append
|
||||||
|
|
||||||
abstract class Member(var annotations: Annotations, val modifiers: Modifiers) : Element()
|
abstract class Member(var annotations: Annotations, val modifiers: Modifiers) : Element()
|
||||||
|
|
||||||
@@ -26,7 +30,8 @@ class ClassBody (
|
|||||||
val members: List<Member>,
|
val members: List<Member>,
|
||||||
val companionObjectMembers: List<Member>,
|
val companionObjectMembers: List<Member>,
|
||||||
val lBrace: LBrace,
|
val lBrace: LBrace,
|
||||||
val rBrace: RBrace) {
|
val rBrace: RBrace,
|
||||||
|
val overloadReducer: OverloadReducer) {
|
||||||
|
|
||||||
fun append(builder: CodeBuilder) {
|
fun append(builder: CodeBuilder) {
|
||||||
val membersFiltered = members.filter { !it.isEmpty }
|
val membersFiltered = members.filter { !it.isEmpty }
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import com.intellij.util.IncorrectOperationException
|
|||||||
abstract class Constructor(
|
abstract class Constructor(
|
||||||
annotations: Annotations,
|
annotations: Annotations,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
public val parameterList: ParameterList,
|
parameterList: ParameterList,
|
||||||
protected val body: DeferredElement<Block>
|
body: DeferredElement<Block>
|
||||||
) : Member(annotations, modifiers)
|
) : FunctionLike(annotations, modifiers, parameterList, body)
|
||||||
|
|
||||||
class PrimaryConstructor(
|
class PrimaryConstructor(
|
||||||
annotations: Annotations,
|
annotations: Annotations,
|
||||||
@@ -36,14 +36,14 @@ class PrimaryConstructor(
|
|||||||
override fun generateCode(builder: CodeBuilder) { throw IncorrectOperationException() }
|
override fun generateCode(builder: CodeBuilder) { throw IncorrectOperationException() }
|
||||||
|
|
||||||
public fun initializer(): Initializer
|
public fun initializer(): Initializer
|
||||||
= Initializer(body, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false))
|
= Initializer(body!!, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false))
|
||||||
|
|
||||||
public fun createSignature(converter: Converter): PrimaryConstructorSignature {
|
public fun createSignature(converter: Converter): PrimaryConstructorSignature {
|
||||||
val signature = PrimaryConstructorSignature(annotations, modifiers, parameterList)
|
val signature = PrimaryConstructorSignature(annotations, modifiers, parameterList)
|
||||||
|
|
||||||
// assign prototypes later because we don't know yet whether the body is empty or not
|
// assign prototypes later because we don't know yet whether the body is empty or not
|
||||||
converter.addPostUnfoldDeferredElementsAction {
|
converter.addPostUnfoldDeferredElementsAction {
|
||||||
val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = body.isEmpty, commentsInside = body.isEmpty)
|
val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = body!!.isEmpty, commentsInside = body.isEmpty)
|
||||||
signature.assignPrototypesFrom(this, inheritance)
|
signature.assignPrototypesFrom(this, inheritance)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ class SecondaryConstructor(
|
|||||||
builder append " : " append thisOrSuperCall
|
builder append " : " append thisOrSuperCall
|
||||||
}
|
}
|
||||||
|
|
||||||
builder append " " append body
|
builder append " " append body!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,16 +18,23 @@ package org.jetbrains.kotlin.j2k.ast
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.j2k.*
|
import org.jetbrains.kotlin.j2k.*
|
||||||
|
|
||||||
|
abstract class FunctionLike(
|
||||||
|
annotations: Annotations,
|
||||||
|
modifiers: Modifiers,
|
||||||
|
val parameterList: ParameterList,
|
||||||
|
val body: DeferredElement<Block>?
|
||||||
|
) : Member(annotations, modifiers)
|
||||||
|
|
||||||
class Function(
|
class Function(
|
||||||
val name: Identifier,
|
val name: Identifier,
|
||||||
annotations: Annotations,
|
annotations: Annotations,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
val returnType: Type,
|
val returnType: Type,
|
||||||
val typeParameterList: TypeParameterList,
|
val typeParameterList: TypeParameterList,
|
||||||
val parameterList: ParameterList,
|
parameterList: ParameterList,
|
||||||
val body: DeferredElement<Block>?,
|
body: DeferredElement<Block>?,
|
||||||
val isInTrait: Boolean
|
val isInTrait: Boolean
|
||||||
) : Member(annotations, modifiers) {
|
) : FunctionLike(annotations, modifiers, parameterList, body) {
|
||||||
|
|
||||||
private fun presentationModifiers(): Modifiers {
|
private fun presentationModifiers(): Modifiers {
|
||||||
var modifiers = this.modifiers
|
var modifiers = this.modifiers
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
class A {
|
||||||
|
private String s = "";
|
||||||
|
private int x = 0;
|
||||||
|
|
||||||
|
public A() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public A(int p, String s){
|
||||||
|
this(p, s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public A(int p, String s, int x) {
|
||||||
|
this();
|
||||||
|
this.s = s;
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// ERROR: Val cannot be reassigned
|
||||||
|
// ERROR: Val cannot be reassigned
|
||||||
|
class A() {
|
||||||
|
private val s = ""
|
||||||
|
private val x = 0
|
||||||
|
|
||||||
|
overloads public constructor(p: Int, s: String, x: Int = 1) : this() {
|
||||||
|
this.s = s
|
||||||
|
this.x = x
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
abstract class A {
|
||||||
|
public abstract void foo(int p);
|
||||||
|
|
||||||
|
public void foo(){
|
||||||
|
foo(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
abstract class A {
|
||||||
|
public abstract fun foo(p: Int)
|
||||||
|
|
||||||
|
public fun foo() {
|
||||||
|
foo(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
class A {
|
||||||
|
private int field = 0;
|
||||||
|
|
||||||
|
public int getField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField(int field) {
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField() {
|
||||||
|
setField(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class A {
|
||||||
|
public var field: Int = 0
|
||||||
|
|
||||||
|
public fun setField() {
|
||||||
|
field = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
class A {
|
||||||
|
@NotNull
|
||||||
|
Object foo(String s) {
|
||||||
|
System.out.println("s = " + s);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
Object foo() {
|
||||||
|
return foo(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Object bar(String s) {
|
||||||
|
System.out.println("s = " + s);
|
||||||
|
return s == null ? "" : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
Object bar() {
|
||||||
|
return bar(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Object bar1(String s) {
|
||||||
|
System.out.println("s = " + s);
|
||||||
|
return s == null ? "" : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Object bar1() {
|
||||||
|
return bar1(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void f() {
|
||||||
|
f(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void f(int p) {
|
||||||
|
System.out.println("p = " + p);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// ERROR: Type mismatch: inferred type is kotlin.Any? but kotlin.Any was expected
|
||||||
|
// ERROR: Type mismatch: inferred type is kotlin.Any? but kotlin.Any was expected
|
||||||
|
class A {
|
||||||
|
overloads fun foo(s: String? = null): Any {
|
||||||
|
println("s = " + s!!)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(s: String?): Any? {
|
||||||
|
println("s = " + s!!)
|
||||||
|
return if (s == null) "" else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): Any {
|
||||||
|
return bar(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun bar1(s: String?): Any? {
|
||||||
|
println("s = " + s!!)
|
||||||
|
return if (s == null) "" else null
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun bar1(): Any {
|
||||||
|
return bar1(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecated("")
|
||||||
|
public fun f() {
|
||||||
|
f(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun f(p: Int) {
|
||||||
|
println("p = " + p)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
interface I {
|
||||||
|
void foo(int i, char c, String s);
|
||||||
|
void bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
class A implements I{
|
||||||
|
public void foo(int i, char c, String s) {
|
||||||
|
System.out.println("foo" + i + c + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void foo(int i, char c) {
|
||||||
|
foo(i, c, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void foo(int i) {
|
||||||
|
foo(i, 'a', "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bar() {
|
||||||
|
bar(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bar(int i) {}
|
||||||
|
|
||||||
|
public void x() {
|
||||||
|
x(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void x(int i) {}
|
||||||
|
|
||||||
|
public void y() {
|
||||||
|
y(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void y(int i) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
public void x() {
|
||||||
|
super.x();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void y(int i) {
|
||||||
|
super.y(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
trait I {
|
||||||
|
public fun foo(i: Int, c: Char, s: String)
|
||||||
|
public fun bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
open class A : I {
|
||||||
|
override fun foo(i: Int, c: Char, s: String) {
|
||||||
|
println("foo" + i + c + s)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun foo(i: Int, c: Char) {
|
||||||
|
foo(i, c, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun foo(i: Int) {
|
||||||
|
foo(i, 'a', "")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bar() {
|
||||||
|
bar(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun bar(i: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public open fun x() {
|
||||||
|
x(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun x(i: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun y() {
|
||||||
|
y(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public open fun y(i: Int) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
override fun x() {
|
||||||
|
super.x()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun y(i: Int) {
|
||||||
|
super.y(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
class A {
|
||||||
|
void foo(int i, char c, String s) {
|
||||||
|
System.out.println("foo" + i + c + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo(int i, char c) {
|
||||||
|
foo(i, c, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo(int i) {
|
||||||
|
foo(i, 'a', "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int bar(String s) {
|
||||||
|
System.out.println("s = " + s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bar() {
|
||||||
|
return bar(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class A {
|
||||||
|
overloads fun foo(i: Int, c: Char = 'a', s: String = "") {
|
||||||
|
println("foo" + i + c + s)
|
||||||
|
}
|
||||||
|
|
||||||
|
overloads fun bar(s: String? = null): Int {
|
||||||
|
println("s = " + s!!)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
class A {
|
||||||
|
public void foo(int p) {
|
||||||
|
System.out.println("p = [" + p + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void foo(){
|
||||||
|
foo(calcSomething());
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method should be invoked under synchronized block!
|
||||||
|
private int calcSomething() { return 0; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
class A {
|
||||||
|
public fun foo(p: Int) {
|
||||||
|
println("p = [" + p + "]")
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public fun foo() {
|
||||||
|
foo(calcSomething())
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method should be invoked under synchronized block!
|
||||||
|
private fun calcSomething(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,6 +78,7 @@ import java.util.regex.Pattern;
|
|||||||
JavaToKotlinConverterForWebDemoTestGenerated.NewClassExpression.class,
|
JavaToKotlinConverterForWebDemoTestGenerated.NewClassExpression.class,
|
||||||
JavaToKotlinConverterForWebDemoTestGenerated.Nullability.class,
|
JavaToKotlinConverterForWebDemoTestGenerated.Nullability.class,
|
||||||
JavaToKotlinConverterForWebDemoTestGenerated.ObjectLiteral.class,
|
JavaToKotlinConverterForWebDemoTestGenerated.ObjectLiteral.class,
|
||||||
|
JavaToKotlinConverterForWebDemoTestGenerated.Overloads.class,
|
||||||
JavaToKotlinConverterForWebDemoTestGenerated.PackageStatement.class,
|
JavaToKotlinConverterForWebDemoTestGenerated.PackageStatement.class,
|
||||||
JavaToKotlinConverterForWebDemoTestGenerated.ParenthesizedExpression.class,
|
JavaToKotlinConverterForWebDemoTestGenerated.ParenthesizedExpression.class,
|
||||||
JavaToKotlinConverterForWebDemoTestGenerated.PolyadicExpression.class,
|
JavaToKotlinConverterForWebDemoTestGenerated.PolyadicExpression.class,
|
||||||
@@ -1313,6 +1314,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("secondaryConstructorWithDefaultValues2.java")
|
||||||
|
public void testSecondaryConstructorWithDefaultValues2() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/constructors/secondaryConstructorWithDefaultValues2.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("secondaryConstructorsInInnerClass.java")
|
@TestMetadata("secondaryConstructorsInInnerClass.java")
|
||||||
public void testSecondaryConstructorsInInnerClass() throws Exception {
|
public void testSecondaryConstructorsInInnerClass() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/constructors/secondaryConstructorsInInnerClass.java");
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/constructors/secondaryConstructorsInInnerClass.java");
|
||||||
@@ -3489,6 +3496,51 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("j2k/testData/fileOrElement/overloads")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Overloads extends AbstractJavaToKotlinConverterForWebDemoTest {
|
||||||
|
@TestMetadata("Abstract.java")
|
||||||
|
public void testAbstract() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Abstract.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("AccessorToDrop.java")
|
||||||
|
public void testAccessorToDrop() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/AccessorToDrop.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInOverloads() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/overloads"), Pattern.compile("^(.+)\\.java$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Annotations.java")
|
||||||
|
public void testAnnotations() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Annotations.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Override.java")
|
||||||
|
public void testOverride() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Override.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Simple.java")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Simple.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Synchronized.java")
|
||||||
|
public void testSynchronized() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Synchronized.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("j2k/testData/fileOrElement/packageStatement")
|
@TestMetadata("j2k/testData/fileOrElement/packageStatement")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ import java.util.regex.Pattern;
|
|||||||
JavaToKotlinConverterSingleFileTestGenerated.NewClassExpression.class,
|
JavaToKotlinConverterSingleFileTestGenerated.NewClassExpression.class,
|
||||||
JavaToKotlinConverterSingleFileTestGenerated.Nullability.class,
|
JavaToKotlinConverterSingleFileTestGenerated.Nullability.class,
|
||||||
JavaToKotlinConverterSingleFileTestGenerated.ObjectLiteral.class,
|
JavaToKotlinConverterSingleFileTestGenerated.ObjectLiteral.class,
|
||||||
|
JavaToKotlinConverterSingleFileTestGenerated.Overloads.class,
|
||||||
JavaToKotlinConverterSingleFileTestGenerated.PackageStatement.class,
|
JavaToKotlinConverterSingleFileTestGenerated.PackageStatement.class,
|
||||||
JavaToKotlinConverterSingleFileTestGenerated.ParenthesizedExpression.class,
|
JavaToKotlinConverterSingleFileTestGenerated.ParenthesizedExpression.class,
|
||||||
JavaToKotlinConverterSingleFileTestGenerated.PolyadicExpression.class,
|
JavaToKotlinConverterSingleFileTestGenerated.PolyadicExpression.class,
|
||||||
@@ -1313,6 +1314,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("secondaryConstructorWithDefaultValues2.java")
|
||||||
|
public void testSecondaryConstructorWithDefaultValues2() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/constructors/secondaryConstructorWithDefaultValues2.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("secondaryConstructorsInInnerClass.java")
|
@TestMetadata("secondaryConstructorsInInnerClass.java")
|
||||||
public void testSecondaryConstructorsInInnerClass() throws Exception {
|
public void testSecondaryConstructorsInInnerClass() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/constructors/secondaryConstructorsInInnerClass.java");
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/constructors/secondaryConstructorsInInnerClass.java");
|
||||||
@@ -3489,6 +3496,51 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("j2k/testData/fileOrElement/overloads")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Overloads extends AbstractJavaToKotlinConverterSingleFileTest {
|
||||||
|
@TestMetadata("Abstract.java")
|
||||||
|
public void testAbstract() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Abstract.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("AccessorToDrop.java")
|
||||||
|
public void testAccessorToDrop() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/AccessorToDrop.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInOverloads() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/overloads"), Pattern.compile("^(.+)\\.java$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Annotations.java")
|
||||||
|
public void testAnnotations() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Annotations.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Override.java")
|
||||||
|
public void testOverride() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Override.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Simple.java")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Simple.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Synchronized.java")
|
||||||
|
public void testSynchronized() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/overloads/Synchronized.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("j2k/testData/fileOrElement/packageStatement")
|
@TestMetadata("j2k/testData/fileOrElement/packageStatement")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user