J2K: coversion of specially mapped built-in methods + replacing "get" with "[]" where possible
This commit is contained in:
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
||||
import org.jetbrains.kotlin.idea.intentions.*
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceGetIntention
|
||||
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.RemoveRightPartOfBinaryExpressionFix
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
@@ -58,6 +59,7 @@ object J2KPostProcessingRegistrar {
|
||||
registerIntentionBasedProcessing(IfThenToElvisIntention()) { applyTo(it) }
|
||||
registerIntentionBasedProcessing(IfNullToElvisIntention()) { applyTo(it) }
|
||||
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention()) { applyTo(it) }
|
||||
registerIntentionBasedProcessing(ReplaceGetIntention()) { applyTo(it) }
|
||||
|
||||
registerDiagnosticBasedProcessing<JetBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, diagnostic ->
|
||||
val expression = RemoveRightPartOfBinaryExpressionFix(element, "").invoke()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fun foo(o: Any) {
|
||||
if (o is String) {
|
||||
val l = o.length()
|
||||
val l = o.length
|
||||
}
|
||||
somethingElse()
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fun foo(o: Any) {
|
||||
if (o !is String) return
|
||||
val l = o.length()
|
||||
val l = o.length
|
||||
somethingElse(o as String/* we should not remove this cast because it's not in pasted range*/)
|
||||
}
|
||||
@@ -312,8 +312,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
}
|
||||
|
||||
if (target is PsiMethod) {
|
||||
val specialMethod = SpecialMethod.values().firstOrNull { it.matches(target) }
|
||||
if (specialMethod != null && (specialMethod.parameterCount == null || specialMethod.parameterCount == arguments.size())) {
|
||||
val specialMethod = SpecialMethod.match(target, arguments.size(), converter.services)
|
||||
if (specialMethod != null) {
|
||||
val converted = specialMethod.convertCall(methodExpr.getQualifierExpression(), arguments, typeArguments, codeConverter)
|
||||
if (converted != null) {
|
||||
result = converted
|
||||
@@ -350,23 +350,31 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
}
|
||||
|
||||
override fun visitNewExpression(expression: PsiNewExpression) {
|
||||
val type = expression.type
|
||||
if (expression.getArrayInitializer() != null) {
|
||||
result = codeConverter.convertExpression(expression.getArrayInitializer())
|
||||
}
|
||||
else if (expression.getArrayDimensions().size() > 0 && expression.getType() is PsiArrayType) {
|
||||
result = ArrayWithoutInitializationExpression(
|
||||
typeConverter.convertType(expression.getType(), Nullability.NotNull) as ArrayType,
|
||||
typeConverter.convertType(expression.type, Nullability.NotNull) as ArrayType,
|
||||
codeConverter.convertExpressions(expression.getArrayDimensions()))
|
||||
}
|
||||
else {
|
||||
val anonymousClass = expression.getAnonymousClass()
|
||||
if (type?.canonicalText in PsiPrimitiveType.getAllBoxedTypeNames()) {
|
||||
val argument = expression.argumentList?.expressions?.singleOrNull()
|
||||
if (argument != null && argument.type is PsiPrimitiveType) {
|
||||
result = codeConverter.convertExpression(argument)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val qualifier = expression.getQualifier()
|
||||
val classRef = expression.getClassOrAnonymousClassReference()
|
||||
val classRefConverted = if (classRef != null) converter.convertCodeReferenceElement(classRef, hasExternalQualifier = qualifier != null) else null
|
||||
result = NewClassExpression(classRefConverted,
|
||||
convertArguments(expression),
|
||||
codeConverter.convertExpression(qualifier),
|
||||
if (anonymousClass != null) converter.convertAnonymousClassBody(anonymousClass) else null)
|
||||
convertArguments(expression),
|
||||
codeConverter.convertExpression(qualifier),
|
||||
expression.anonymousClass?.let { converter.convertAnonymousClassBody(it) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,97 @@ import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT
|
||||
import com.intellij.psi.CommonClassNames.JAVA_LANG_STRING
|
||||
import com.intellij.psi.impl.PsiExpressionEvaluator
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
|
||||
enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String, val parameterCount: Int?) {
|
||||
CHAR_SEQUENCE_LENGTH(CharSequence::class.java.name, "length", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier)
|
||||
},
|
||||
|
||||
COLLECTION_SIZE(Collection::class.java.name, "size", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier)
|
||||
},
|
||||
|
||||
MAP_SIZE(Map::class.java.name, "size", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier)
|
||||
},
|
||||
|
||||
MAP_KEY_SET(Map::class.java.name, "keySet", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier, "keys")
|
||||
},
|
||||
|
||||
MAP_VALUES(Map::class.java.name, "values", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier)
|
||||
},
|
||||
|
||||
MAP_ENTRY_SET(Map::class.java.name, "entrySet", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier, "entries")
|
||||
},
|
||||
|
||||
ENUM_NAME(Enum::class.java.name, "name", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier, "name")
|
||||
},
|
||||
|
||||
ENUM_ORDINAL(Enum::class.java.name, "ordinal", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertMethodCallToPropertyUse(codeConverter, qualifier)
|
||||
},
|
||||
|
||||
CHAR_AT(CharSequence::class.java.name, "charAt", 1) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("get", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
NUMBER_BYTE_VALUE(Number::class.java.name, "byteValue", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("toByte", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
NUMBER_SHORT_VALUE(Number::class.java.name, "shortValue", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("toShort", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
NUMBER_INT_VALUE(Number::class.java.name, "intValue", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("toInt", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
NUMBER_LONG_VALUE(Number::class.java.name, "longValue", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("toLong", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
NUMBER_FLOAT_VALUE(Number::class.java.name, "floatValue", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("toFloat", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
NUMBER_DOUBLE_VALUE(Number::class.java.name, "doubleValue", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("toDouble", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
LIST_REMOVE(List::class.java.name, "remove", 1) {
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher)
|
||||
= super.matches(method, superMethodsSearcher) && method.parameterList.parameters.single().type.canonicalText == "int"
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertWithChangedName("removeAt", qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
OBJECT_EQUALS(null, "equals", 1) {
|
||||
override fun matches(method: PsiMethod)
|
||||
= super.matches(method) && method.getParameterList().getParameters().single().getType().getCanonicalText() == JAVA_LANG_OBJECT
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean
|
||||
= super.matches(method, superMethodsSearcher) && method.getParameterList().getParameters().single().getType().getCanonicalText() == JAVA_LANG_OBJECT
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
|
||||
if (qualifier == null || qualifier is PsiSuperExpression) return null
|
||||
@@ -33,7 +119,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
|
||||
}
|
||||
},
|
||||
|
||||
OBJECT_GET_CLASS("java.lang.Object", "getClass", 0) {
|
||||
OBJECT_GET_CLASS(JAVA_LANG_OBJECT, "getClass", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression {
|
||||
val identifier = Identifier("javaClass", false).assignNoPrototype()
|
||||
return if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
|
||||
@@ -45,27 +131,27 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
|
||||
= BinaryExpression(codeConverter.convertExpression(arguments[0]), codeConverter.convertExpression(arguments[1]), "==")
|
||||
},
|
||||
|
||||
COLLECTIONS_EMPTY_LIST("java.util.Collections", "emptyList", 0) {
|
||||
COLLECTIONS_EMPTY_LIST(Collections::class.java.name, "emptyList", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(null, "emptyList", listOf(), typeArgumentsConverted, false)
|
||||
},
|
||||
|
||||
COLLECTIONS_EMPTY_SET("java.util.Collections", "emptySet", 0) {
|
||||
COLLECTIONS_EMPTY_SET(Collections::class.java.name, "emptySet", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(null, "emptySet", listOf(), typeArgumentsConverted, false)
|
||||
},
|
||||
|
||||
COLLECTIONS_EMPTY_MAP("java.util.Collections", "emptyMap", 0) {
|
||||
COLLECTIONS_EMPTY_MAP(Collections::class.java.name, "emptyMap", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(null, "emptyMap", listOf(), typeArgumentsConverted, false)
|
||||
},
|
||||
|
||||
COLLECTIONS_SINGLETON_LIST("java.util.Collections", "singletonList", 1) {
|
||||
COLLECTIONS_SINGLETON_LIST(Collections::class.java.name, "singletonList", 1) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(null, "listOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false)
|
||||
},
|
||||
|
||||
COLLECTIONS_SINGLETON("java.util.Collections", "singleton", 1) {
|
||||
COLLECTIONS_SINGLETON(Collections::class.java.name, "singleton", 1) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(null, "setOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false)
|
||||
},
|
||||
@@ -135,15 +221,16 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
|
||||
},
|
||||
|
||||
STRING_JOIN(JAVA_LANG_STRING, "join", 2) {
|
||||
override fun matches(method: PsiMethod)
|
||||
= super.matches(method) && method.parameterList.parameters.last().type.canonicalText == "java.lang.Iterable<? extends java.lang.CharSequence>"
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean
|
||||
= super.matches(method, superMethodsSearcher) && method.parameterList.parameters.last().type.canonicalText == "java.lang.Iterable<? extends java.lang.CharSequence>"
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression?
|
||||
= MethodCallExpression.buildNotNull(codeConverter.convertExpression(arguments[1]), "joinToString", codeConverter.convertExpressions(arguments.take(1)), emptyList())
|
||||
},
|
||||
|
||||
STRING_JOIN_VARARG(JAVA_LANG_STRING, "join", null) {
|
||||
override fun matches(method: PsiMethod): Boolean = super.matches(method) && method.parameterList.let { it.parametersCount == 2 && it.parameters.last().isVarArgs }
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean
|
||||
= super.matches(method, superMethodsSearcher) && method.parameterList.let { it.parametersCount == 2 && it.parameters.last().isVarArgs }
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
|
||||
if (arguments.size() == 2 && arguments.last().isAssignableToCharSequenceArray()) {
|
||||
@@ -186,59 +273,101 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
|
||||
},
|
||||
|
||||
STRING_FORMAT_WITH_LOCALE(JAVA_LANG_STRING, "format", null) {
|
||||
override fun matches(method: PsiMethod)
|
||||
= super.matches(method) &&
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean
|
||||
= super.matches(method, superMethodsSearcher) &&
|
||||
method.parameterList.parametersCount == 3 &&
|
||||
method.parameterList.parameters.let { it.first().type.canonicalText == "java.util.Locale" && it.last().isVarArgs }
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(codeConverter.convertExpression(arguments[1]), "format", codeConverter.convertExpressions(listOf(arguments[0]) + arguments.drop(2)), emptyList(), false)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
|
||||
if (arguments.size() < 2) return null // incorrect call
|
||||
return MethodCallExpression.build(codeConverter.convertExpression(arguments[1]), "format", codeConverter.convertExpressions(listOf(arguments[0]) + arguments.drop(2)), emptyList(), false)
|
||||
}
|
||||
},
|
||||
|
||||
STRING_FORMAT(JAVA_LANG_STRING, "format", null) {
|
||||
override fun matches(method: PsiMethod): Boolean {
|
||||
return super.matches(method) &&
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean {
|
||||
return super.matches(method, superMethodsSearcher) &&
|
||||
method.parameterList.parametersCount == 2 &&
|
||||
method.parameterList.parameters.last().isVarArgs
|
||||
}
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(codeConverter.convertExpression(arguments.first()), "format", codeConverter.convertExpressions(arguments.drop(1)), emptyList(), false)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
|
||||
if (arguments.isEmpty()) return null // incorrect call
|
||||
return MethodCallExpression.build(codeConverter.convertExpression(arguments.first()), "format", codeConverter.convertExpressions(arguments.drop(1)), emptyList(), false)
|
||||
}
|
||||
},
|
||||
|
||||
STRING_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "valueOf", null) {
|
||||
override fun matches(method: PsiMethod)
|
||||
= matchesClass(method) &&
|
||||
(matchesName(method) || matchesName(method, "copyValueOf")) &&
|
||||
method.parameterList.parametersCount.let { it == 1 || it == 3} &&
|
||||
method.parameterList.parameters.first().type.canonicalText == "char[]"
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean {
|
||||
return super.matches(method, superMethodsSearcher)
|
||||
&& method.parameterList.parametersCount.let { it == 1 || it == 3}
|
||||
&& method.parameterList.parameters.first().type.canonicalText == "char[]"
|
||||
}
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(null, "String", codeConverter.convertExpressions(arguments), emptyList(), false)
|
||||
},
|
||||
|
||||
STRING_COPY_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "copyValueOf", null) {
|
||||
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean {
|
||||
return super.matches(method, superMethodsSearcher)
|
||||
&& method.parameterList.parametersCount.let { it == 1 || it == 3 }
|
||||
&& method.parameterList.parameters.first().type.canonicalText == "char[]"
|
||||
}
|
||||
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= STRING_VALUE_OF_CHAR_ARRAY.convertCall(qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
STRING_VALUE_OF(JAVA_LANG_STRING, "valueOf", 1) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.build(codeConverter.convertExpression(arguments.single()), "toString", emptyList(), emptyList(), false)
|
||||
},
|
||||
|
||||
SYSTEM_OUT_PRINTLN("java.io.PrintStream", "println", null) {
|
||||
SYSTEM_OUT_PRINTLN(PrintStream::class.java.name, "println", null) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertSystemOutMethodCall(methodName, qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
},
|
||||
|
||||
SYSTEM_OUT_PRINT("java.io.PrintStream", "print", null) {
|
||||
SYSTEM_OUT_PRINT(PrintStream::class.java.name, "print", null) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= convertSystemOutMethodCall(methodName, qualifier, arguments, typeArgumentsConverted, codeConverter)
|
||||
};
|
||||
|
||||
open fun matches(method: PsiMethod): Boolean = matchesName(method) && matchesClass(method) && matchesParameterCount(method)
|
||||
open fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean
|
||||
= method.name == methodName && matchesClass(method, superMethodsSearcher) && matchesParameterCount(method)
|
||||
|
||||
protected fun matchesClass(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean {
|
||||
if (qualifiedClassName == null) return true
|
||||
val superMethods = superMethodsSearcher.findDeepestSuperMethods(method)
|
||||
return if (superMethods.isEmpty())
|
||||
method.containingClass?.qualifiedName == qualifiedClassName
|
||||
else
|
||||
superMethods.any { it.containingClass?.qualifiedName == qualifiedClassName }
|
||||
}
|
||||
|
||||
protected fun matchesName(method: PsiMethod, name: String? = null) = method.name == (name ?: methodName)
|
||||
protected fun matchesClass(method: PsiMethod) = qualifiedClassName == null || method.containingClass?.qualifiedName == qualifiedClassName
|
||||
protected fun matchesParameterCount(method: PsiMethod) = parameterCount == null || parameterCount == method.parameterList.parametersCount
|
||||
|
||||
abstract fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression?
|
||||
|
||||
protected fun convertMethodCallToPropertyUse(codeConverter: CodeConverter, qualifier: PsiExpression?, propertyName: String = methodName): Expression {
|
||||
val identifier = Identifier(propertyName, false).assignNoPrototype()
|
||||
return if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
|
||||
}
|
||||
|
||||
protected fun convertWithChangedName(name: String, qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
|
||||
= MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), name, codeConverter.convertExpressions(arguments), typeArgumentsConverted)
|
||||
|
||||
companion object {
|
||||
private val valuesByName = values().groupBy { it.methodName }
|
||||
|
||||
fun match(method: PsiMethod, argumentCount: Int, services: JavaToKotlinConverterServices): SpecialMethod? {
|
||||
val candidates = valuesByName[method.name] ?: return null
|
||||
return candidates
|
||||
.firstOrNull { it.matches(method, services.superMethodsSearcher) }
|
||||
?.check { it.parameterCount == null || it.parameterCount == argumentCount } // if parameterCount is specified we should make sure that argument count is correct
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertSystemOutMethodCall(
|
||||
|
||||
Vendored
+2
@@ -6,6 +6,8 @@ public open class KotlinClass(public var field: Int) {
|
||||
|
||||
public open fun foo(mutableCollection: MutableCollection<String>, nullableCollection: Collection<Int>?): MutableList<Any> = arrayListOf()
|
||||
|
||||
fun get(i: Int) = 0
|
||||
|
||||
companion object {
|
||||
public fun staticFun(p: Int): Int = p
|
||||
public var staticVar: Int = 1
|
||||
|
||||
@@ -6,6 +6,6 @@ internal class Foo {
|
||||
fun foo(o: HashSet<Any?>?) {
|
||||
val o2: HashSet<Any?>? = o
|
||||
var foo: Int = 0
|
||||
foo = o2!!.size()
|
||||
foo = o2!!.size
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,6 @@ internal class Foo {
|
||||
fun foo(o: HashSet<Any>) {
|
||||
val o2 = o
|
||||
var foo = 0
|
||||
foo = o2.size()
|
||||
foo = o2.size
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import java.util.HashMap;
|
||||
import kotlinApi.KotlinClass;
|
||||
|
||||
class X {
|
||||
int get(int index) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class C {
|
||||
String foo(HashMap<String, String> map) {
|
||||
return map.get("a");
|
||||
}
|
||||
|
||||
int foo(X x) {
|
||||
return x.get(0);
|
||||
}
|
||||
|
||||
int foo(KotlinClass kotlinClass) {
|
||||
return kotlinClass.get(0); // not operator!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// ERROR: Type mismatch: inferred type is kotlin.String? but kotlin.String was expected
|
||||
import java.util.HashMap
|
||||
import kotlinApi.KotlinClass
|
||||
|
||||
internal class X {
|
||||
fun get(index: Int): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
internal class C {
|
||||
fun foo(map: HashMap<String, String>): String {
|
||||
return map["a"]
|
||||
}
|
||||
|
||||
fun foo(x: X): Int {
|
||||
return x.get(0)
|
||||
}
|
||||
|
||||
fun foo(kotlinClass: KotlinClass): Int {
|
||||
return kotlinClass.get(0) // not operator!
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
internal class C {
|
||||
fun foo(o: Any) {
|
||||
if (o is String) {
|
||||
val l = o.length()
|
||||
val l = o.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
internal class C {
|
||||
fun foo(o: Any) {
|
||||
if (o is String) {
|
||||
val l = o.length()
|
||||
val l = o.length
|
||||
val substring = o.substring(l - 2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ internal class A// this is a primary constructor
|
||||
} // end of primary constructor body
|
||||
|
||||
// this is a secondary constructor 2
|
||||
constructor(s: String) : this(s.length()) {
|
||||
constructor(s: String) : this(s.length) {
|
||||
} // end of secondary constructor 2 body
|
||||
}// this is a secondary constructor 1
|
||||
// end of secondary constructor 1 body
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
internal open class Base(o: Any, l: Int)
|
||||
|
||||
internal class C(private val string: String) : Base(string, string.length())
|
||||
internal class C(private val string: String) : Base(string, string.length)
|
||||
|
||||
@@ -1 +1 @@
|
||||
internal class C @JvmOverloads constructor(private val string: String, a: Int = string.length())
|
||||
internal class C @JvmOverloads constructor(private val string: String, a: Int = string.length)
|
||||
|
||||
@@ -2,6 +2,6 @@ internal enum class Color : Runnable {
|
||||
WHITE, BLACK, RED, YELLOW, BLUE;
|
||||
|
||||
override fun run() {
|
||||
println("name()=" + name() + ", toString()=" + toString())
|
||||
println("name()=" + name + ", toString()=" + toString())
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class A {
|
||||
internal fun foo(collection: Collection<String>) {
|
||||
for (i in collection.size() downTo 0) {
|
||||
for (i in collection.size downTo 0) {
|
||||
println(i)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
internal object Test {
|
||||
fun toFileSystemSafeName(name: String): String {
|
||||
val size = name.length()
|
||||
val size = name.length
|
||||
return name
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,6 +2,6 @@ import kotlinApi.*
|
||||
|
||||
internal class A {
|
||||
fun foo(t: KotlinTrait): Int {
|
||||
return t.nullableFun()!!.length() + t.notNullableFun().length()
|
||||
return t.nullableFun()!!.length + t.notNullableFun().length
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,6 @@ import kotlinApi.*
|
||||
|
||||
internal class A {
|
||||
fun foo(c: KotlinClass): Int {
|
||||
return c.nullableProperty!!.length() + c.property.length() + KotlinClass.nullableStaticVar!! + KotlinClass.staticVar + KotlinClass.nullableStaticFun(1)!! + KotlinClass.staticFun(1) + nullableGlobalFunction("")!!.length() + globalFunction("").length()
|
||||
return c.nullableProperty!!.length + c.property.length + KotlinClass.nullableStaticVar!! + KotlinClass.staticVar + KotlinClass.nullableStaticFun(1)!! + KotlinClass.staticFun(1) + nullableGlobalFunction("")!!.length + globalFunction("").length
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import java.util.*;
|
||||
|
||||
enum E {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
class A {
|
||||
void foo(List<String> list, Collection<Integer> collection, Map<Integer, Integer> map) {
|
||||
int a = "".length();
|
||||
String b = E.A.name();
|
||||
int c = E.A.ordinal();
|
||||
int d = list.size() + collection.size();
|
||||
int e = map.size();
|
||||
int f = map.keySet().size();
|
||||
int g = map.values().size();
|
||||
int h = map.entrySet().size();
|
||||
}
|
||||
|
||||
void bar(List<String> list) {
|
||||
char c = "a".charAt(0);
|
||||
byte b = new Integer(10).byteValue();
|
||||
int i = new Double(10.1).intValue();
|
||||
float f = new Double(10.1).floatValue();
|
||||
long l = new Double(10.1).longValue();
|
||||
short s = new Double(10.1).shortValue();
|
||||
|
||||
String removed = list.remove(10);
|
||||
Boolean isRemoved = list.remove("a");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import java.util.*
|
||||
|
||||
internal enum class E {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
internal class A {
|
||||
fun foo(list: List<String>, collection: Collection<Int>, map: Map<Int, Int>) {
|
||||
val a = "".length
|
||||
val b = E.A.name
|
||||
val c = E.A.ordinal
|
||||
val d = list.size + collection.size
|
||||
val e = map.size
|
||||
val f = map.keys.size
|
||||
val g = map.values.size
|
||||
val h = map.entries.size
|
||||
}
|
||||
|
||||
fun bar(list: MutableList<String>) {
|
||||
val c = "a"[0]
|
||||
val b = 10.toByte()
|
||||
val i = 10.1.toInt()
|
||||
val f = 10.1.toFloat()
|
||||
val l = 10.1.toLong()
|
||||
val s = 10.1.toShort()
|
||||
|
||||
val removed = list.removeAt(10)
|
||||
val isRemoved = list.remove("a")
|
||||
}
|
||||
}
|
||||
@@ -25,12 +25,12 @@ internal class A {
|
||||
|
||||
fun normalMethods() {
|
||||
val s = "test string"
|
||||
s.length()
|
||||
s.length
|
||||
s.isEmpty()
|
||||
s.charAt(1)
|
||||
s[1]
|
||||
s.codePointAt(2)
|
||||
s.codePointBefore(2)
|
||||
s.codePointCount(0, s.length())
|
||||
s.codePointCount(0, s.length)
|
||||
s.offsetByCodePoints(0, 4)
|
||||
s.compareTo("test 2")
|
||||
s.concat(" another")
|
||||
|
||||
@@ -6,7 +6,7 @@ internal class A {
|
||||
}
|
||||
|
||||
fun bar(collection: MutableCollection<String>) {
|
||||
if (collection.size() < 5) {
|
||||
if (collection.size < 5) {
|
||||
foo(collection)
|
||||
} else {
|
||||
collection.add("a")
|
||||
|
||||
@@ -4,6 +4,6 @@ internal class C {
|
||||
}
|
||||
|
||||
fun foo(): Int {
|
||||
return getString(true)!!.length()
|
||||
return getString(true)!!.length
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun foo(s: String?, b: Boolean): Int {
|
||||
if (s == null) println("null")
|
||||
if (b) return s!!.length()
|
||||
if (b) return s!!.length
|
||||
return 10
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
internal class A {
|
||||
fun foo(s: String?): Int {
|
||||
if (s != null) {
|
||||
return s.length()
|
||||
return s.length
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -955,6 +955,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/codeSimplifications"), Pattern.compile("^(.+)\\.java$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("GetOperator.java")
|
||||
public void testGetOperator() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/codeSimplifications/GetOperator.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("IfNullReturnToElvis.java")
|
||||
public void testIfNullReturnToElvis() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/codeSimplifications/IfNullReturnToElvis.java");
|
||||
@@ -3148,6 +3154,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("specialBuiltinMembers.java")
|
||||
public void testSpecialBuiltinMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/specialBuiltinMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stringMethods.java")
|
||||
public void testStringMethods() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/stringMethods.java");
|
||||
|
||||
@@ -955,6 +955,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/codeSimplifications"), Pattern.compile("^(.+)\\.java$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("GetOperator.java")
|
||||
public void testGetOperator() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/codeSimplifications/GetOperator.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("IfNullReturnToElvis.java")
|
||||
public void testIfNullReturnToElvis() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/codeSimplifications/IfNullReturnToElvis.java");
|
||||
@@ -3148,6 +3154,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("specialBuiltinMembers.java")
|
||||
public void testSpecialBuiltinMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/specialBuiltinMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stringMethods.java")
|
||||
public void testStringMethods() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/methodCallExpression/stringMethods.java");
|
||||
|
||||
Reference in New Issue
Block a user