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
@@ -826,6 +826,8 @@ public interface Errors {
DiagnosticFactory0<KtExpression> ALWAYS_NULL = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<KtNullableType> USELESS_NULLABLE_CHECK = DiagnosticFactory0.create(WARNING, NULLABLE_TYPE);
DiagnosticFactory1<KtElement, Boolean> USELESS_IS_CHECK = DiagnosticFactory1.create(WARNING);
// Properties / locals
@@ -396,6 +396,7 @@ public class DefaultErrorMessages {
MAP.put(IS_ENUM_ENTRY, "'is' over enum entry is not allowed, use comparison instead");
MAP.put(ENUM_ENTRY_AS_TYPE, "Use of enum entry names as types is not allowed, use enum type instead");
MAP.put(USELESS_NULLABLE_CHECK, "Non-null type is checked for instance of nullable type");
MAP.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING);
MAP.put(WRONG_SETTER_PARAMETER_TYPE, "Setter parameter type must be equal to the type of the property, i.e. ''{0}''", RENDER_TYPE, RENDER_TYPE);
MAP.put(WRONG_GETTER_RETURN_TYPE, "Getter return type must be equal to the type of the property, i.e. ''{0}''", RENDER_TYPE, RENDER_TYPE);
MAP.put(WRONG_SETTER_RETURN_TYPE, "Setter return type must be Unit");
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.*
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
import org.jetbrains.kotlin.types.typeUtil.containsError
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import java.util.*
class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) {
@@ -51,7 +53,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val typeReference = expression.typeReference
if (typeReference != null && knownType != null) {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(leftHandSide, knownType, context)
val conditionInfo = checkTypeForIs(context, knownType, typeReference, dataFlowValue).thenInfo
val conditionInfo = checkTypeForIs(context, expression, expression.isNegated, knownType, typeReference, dataFlowValue).thenInfo
val newDataFlowInfo = conditionInfo.and(typeInfo.dataFlowInfo)
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo)
}
@@ -342,7 +344,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
}
val typeReference = condition.typeReference
if (typeReference != null) {
val result = checkTypeForIs(context, subjectType, typeReference, subjectDataFlowValue)
val result = checkTypeForIs(context, condition, condition.isNegated, subjectType, typeReference, subjectDataFlowValue)
if (condition.isNegated) {
newDataFlowInfo = ConditionalDataFlowInfo(result.elseInfo, result.thenInfo)
}
@@ -417,6 +419,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
private fun checkTypeForIs(
context: ExpressionTypingContext,
isCheck: KtElement,
negated: Boolean,
subjectType: KotlinType,
typeReferenceAfterIs: KtTypeReference,
subjectDataFlowValue: DataFlowValue
@@ -432,13 +436,21 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
if (targetDescriptor != null && DescriptorUtils.isEnumEntry(targetDescriptor)) {
context.trace.report(IS_ENUM_ENTRY.on(typeReferenceAfterIs))
}
if (!TypeUtils.isNullableType(subjectType) && targetType.isMarkedNullable) {
val subjectTypeHasError = subjectType.containsError()
if (!subjectTypeHasError && !TypeUtils.isNullableType(subjectType) && targetType.isMarkedNullable) {
val element = typeReferenceAfterIs.typeElement
assert(element is KtNullableType) { "element must be instance of " + KtNullableType::class.java.name }
context.trace.report(Errors.USELESS_NULLABLE_CHECK.on(element as KtNullableType))
}
checkTypeCompatibility(context, targetType, subjectType, typeReferenceAfterIs)
if (!subjectTypeHasError && !targetType.containsError()) {
val possibleTypes = hashSetOf(subjectType)
possibleTypes.addAll(context.dataFlowInfo.getStableTypes(subjectDataFlowValue))
val intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, possibleTypes.map { it.upperIfFlexible() })
if (intersection?.isSubtypeOf(targetType) ?: false) {
context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated))
}
}
if (CastDiagnosticsUtil.isCastErased(subjectType, targetType, KotlinTypeChecker.DEFAULT)) {
context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReferenceAfterIs, targetType))
}
+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<!>
@@ -7,23 +7,23 @@ fun test(d: Any, dl: Collection<dynamic>) {
d as? <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d as? <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
d is <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
<!USELESS_IS_CHECK!>d is <!DYNAMIC_NOT_ALLOWED!>dynamic<!><!>
<!USELESS_IS_CHECK!>d is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!><!>
d !is <!DYNAMIC_NOT_ALLOWED!>dynamic<!>
d !is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!>
<!USELESS_IS_CHECK!>d !is <!DYNAMIC_NOT_ALLOWED!>dynamic<!><!>
<!USELESS_IS_CHECK!>d !is <!DYNAMIC_NOT_ALLOWED!>dynamic?<!><!>
when (d) {
is <!DYNAMIC_NOT_ALLOWED!>dynamic<!> -> {}
is <!DYNAMIC_NOT_ALLOWED, DUPLICATE_LABEL_IN_WHEN!>dynamic?<!> -> {}
!is <!DYNAMIC_NOT_ALLOWED!>dynamic<!> -> {}
!is <!DYNAMIC_NOT_ALLOWED, DUPLICATE_LABEL_IN_WHEN!>dynamic?<!> -> {}
<!USELESS_IS_CHECK!>is <!DYNAMIC_NOT_ALLOWED!>dynamic<!><!> -> {}
<!USELESS_IS_CHECK!>is <!DYNAMIC_NOT_ALLOWED, DUPLICATE_LABEL_IN_WHEN!>dynamic?<!><!> -> {}
<!USELESS_IS_CHECK!>!is <!DYNAMIC_NOT_ALLOWED!>dynamic<!><!> -> {}
<!USELESS_IS_CHECK!>!is <!DYNAMIC_NOT_ALLOWED, DUPLICATE_LABEL_IN_WHEN!>dynamic?<!><!> -> {}
}
dl as List<dynamic>
dl is List<dynamic>
<!USELESS_IS_CHECK!>dl is List<dynamic><!>
when (dl) {
is List<dynamic> -> {}
<!USELESS_IS_CHECK!>is List<dynamic><!> -> {}
}
}
@@ -1,5 +1,5 @@
fun f(a: Array<out Number>) = a.isArrayOf<Int>()
fun f1(a: Array<out Number>) = a is Array<*>
fun f1(a: Array<out Number>) = <!USELESS_IS_CHECK!>a is Array<*><!>
fun f2(a: Array<out Number>) = a is <!CANNOT_CHECK_FOR_ERASED!>Array<Int><!>
+1 -1
View File
@@ -1,5 +1,5 @@
fun test() {
if (1 is Int) {
if (<warning>1 is Int</warning>) {
if (1 is <error>Boolean</error>) {
}
+2 -2
View File
@@ -5,8 +5,8 @@ fun foo() : Int {
val x = 1
when (x) {
is <error>String</error> -> <warning>1</warning>
!is Int -> <warning>1</warning>
is Any<warning>?</warning> -> <warning>1</warning>
<warning>!is Int</warning> -> <warning>1</warning>
<warning>is Any<warning>?</warning></warning> -> <warning>1</warning>
<error>s</error> -> <warning>1</warning>
1 -> <warning>1</warning>
1 + <error>a</error> -> <warning>1</warning>
+5 -5
View File
@@ -49,7 +49,7 @@ fun f10(a : A?) {
if (!(a is B)) {
return;
}
if (!(a is B)) {
if (!(<warning>a is B</warning>)) {
return;
}
}
@@ -71,7 +71,7 @@ fun f11(a : A?) {
is B -> <info descr="Smart cast to B">a</info>.bar()
is A -> <info descr="Smart cast to A">a</info>.foo()
is Any -> <info descr="Smart cast to A">a</info>.foo()
is Any? -> a.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
<warning>is Any?</warning> -> a.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
else -> a<info>?.</info>foo()
}
}
@@ -81,12 +81,12 @@ fun f12(a : A?) {
is B -> <info descr="Smart cast to B">a</info>.bar()
is A -> <info descr="Smart cast to A">a</info>.foo()
is Any -> <info descr="Smart cast to A">a</info>.foo();
is Any? -> a.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
<warning>is Any?</warning> -> a.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
is C -> <info descr="Smart cast to C">a</info>.bar()
else -> a<info>?.</info>foo()
}
if (a is Any?) {
if (<warning>a is Any?</warning>) {
a<info>?.</info><error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
}
if (a is B) {
@@ -203,7 +203,7 @@ fun mergeSmartCasts(a: Any?) {
when (a) {
is String, is Any -> a.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: compareTo">compareTo</error>("")
}
if (a is String && a is Any) {
if (a is String && <warning>a is Any</warning>) {
val <warning>i</warning>: Int = <info descr="Smart cast to kotlin.String">a</info>.compareTo("")
}
if (a is String && <info descr="Smart cast to kotlin.String">a</info>.compareTo("") == 0) {}