From cfc09048c6a795dad45a6edda60f56e9d5fd963f Mon Sep 17 00:00:00 2001 From: vldf Date: Wed, 29 Jul 2020 11:50:34 +0300 Subject: [PATCH] [FIR] Add RedundantCallOfConversionMethod checker --- .../StringTemplate.kt | 3 + .../StringTemplate.txt | 7 ++ .../booleanToInt.kt | 7 ++ .../booleanToInt.txt | 15 +++ .../RedundantCallOfConversionMethod/byte.kt | 2 + .../RedundantCallOfConversionMethod/byte.txt | 3 + .../RedundantCallOfConversionMethod/char.kt | 2 + .../RedundantCallOfConversionMethod/char.txt | 3 + .../RedundantCallOfConversionMethod/double.kt | 2 + .../double.txt | 3 + .../RedundantCallOfConversionMethod/float.kt | 2 + .../RedundantCallOfConversionMethod/float.txt | 3 + .../RedundantCallOfConversionMethod/int.kt | 2 + .../RedundantCallOfConversionMethod/int.txt | 3 + .../RedundantCallOfConversionMethod/long.kt | 2 + .../RedundantCallOfConversionMethod/long.txt | 3 + .../nullable.kt | 5 + .../nullable.txt | 4 + .../nullable2.kt | 7 ++ .../nullable2.txt | 17 +++ .../safeString.kt | 6 + .../safeString.txt | 5 + .../safeString2.kt | 6 + .../safeString2.txt | 17 +++ .../RedundantCallOfConversionMethod/short.kt | 2 + .../RedundantCallOfConversionMethod/short.txt | 3 + .../RedundantCallOfConversionMethod/string.kt | 2 + .../string.txt | 3 + .../toOtherType.kt | 3 + .../toOtherType.txt | 3 + .../RedundantCallOfConversionMethod/uByte.kt | 4 + .../RedundantCallOfConversionMethod/uByte.txt | 4 + .../RedundantCallOfConversionMethod/uInt.kt | 4 + .../RedundantCallOfConversionMethod/uInt.txt | 4 + .../RedundantCallOfConversionMethod/uLong.kt | 4 + .../RedundantCallOfConversionMethod/uLong.txt | 4 + .../RedundantCallOfConversionMethod/uShort.kt | 4 + .../uShort.txt | 4 + .../variable.kt | 3 + .../variable.txt | 5 + .../ExtendedFirDiagnosticsTestGenerated.java | 113 ++++++++++++++++++ .../expression/DefaultExpressionCheckers.kt | 3 + .../RedundantCallOfConversionMethod.kt | 76 ++++++++++++ .../fir/analysis/diagnostics/FirErrors.kt | 3 +- 44 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.txt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.kt create mode 100644 compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.txt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantCallOfConversionMethod.kt diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.kt new file mode 100644 index 00000000000..3c918e0f098 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.kt @@ -0,0 +1,3 @@ +interface IC { + fun toString(x: String): String = "IC$x" +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.txt new file mode 100644 index 00000000000..9f7cdfd277f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.txt @@ -0,0 +1,7 @@ +FILE: StringTemplate.kt + public abstract interface IC : R|kotlin/Any| { + public open fun toString(x: R|kotlin/String|): R|kotlin/String| { + ^toString (String(IC), R|/x|.R|kotlin/Any.toString|()) + } + + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.kt new file mode 100644 index 00000000000..8a14ecb9e3a --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false + +fun Boolean.toInt() = if (this) 1 else 0 + +fun test(x: Int, y: Int): Int { + return (x > y).toInt() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.txt new file mode 100644 index 00000000000..0987c8fca5c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.txt @@ -0,0 +1,15 @@ +FILE: booleanToInt.kt + public final fun R|kotlin/Boolean|.toInt(): R|kotlin/Int| { + ^toInt when () { + this@R|/toInt| -> { + Int(1) + } + else -> { + Int(0) + } + } + + } + public final fun test(x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Int| { + ^test CMP(>, R|/x|.R|kotlin/Int.compareTo|(R|/y|)).R|/toInt|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.kt new file mode 100644 index 00000000000..a922fb28fc7 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = Byte.MAX_VALUE.toByte() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.txt new file mode 100644 index 00000000000..811cd12a92a --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.txt @@ -0,0 +1,3 @@ +FILE: byte.kt + public final val foo: R|kotlin/Byte| = Q|kotlin/Byte|.R|kotlin/Byte.Companion.MAX_VALUE|.R|kotlin/Byte.toByte|() + public get(): R|kotlin/Byte| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.kt new file mode 100644 index 00000000000..0e61ad3a209 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = 'a'.toChar() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.txt new file mode 100644 index 00000000000..9684416612d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.txt @@ -0,0 +1,3 @@ +FILE: char.kt + public final val foo: R|kotlin/Char| = Char(a).R|kotlin/Char.toChar|() + public get(): R|kotlin/Char| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.kt new file mode 100644 index 00000000000..0d9ae8046e8 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = 1.1.toDouble() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.txt new file mode 100644 index 00000000000..27b697e1fea --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.txt @@ -0,0 +1,3 @@ +FILE: double.kt + public final val foo: R|kotlin/Double| = Double(1.1).R|kotlin/Double.toDouble|() + public get(): R|kotlin/Double| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.kt new file mode 100644 index 00000000000..13cc81a9964 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = 1.1f.toFloat() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.txt new file mode 100644 index 00000000000..265cfe9e549 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.txt @@ -0,0 +1,3 @@ +FILE: float.kt + public final val foo: R|kotlin/Float| = Float(1.1).R|kotlin/Float.toFloat|() + public get(): R|kotlin/Float| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.kt new file mode 100644 index 00000000000..07ba241ee66 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = 1.toInt() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.txt new file mode 100644 index 00000000000..cedb43319a0 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.txt @@ -0,0 +1,3 @@ +FILE: int.kt + public final val foo: R|kotlin/Int| = Int(1).R|kotlin/Int.toInt|() + public get(): R|kotlin/Int| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.kt new file mode 100644 index 00000000000..04f9eef34bd --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = Long.MAX_VALUE.toLong() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.txt new file mode 100644 index 00000000000..156fdaf55fa --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.txt @@ -0,0 +1,3 @@ +FILE: long.kt + public final val foo: R|kotlin/Long| = Q|kotlin/Long|.R|kotlin/Long.Companion.MAX_VALUE|.R|kotlin/Long.toLong|() + public get(): R|kotlin/Long| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.kt new file mode 100644 index 00000000000..d43f6516445 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +fun foo(s: String?) { + val t: String = s.toString() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.txt new file mode 100644 index 00000000000..d7ecdbcd880 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.txt @@ -0,0 +1,4 @@ +FILE: nullable.kt + public final fun foo(s: R|kotlin/String?|): R|kotlin/Unit| { + lval t: R|kotlin/String| = R|/s|.R|kotlin/toString|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.kt new file mode 100644 index 00000000000..a170902eb5d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME +data class Foo(val name: String) + +fun nullable2(foo: Foo?) { + val s: String = foo?.name.toString() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.txt new file mode 100644 index 00000000000..65ce0bd6660 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.txt @@ -0,0 +1,17 @@ +FILE: nullable2.kt + public final data class Foo : R|kotlin/Any| { + public constructor(name: R|kotlin/String|): R|Foo| { + super() + } + + public final val name: R|kotlin/String| = R|/name| + public get(): R|kotlin/String| + + public final fun component1(): R|kotlin/String| + + public final fun copy(name: R|kotlin/String| = this@R|/Foo|.R|/Foo.name|): R|Foo| + + } + public final fun nullable2(foo: R|Foo?|): R|kotlin/Unit| { + lval s: R|kotlin/String| = R|/foo|?.{ $subj$.R|/Foo.name| }.R|kotlin/toString|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt new file mode 100644 index 00000000000..117eefbbe6a --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME + +fun test() { + val foo: String? = null + foo?.toString() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.txt new file mode 100644 index 00000000000..7612e0d4c56 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.txt @@ -0,0 +1,5 @@ +FILE: safeString.kt + public final fun test(): R|kotlin/Unit| { + lval foo: R|kotlin/String?| = Null(null) + R|/foo|?.{ $subj$.R|kotlin/Any.toString|() } + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt new file mode 100644 index 00000000000..650024a7204 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +data class Foo(val name: String) + +fun test(foo: Foo?) { + val s: String? = foo?.name?.toString() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.txt new file mode 100644 index 00000000000..0e76b7f9b95 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.txt @@ -0,0 +1,17 @@ +FILE: safeString2.kt + public final data class Foo : R|kotlin/Any| { + public constructor(name: R|kotlin/String|): R|Foo| { + super() + } + + public final val name: R|kotlin/String| = R|/name| + public get(): R|kotlin/String| + + public final fun component1(): R|kotlin/String| + + public final fun copy(name: R|kotlin/String| = this@R|/Foo|.R|/Foo.name|): R|Foo| + + } + public final fun test(foo: R|Foo?|): R|kotlin/Unit| { + lval s: R|kotlin/String?| = R|/foo|?.{ $subj$.R|/Foo.name| }?.{ $subj$.R|kotlin/Any.toString|() } + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.kt new file mode 100644 index 00000000000..bb7f0fd2f92 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = Short.MAX_VALUE.toShort() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.txt new file mode 100644 index 00000000000..a9814617832 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.txt @@ -0,0 +1,3 @@ +FILE: short.kt + public final val foo: R|kotlin/Short| = Q|kotlin/Short|.R|kotlin/Short.Companion.MAX_VALUE|.R|kotlin/Short.toShort|() + public get(): R|kotlin/Short| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.kt new file mode 100644 index 00000000000..3bf11b5871f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val foo = "".toString() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.txt new file mode 100644 index 00000000000..c7e85f7512c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.txt @@ -0,0 +1,3 @@ +FILE: string.kt + public final val foo: R|kotlin/String| = String().R|kotlin/Any.toString|() + public get(): R|kotlin/String| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.kt new file mode 100644 index 00000000000..36505c82816 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.kt @@ -0,0 +1,3 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +val foo = 1.toLong() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.txt new file mode 100644 index 00000000000..48a735da48d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.txt @@ -0,0 +1,3 @@ +FILE: toOtherType.kt + public final val foo: R|kotlin/Long| = Int(1).R|kotlin/Int.toLong|() + public get(): R|kotlin/Long| diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.kt new file mode 100644 index 00000000000..65588def258 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun test(i: UByte) { + val foo = i.toUByte() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.txt new file mode 100644 index 00000000000..8e123eaa858 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.txt @@ -0,0 +1,4 @@ +FILE: uByte.kt + public final fun test(i: R|kotlin/UByte|): R|kotlin/Unit| { + lval foo: R|kotlin/UByte| = R|/i|.R|kotlin/UByte.toUByte|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.kt new file mode 100644 index 00000000000..5206cec1733 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun test(i: UInt) { + val foo = i.toUInt() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.txt new file mode 100644 index 00000000000..d9a0e8568ec --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.txt @@ -0,0 +1,4 @@ +FILE: uInt.kt + public final fun test(i: R|kotlin/UInt|): R|kotlin/Unit| { + lval foo: R|kotlin/UInt| = R|/i|.R|kotlin/UInt.toUInt|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.kt new file mode 100644 index 00000000000..b4000455e91 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun test(i: ULong) { + val foo = i.toULong() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.txt new file mode 100644 index 00000000000..5fd3aa5cac8 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.txt @@ -0,0 +1,4 @@ +FILE: uLong.kt + public final fun test(i: R|kotlin/ULong|): R|kotlin/Unit| { + lval foo: R|kotlin/ULong| = R|/i|.R|kotlin/ULong.toULong|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.kt new file mode 100644 index 00000000000..2ef3e96deb7 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun test(i: UShort) { + val foo = i.toUShort() +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.txt new file mode 100644 index 00000000000..aea8e9ae678 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.txt @@ -0,0 +1,4 @@ +FILE: uShort.kt + public final fun test(i: R|kotlin/UShort|): R|kotlin/Unit| { + lval foo: R|kotlin/UShort| = R|/i|.R|kotlin/UShort.toUShort|() + } diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.kt new file mode 100644 index 00000000000..63f7a2da8dd --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.kt @@ -0,0 +1,3 @@ +// WITH_RUNTIME +val foo = "" +val bar = foo.toString() \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.txt new file mode 100644 index 00000000000..3b5be0d51b2 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.txt @@ -0,0 +1,5 @@ +FILE: variable.kt + public final val foo: R|kotlin/String| = String() + public get(): R|kotlin/String| + public final val bar: R|kotlin/String| = R|/foo|.R|kotlin/Any.toString|() + public get(): R|kotlin/String| diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java index fbe0fe3972e..b92ee170343 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java @@ -166,6 +166,119 @@ public class ExtendedFirDiagnosticsTestGenerated extends AbstractExtendedFirDiag } } + @TestMetadata("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantCallOfConversionMethod extends AbstractExtendedFirDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInRedundantCallOfConversionMethod() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("booleanToInt.kt") + public void testBooleanToInt() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.kt"); + } + + @TestMetadata("byte.kt") + public void testByte() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/byte.kt"); + } + + @TestMetadata("char.kt") + public void testChar() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/char.kt"); + } + + @TestMetadata("double.kt") + public void testDouble() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/double.kt"); + } + + @TestMetadata("float.kt") + public void testFloat() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/float.kt"); + } + + @TestMetadata("int.kt") + public void testInt() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/int.kt"); + } + + @TestMetadata("long.kt") + public void testLong() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/long.kt"); + } + + @TestMetadata("nullable.kt") + public void testNullable() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable.kt"); + } + + @TestMetadata("nullable2.kt") + public void testNullable2() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/nullable2.kt"); + } + + @TestMetadata("safeString.kt") + public void testSafeString() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt"); + } + + @TestMetadata("safeString2.kt") + public void testSafeString2() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt"); + } + + @TestMetadata("short.kt") + public void testShort() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/short.kt"); + } + + @TestMetadata("string.kt") + public void testString() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/string.kt"); + } + + @TestMetadata("StringTemplate.kt") + public void testStringTemplate() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.kt"); + } + + @TestMetadata("toOtherType.kt") + public void testToOtherType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.kt"); + } + + @TestMetadata("uByte.kt") + public void testUByte() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uByte.kt"); + } + + @TestMetadata("uInt.kt") + public void testUInt() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uInt.kt"); + } + + @TestMetadata("uLong.kt") + public void testULong() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uLong.kt"); + } + + @TestMetadata("uShort.kt") + public void testUShort() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/uShort.kt"); + } + + @TestMetadata("variable.kt") + public void testVariable() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/variable.kt"); + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/extendedCheckers/emptyRangeChecker") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/DefaultExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/DefaultExpressionCheckers.kt index 6f554dc5aac..61bbf9f2b27 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/DefaultExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/DefaultExpressionCheckers.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression +import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantCallOfConversionMethod + object CommonExpressionCheckers : ExpressionCheckers() { override val expressionCheckers: List = listOf() override val qualifiedAccessCheckers: List = listOf( @@ -16,6 +18,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirProjectionsOnNonClassTypeArgumentChecker, FirUpperBoundViolatedChecker, FirTypeArgumentsNotAllowedExpressionChecker, + RedundantCallOfConversionMethod ) override val functionCallCheckers: List = listOf() } \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantCallOfConversionMethod.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantCallOfConversionMethod.kt new file mode 100644 index 00000000000..410afc87589 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantCallOfConversionMethod.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.checkers.extended + +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.expressions.FirConstExpression +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.psi +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.types.ConeFlexibleType +import org.jetbrains.kotlin.fir.types.classId +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.isMarkedNullable +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.psi.KtBinaryExpression +import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression +import org.jetbrains.kotlin.types.expressions.OperatorConventions + +object RedundantCallOfConversionMethod : FirQualifiedAccessChecker() { + override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { + if (functionCall !is FirFunctionCall) return + if (functionCall.source?.kind == FirFakeSourceElementKind.GeneratedToStringCallOnTemplateEntry) return + val functionName = functionCall.calleeReference.name.asString() + val qualifiedType = targetClassMap[functionName] ?: return + + if (functionCall.explicitReceiver?.isRedundant(qualifiedType) == true) { + reporter.report(functionCall.source, FirErrors.REDUNDANT_CALL_OF_CONVERSION_METHOD) + } + } + + private val targetClassMap = mapOf( + "toString" to StandardClassIds.String, + "toDouble" to StandardClassIds.Double, + "toFloat" to StandardClassIds.Float, + "toLong" to StandardClassIds.Long, + "toInt" to StandardClassIds.Int, + "toChar" to StandardClassIds.Char, + "toShort" to StandardClassIds.Short, + "toByte" to StandardClassIds.Byte, + "toULong" to StandardClassIds.ULong, + "toUInt" to StandardClassIds.UInt, + "toUShort" to StandardClassIds.UShort, + "toUByte" to StandardClassIds.UByte + ) + + private fun FirExpression.isRedundant(qualifiedClassId: ClassId): Boolean { + val thisType = if (this is FirConstExpression<*>) { + this.typeRef.coneType.classId + } else { + val binaryExpression = psi as? KtBinaryExpression + val operator = binaryExpression?.operationToken + if (operator in OperatorConventions.COMPARISON_OPERATIONS) { + // Special case here because compareTo returns Int + StandardClassIds.Boolean + } else { + when { + typeRef.coneType is ConeFlexibleType -> null + psi?.parent !is KtSafeQualifiedExpression + && (psi is KtSafeQualifiedExpression || typeRef.coneType.isMarkedNullable) -> null + this.typeRef.coneType.isMarkedNullable -> null + else -> this.typeRef.coneType.classId + } + } + } + return thisType == qualifiedClassId + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 7c71ed884cd..49712c5d754 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -104,8 +104,7 @@ object FirErrors { val REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE by warning0() val CAN_BE_VAL by warning0() val CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT by warning0() + val REDUNDANT_CALL_OF_CONVERSION_METHOD by warning0() val ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS by warning0() val EMPTY_RANGE by warning0() } - -