Detect redundant 'is' check

#KT-14187 Fixed
This commit is contained in:
Dmitry Neverov
2017-05-01 08:27:25 +02:00
committed by Mikhail Zarechenskiy
parent 768e0fa738
commit cd24adac32
36 changed files with 123 additions and 76 deletions
+2 -2
View File
@@ -18,11 +18,11 @@ class MyColor(val x: Color.<!ENUM_ENTRY_AS_TYPE!>RED<!>, y: Color.<!ENUM_ENTRY_A
fun local(arg: Color.<!ENUM_ENTRY_AS_TYPE!>RED<!>): Color.<!ENUM_ENTRY_AS_TYPE!>RED<!> = arg
val temp: Color.<!ENUM_ENTRY_AS_TYPE!>RED<!> = <!TYPE_MISMATCH!>Color.RED<!>
temp <!USELESS_CAST!>as? Color.<!ENUM_ENTRY_AS_TYPE!>RED<!><!>
if (temp is <!IS_ENUM_ENTRY!>Color.<!ENUM_ENTRY_AS_TYPE!>RED<!><!>) {
if (<!USELESS_IS_CHECK!>temp is <!IS_ENUM_ENTRY!>Color.<!ENUM_ENTRY_AS_TYPE!>RED<!><!><!>) {
return temp <!USELESS_CAST!>as Color.<!ENUM_ENTRY_AS_TYPE!>RED<!><!>
}
val obj = object : Color.<!ENUM_ENTRY_AS_TYPE!>RED<!> {}
if (obj is <!IS_ENUM_ENTRY!>Color.<!ENUM_ENTRY_AS_TYPE!>RED<!><!>) {
if (<!USELESS_IS_CHECK!>obj is <!IS_ENUM_ENTRY!>Color.<!ENUM_ENTRY_AS_TYPE!>RED<!><!><!>) {
return obj
}
return <!TYPE_MISMATCH!>Color.RED<!>
+20 -1
View File
@@ -1,7 +1,26 @@
// FILE: KotlinFile.kt
fun test() {
if (1 is Int) {
if (<!USELESS_IS_CHECK!>1 is Int<!>) {
if (1 is <!INCOMPATIBLE_TYPES!>Boolean<!>) {
}
}
A.create() is A
<!USELESS_IS_CHECK!>A.create() is A?<!>
<!UNRESOLVED_REFERENCE!>unresolved<!> is A
<!UNRESOLVED_REFERENCE!>unresolved<!> is A?
val x = foo()
x as String
<!USELESS_IS_CHECK!>x is String<!>
}
fun foo(): Any = ""
// FILE: A.java
class A {
static A create() { return null; }
}
+11
View File
@@ -1,3 +1,14 @@
package
public fun foo(): kotlin.Any
public fun test(): kotlin.Unit
public/*package*/ open class A {
public/*package*/ constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public/*package*/ open fun create(): A!
}
+1 -1
View File
@@ -46,7 +46,7 @@ fun cannotBe() {
<!VARIABLE_EXPECTED!>foo()<!> = Unit;
(<!VARIABLE_EXPECTED!>i <!USELESS_CAST!>as Int<!><!>) = 34
(<!VARIABLE_EXPECTED!>i is Int<!>) = false
(<!USELESS_IS_CHECK, VARIABLE_EXPECTED!>i is Int<!>) = false
<!VARIABLE_EXPECTED!>A()<!> = A()
<!VARIABLE_EXPECTED!>5<!> = 34
}
@@ -45,10 +45,10 @@ fun test(a: Any) {
.0f<!UNSUPPORTED!>in<!> a
.0<!UNSUPPORTED, UNRESOLVED_REFERENCE!>din<!> a
1<!UNSUPPORTED!>is<!> Any
<!USELESS_IS_CHECK!>1<!UNSUPPORTED!>is<!> Any<!>
1<!UNSUPPORTED!>as<!> Any
1<!UNSUPPORTED!>as?<!> Any
1<!UNSUPPORTED!>!is<!> Any
<!USELESS_IS_CHECK!>1<!UNSUPPORTED!>!is<!> Any<!>
1<!UNSUPPORTED!>!in<!> a
}
@@ -31,7 +31,8 @@ fun test(a: Any) {
a <!UNSUPPORTED!>!in<!>'s'
a <!UNSUPPORTED!>!in<!><!EMPTY_CHARACTER_LITERAL!>''<!>
if("s"<!UNSUPPORTED!>is<!> Any) {}
if(<!USELESS_IS_CHECK!>"s"<!UNSUPPORTED!>is<!> Any<!>) {}
if(<!USELESS_IS_CHECK!>"s"<!UNSUPPORTED!>is<!> Any<!>) {}
test("s"<!UNSUPPORTED!>as<!> Any)
a <!UNSUPPORTED!>foo<!>""<!UNSUPPORTED, SYNTAX!>1<!>
@@ -26,7 +26,7 @@ fun foo() {
}
fun bar(a: Ann = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>) {
if (a is Ann) {}
if (<!USELESS_IS_CHECK!>a is Ann<!>) {}
}
operator fun String.invoke() {}
@@ -2,4 +2,4 @@ open class Base<A>
class Some: Base<Int>()
// a is Some => a is Base<Int>
fun f(a: Some) = a is Base<Int>
fun f(a: Some) = <!USELESS_IS_CHECK!>a is Base<Int><!>
@@ -5,4 +5,4 @@ open class Base<in T>
class SubBase: Base<A>()
// f is SubBase => f is Base<A> => (Base<Contravariant T>, B <: A) f is Base<B>
fun test(f: SubBase) = f is Base<B>
fun test(f: SubBase) = <!USELESS_IS_CHECK!>f is Base<B><!>
@@ -5,4 +5,4 @@ open class Base<out T>
class SubBase: Base<B>()
// f is SubBase => (SubBase <: Base<B>) f is Base<B> => (B <: A, Base<Covariant T> => SubBase <: Base<A>) f is Base<A>
fun test(f: SubBase) = f is Base<A>
fun test(f: SubBase) = <!USELESS_IS_CHECK!>f is Base<A><!>
@@ -1 +1 @@
fun f(a: MutableList<out Number>) = a is MutableList<out Any>
fun f(a: MutableList<out Number>) = <!USELESS_IS_CHECK!>a is MutableList<out Any><!>
@@ -1 +1 @@
fun f(a: MutableList<String>) = a is MutableList<out CharSequence>
fun f(a: MutableList<String>) = <!USELESS_IS_CHECK!>a is MutableList<out CharSequence><!>
@@ -1 +1 @@
fun f(a: List<Number>) = a is List<Any>
fun f(a: List<Number>) = <!USELESS_IS_CHECK!>a is List<Any><!>
+1 -1
View File
@@ -1 +1 @@
fun <T> testing(a: T) = a is T
fun <T> testing(a: T) = <!USELESS_IS_CHECK!>a is T<!>
@@ -1,14 +1,14 @@
fun <T, S : T> test(x: T?, y: S, z: T) {
x is <!CANNOT_CHECK_FOR_ERASED!>T<!>
x is T?
<!USELESS_IS_CHECK!>x is T?<!>
y is T
y is S
y is T?
y is S?
<!USELESS_IS_CHECK!>y is T<!>
<!USELESS_IS_CHECK!>y is S<!>
<!USELESS_IS_CHECK!>y is T?<!>
<!USELESS_IS_CHECK!>y is S?<!>
z is T
z is T?
<!USELESS_IS_CHECK!>z is T<!>
<!USELESS_IS_CHECK!>z is T?<!>
<!UNCHECKED_CAST!>null as T<!>
null <!USELESS_CAST!>as T?<!>
@@ -22,6 +22,6 @@ inline fun <reified T> test(x: T?) {
}
fun <T> foo(x: List<T>, y: List<T>?) {
x is List<T>
<!USELESS_IS_CHECK!>x is List<T><!>
y is List<T>
}
@@ -22,17 +22,17 @@ public class JavaClass {
// FILE: test.kt
fun <T, S: Any> test(x1: T, x2: T?, y1: S, y2: S?) {
x1 is T?
x2 is T?
y1 is S<!USELESS_NULLABLE_CHECK!>?<!>
y2 is S?
<!USELESS_IS_CHECK!>x1 is T?<!>
<!USELESS_IS_CHECK!>x2 is T?<!>
<!USELESS_IS_CHECK!>y1 is S<!USELESS_NULLABLE_CHECK!>?<!><!>
<!USELESS_IS_CHECK!>y2 is S?<!>
val f1 = JavaClass.foo()
f1 is Int?
<!USELESS_IS_CHECK!>f1 is Int?<!>
val f2 = JavaClass.fooN()
f2 is Int?
<!USELESS_IS_CHECK!>f2 is Int?<!>
val f3 = JavaClass.fooNN()
f3 is Int<!USELESS_NULLABLE_CHECK!>?<!>
<!USELESS_IS_CHECK!>f3 is Int<!USELESS_NULLABLE_CHECK!>?<!><!>
}
@@ -38,7 +38,7 @@ fun t1(b : Boolean) {
return;
}
doSmth(i)
if (i is Int) {
if (<!USELESS_IS_CHECK!>i is Int<!>) {
return;
}
}
@@ -26,7 +26,7 @@ fun t1(x: Int) = when(<!UNUSED_EXPRESSION!>x<!>) {
}
fun t5(x: Int) = <!NO_ELSE_IN_WHEN!>when<!> (x) {
is Int -> 1
<!USELESS_IS_CHECK!>is Int<!> -> 1
2 -> 2
}
@@ -1,7 +1,7 @@
// !CHECK_TYPE
fun foo(x: Number) {
if ((x as Int) is Int) {
if (<!USELESS_IS_CHECK!>(x as Int) is Int<!>) {
checkSubtype<Int>(<!DEBUG_INFO_SMARTCAST!>x<!>)
}
checkSubtype<Int>(<!DEBUG_INFO_SMARTCAST!>x<!>)
@@ -1,11 +1,11 @@
// !CHECK_TYPE
fun noUselessDataFlowInfoCreation(x: Number) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) {
if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) {
if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) {
if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) {
if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) { if (<!USELESS_IS_CHECK!>x is Int<!>) {
} } } } } } } } } } } } } } } } } } } } } } } } }
}
@@ -7,7 +7,7 @@ class DerivedOuter<G> : SuperOuter<G>() {
}
fun bare(x: SuperOuter<*>.SuperInner<*>, y: Any?) {
if (x is SuperOuter.SuperInner) return
if (<!USELESS_IS_CHECK!>x is SuperOuter.SuperInner<!>) return
if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>SuperOuter.SuperInner<!>) {
return
}
+5 -5
View File
@@ -35,7 +35,7 @@ fun f10(init : A?) {
if (!(a is B)) {
return;
}
if (!(a is B)) {
if (!(<!USELESS_IS_CHECK!>a is B<!>)) {
return;
}
}
@@ -57,7 +57,7 @@ fun f11(a : A?) {
is B -> <!DEBUG_INFO_SMARTCAST!>a<!>.bar()
is A -> <!DEBUG_INFO_SMARTCAST!>a<!>.foo()
is Any -> <!DEBUG_INFO_SMARTCAST!>a<!>.foo()
is Any? -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
<!USELESS_IS_CHECK!>is Any?<!> -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
else -> a?.foo()
}
}
@@ -67,12 +67,12 @@ fun f12(a : A?) {
is B -> <!DEBUG_INFO_SMARTCAST!>a<!>.bar()
is A -> <!DEBUG_INFO_SMARTCAST!>a<!>.foo()
is Any -> <!DEBUG_INFO_SMARTCAST!>a<!>.foo();
is Any? -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
<!USELESS_IS_CHECK!>is Any?<!> -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
is C -> <!DEBUG_INFO_SMARTCAST!>a<!>.bar()
else -> a?.foo()
}
if (a is Any?) {
if (<!USELESS_IS_CHECK!>a is Any?<!>) {
a?.<!UNRESOLVED_REFERENCE!>bar<!>()
}
if (a is B) {
@@ -197,7 +197,7 @@ fun mergeSmartCasts(a: Any?) {
when (a) {
is String, is Any -> a.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
}
if (a is String && a is Any) {
if (a is String && <!USELESS_IS_CHECK!>a is Any<!>) {
val <!UNUSED_VARIABLE!>i<!>: Int = <!DEBUG_INFO_SMARTCAST!>a<!>.compareTo("")
}
if (a is String && <!DEBUG_INFO_SMARTCAST!>a<!>.compareTo("") == 0) {}
+2 -2
View File
@@ -5,6 +5,6 @@ inline public fun reg(converter: (Any) -> Any, flag: Boolean) {
}
public inline fun register(converter: (Any) -> Any) {
<!USAGE_IS_NOT_INLINABLE!>converter<!> is (Any) -> Any
reg(converter, <!USAGE_IS_NOT_INLINABLE!>converter<!> is (Any) -> Any)
<!USELESS_IS_CHECK!><!USAGE_IS_NOT_INLINABLE!>converter<!> is (Any) -> Any<!>
reg(converter, <!USELESS_IS_CHECK!><!USAGE_IS_NOT_INLINABLE!>converter<!> is (Any) -> Any<!>)
}
+1 -1
View File
@@ -5,7 +5,7 @@ inline public fun reg(converter: (Any) -> Any) {
public inline fun register(converter: (Any) -> Any) {
reg(when(<!USAGE_IS_NOT_INLINABLE!>converter<!>) {
is (Any) -> Any -> <!USAGE_IS_NOT_INLINABLE!>converter<!>
<!USELESS_IS_CHECK!>is (Any) -> Any<!> -> <!USAGE_IS_NOT_INLINABLE!>converter<!>
else -> <!USAGE_IS_NOT_INLINABLE!>converter<!>
})
}
@@ -9,7 +9,7 @@ sealed class Expr : Stmt() {
fun test(x: Stmt): String =
when (x) {
is Expr -> "expr"
is Stmt -> "stmt"
<!USELESS_IS_CHECK!>is Stmt<!> -> "stmt"
}
fun test2(x: Stmt): String =
@@ -19,5 +19,5 @@ fun test2(x: Stmt): String =
fun test3(x: Expr): String =
when (x) {
is Stmt -> "stmt"
<!USELESS_IS_CHECK!>is Stmt<!> -> "stmt"
}
@@ -9,7 +9,7 @@ sealed class Sealed {
fun foo(s: Sealed): Int {
return <!NO_ELSE_IN_WHEN!>when<!>(s) {
is Sealed.First -> 1
!is Any -> 0
<!USELESS_IS_CHECK!>!is Any<!> -> 0
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ interface B<T> : A<T>
fun <T> foo(b: A<T>) = b
fun <T> test(a: A<T>) {
if (a is Any) {
if (<!USELESS_IS_CHECK!>a is Any<!>) {
// Error:(9, 9) Kotlin: Type inference failed: fun <T> foo(b: A<T>): kotlin.Unit
// cannot be applied to (A<T>)
foo(a)
+3 -2
View File
@@ -5,8 +5,9 @@ fun foo() : Int {
val x = 1
when (x) {
is <!INCOMPATIBLE_TYPES!>String<!> -> <!UNUSED_EXPRESSION!>1<!>
!is Int -> <!UNUSED_EXPRESSION!>1<!>
is Any<!USELESS_NULLABLE_CHECK!>?<!> -> <!UNUSED_EXPRESSION!>1<!>
<!USELESS_IS_CHECK!>!is Int<!> -> <!UNUSED_EXPRESSION!>1<!>
<!USELESS_IS_CHECK!>is Any<!USELESS_NULLABLE_CHECK!>?<!><!> -> <!UNUSED_EXPRESSION!>1<!>
<!USELESS_IS_CHECK!>is Any<!> -> <!UNUSED_EXPRESSION!>1<!>
<!INCOMPATIBLE_TYPES!>s<!> -> <!UNUSED_EXPRESSION!>1<!>
1 -> <!UNUSED_EXPRESSION!>1<!>
1 + <!UNRESOLVED_REFERENCE!>a<!> -> <!UNUSED_EXPRESSION!>1<!>