Detect redundant 'is' check
#KT-14187 Fixed
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
768e0fa738
commit
cd24adac32
@@ -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
|
||||
|
||||
|
||||
+1
@@ -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");
|
||||
|
||||
+16
-4
@@ -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
@@ -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
@@ -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; }
|
||||
}
|
||||
@@ -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
@@ -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() {}
|
||||
|
||||
+1
-1
@@ -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><!>
|
||||
Vendored
+1
-1
@@ -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><!>
|
||||
+1
-1
@@ -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 @@
|
||||
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!>?<!><!>
|
||||
}
|
||||
Vendored
+1
-1
@@ -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<!>) {
|
||||
} } } } } } } } } } } } } } } } } } } } } } } } }
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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<!>
|
||||
|
||||
+10
-10
@@ -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
@@ -1,5 +1,5 @@
|
||||
fun test() {
|
||||
if (1 is Int) {
|
||||
if (<warning>1 is Int</warning>) {
|
||||
if (1 is <error>Boolean</error>) {
|
||||
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -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
@@ -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) {}
|
||||
|
||||
Reference in New Issue
Block a user