Why is this an issue?

Kotlin provides the operators as and as? to cast an expression to a specific type, and is to check the assignment compatibility with a type. These operators are used for downcasts, smart casts, and run-time type checking.

In case the as or as? operator is used for upcasting from a subtype to a supertype, the cast is redundant as it has no effect and can never fail. If a specific type is expected, an expression of a subtype can always be inserted without casting (Substitution Principle and Assignment Compatibility).

Likewise, the is operator is redundant and will always return true if the type of the expression on the left side is assignment compatible with the type on the right.

What is the potential impact?

Code redundancy

Since the operation will always succeed and has no side effects, it is pointless to use it. Conditions with is will lead to dead code branches because they will always or never be satisfied.

How to fix it

Remove the operator and all dead code branches that result from it, or investigate why the expression that is cast or checked has an unexpected compile-time type.

Code examples

Noncompliant code example

fun types(value: Int, elements: List<Number>) {
    val a: Number = value as Number // Noncompliant, Int instance is always a Number
    val b: Number = value as? Number // Noncompliant, Int instance is always a Number

    val text = if (value is Number) { // Noncomplient, else-branch is dead code
        "happens always"
    } else {
        "impossible"
    }
}

Compliant solution

fun types(value: Number, elements: List<Number>) {
    val a: Int = value as Int // Compliant, Number instance could be an Int
    val b: Int = value as? Int // Compliant, Number instance could be an Int

    val text = if (value is Int) { // Compliant, both branches reachable
        "impossible"
    } else {
        "happens always"
    }
}

Resources

Documentation

Articles & blog posts