FIR checker: warn useless as and is
This commit is contained in:
committed by
TeamCityServer
parent
19d939c36e
commit
e2dc21da90
@@ -13,6 +13,6 @@ interface B
|
||||
|
||||
fun test_2(x: Any?) {
|
||||
if (x is A && x is B) {
|
||||
x is A
|
||||
<!USELESS_IS_CHECK!>x is A<!>
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ fun test_1(e: A) {
|
||||
|
||||
val d = when (e) {
|
||||
is E -> 1
|
||||
is A -> 2
|
||||
<!USELESS_IS_CHECK!>is A<!> -> 2
|
||||
}.plus(0)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fun foo() = if (true) 1 else 0
|
||||
|
||||
fun bar(arg: Any?) = when (arg) {
|
||||
is Int -> arg as Int
|
||||
is Int -> arg <!USELESS_CAST!>as Int<!>
|
||||
else -> 42
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ class Some
|
||||
fun foo(): () -> Boolean {
|
||||
val s = Some()
|
||||
if (true) {
|
||||
return { if (s is Some) true else false }
|
||||
return { if (<!USELESS_IS_CHECK!>s is Some<!>) true else false }
|
||||
} else {
|
||||
return { true }
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -14,7 +14,7 @@ class Case1() {
|
||||
|
||||
this.yield("") //UNRESOLVED_REFERENCE
|
||||
|
||||
this as SequenceScope<String>
|
||||
this <!USELESS_CAST!>as SequenceScope<String><!>
|
||||
|
||||
yield("") // resolved to SequenceScope.yield
|
||||
|
||||
@@ -31,10 +31,10 @@ fun case2() {
|
||||
|
||||
this.yield("") //UNRESOLVED_REFERENCE
|
||||
|
||||
this as SequenceScope<String>
|
||||
this <!USELESS_CAST!>as SequenceScope<String><!>
|
||||
|
||||
yield("") // UNRESOLVED_REFERENCE
|
||||
|
||||
this.yield("") // UNRESOLVED_REFERENCE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ fun main(args: Array<String>) {
|
||||
alias<FirEqualityOperatorCall>("EqualityOperatorCallChecker")
|
||||
alias<FirAnonymousFunction>("AnonymousFunctionAsExpressionChecker")
|
||||
alias<FirStringConcatenationCall>("StringConcatenationCallChecker")
|
||||
alias<FirTypeOperatorCall>("TypeOperatorCallChecker")
|
||||
alias<FirResolvedQualifier>("ResolvedQualifierChecker")
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -52,6 +52,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
CONST_MODIFIER,
|
||||
ARRAY_ACCESS,
|
||||
SAFE_ACCESS,
|
||||
AS_TYPE,
|
||||
USELESS_ELVIS,
|
||||
NAME_OF_NAMED_ARGUMENT,
|
||||
VALUE_ARGUMENTS,
|
||||
|
||||
+7
@@ -654,6 +654,13 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val USELESS_ELVIS_RIGHT_IS_NULL by warning<KtBinaryExpression>(PositioningStrategy.USELESS_ELVIS)
|
||||
}
|
||||
|
||||
val CASTS_AND_IS_CHECKS by object : DiagnosticGroup("Casts and is-checks") {
|
||||
val USELESS_CAST by warning<KtBinaryExpressionWithTypeRHS>(PositioningStrategy.AS_TYPE)
|
||||
val USELESS_IS_CHECK by warning<KtElement> {
|
||||
parameter<Boolean>("compileTimeCheckResult")
|
||||
}
|
||||
}
|
||||
|
||||
val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") {
|
||||
val NO_ELSE_IN_WHEN by error<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
||||
parameter<List<WhenMissingCase>>("missingWhenCases")
|
||||
|
||||
+4
@@ -45,6 +45,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _anonymousFunctionAsExpressionCheckers
|
||||
override val stringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker>
|
||||
get() = _stringConcatenationCallCheckers
|
||||
override val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker>
|
||||
get() = _typeOperatorCallCheckers
|
||||
override val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker>
|
||||
get() = _resolvedQualifierCheckers
|
||||
|
||||
@@ -64,6 +66,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _equalityOperatorCallCheckers: MutableSet<FirEqualityOperatorCallChecker> = mutableSetOf()
|
||||
private val _anonymousFunctionAsExpressionCheckers: MutableSet<FirAnonymousFunctionAsExpressionChecker> = mutableSetOf()
|
||||
private val _stringConcatenationCallCheckers: MutableSet<FirStringConcatenationCallChecker> = mutableSetOf()
|
||||
private val _typeOperatorCallCheckers: MutableSet<FirTypeOperatorCallChecker> = mutableSetOf()
|
||||
private val _resolvedQualifierCheckers: MutableSet<FirResolvedQualifierChecker> = mutableSetOf()
|
||||
|
||||
@CheckersComponentInternal
|
||||
@@ -84,6 +87,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
_equalityOperatorCallCheckers += checkers.equalityOperatorCallCheckers
|
||||
_anonymousFunctionAsExpressionCheckers += checkers.anonymousFunctionAsExpressionCheckers
|
||||
_stringConcatenationCallCheckers += checkers.stringConcatenationCallCheckers
|
||||
_typeOperatorCallCheckers += checkers.typeOperatorCallCheckers
|
||||
_resolvedQualifierCheckers += checkers.resolvedQualifierCheckers
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -33,6 +33,7 @@ abstract class ExpressionCheckers {
|
||||
open val equalityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> = emptySet()
|
||||
open val anonymousFunctionAsExpressionCheckers: Set<FirAnonymousFunctionAsExpressionChecker> = emptySet()
|
||||
open val stringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> = emptySet()
|
||||
open val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> = emptySet()
|
||||
open val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker> = emptySet()
|
||||
|
||||
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> get() = basicExpressionCheckers
|
||||
@@ -51,5 +52,6 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> get() = equalityOperatorCallCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allAnonymousFunctionAsExpressionCheckers: Set<FirAnonymousFunctionAsExpressionChecker> get() = anonymousFunctionAsExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> get() = stringConcatenationCallCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> get() = typeOperatorCallCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> get() = resolvedQualifierCheckers + basicExpressionCheckers
|
||||
}
|
||||
|
||||
+2
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStringConcatenationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirTryExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
|
||||
@@ -44,4 +45,5 @@ typealias FirSafeCallExpressionChecker = FirExpressionChecker<FirSafeCallExpress
|
||||
typealias FirEqualityOperatorCallChecker = FirExpressionChecker<FirEqualityOperatorCall>
|
||||
typealias FirAnonymousFunctionAsExpressionChecker = FirExpressionChecker<FirAnonymousFunction>
|
||||
typealias FirStringConcatenationCallChecker = FirExpressionChecker<FirStringConcatenationCall>
|
||||
typealias FirTypeOperatorCallChecker = FirExpressionChecker<FirTypeOperatorCall>
|
||||
typealias FirResolvedQualifierChecker = FirExpressionChecker<FirResolvedQualifier>
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotation
|
||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
@@ -390,6 +391,10 @@ object FirErrors {
|
||||
val USELESS_ELVIS by warning1<KtBinaryExpression, ConeKotlinType>(SourceElementPositioningStrategies.USELESS_ELVIS)
|
||||
val USELESS_ELVIS_RIGHT_IS_NULL by warning0<KtBinaryExpression>(SourceElementPositioningStrategies.USELESS_ELVIS)
|
||||
|
||||
// Casts and is-checks
|
||||
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
|
||||
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
|
||||
|
||||
// When expressions
|
||||
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
||||
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
// See .../types/CastDiagnosticsUtil.kt for counterparts, including isRefinementUseless, isExactTypeCast, isUpcast.
|
||||
object FirUselessTypeOperationCallChecker : FirTypeOperatorCallChecker() {
|
||||
override fun check(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (expression.operation !in FirOperation.TYPES) return
|
||||
val arg = expression.argument
|
||||
|
||||
val candidateType = arg.typeRef.coneType.upperBoundIfFlexible().fullyExpandedType(context.session)
|
||||
if (candidateType is ConeKotlinErrorType) return
|
||||
|
||||
val targetType = expression.conversionTypeRef.coneType.fullyExpandedType(context.session)
|
||||
if (targetType is ConeKotlinErrorType) return
|
||||
|
||||
// x as? Type <=> x as Type?
|
||||
val refinedTargetType =
|
||||
if (expression.operation == FirOperation.SAFE_AS) {
|
||||
targetType.withNullability(ConeNullability.NULLABLE, context.session.typeContext)
|
||||
} else {
|
||||
targetType
|
||||
}
|
||||
if (isRefinementUseless(context, candidateType, refinedTargetType, shouldCheckForExactType(expression, context))) {
|
||||
when (expression.operation) {
|
||||
FirOperation.IS -> reporter.reportOn(expression.source, FirErrors.USELESS_IS_CHECK, true, context)
|
||||
FirOperation.NOT_IS -> reporter.reportOn(expression.source, FirErrors.USELESS_IS_CHECK, false, context)
|
||||
FirOperation.AS, FirOperation.SAFE_AS -> reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context)
|
||||
else -> throw AssertionError("Should not be here: ${expression.operation}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun shouldCheckForExactType(expression: FirTypeOperatorCall, context: CheckerContext): Boolean {
|
||||
return when (expression.operation) {
|
||||
FirOperation.IS, FirOperation.NOT_IS -> false
|
||||
// TODO: differentiate if this expression defines the enclosing thing's type
|
||||
// e.g.,
|
||||
// val c1 get() = 1 as Number
|
||||
// val c2: Number get() = 1 <!USELESS_CAST!>as Number<!>
|
||||
FirOperation.AS, FirOperation.SAFE_AS -> true
|
||||
else -> throw AssertionError("Should not be here: ${expression.operation}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isRefinementUseless(
|
||||
context: CheckerContext,
|
||||
candidateType: ConeKotlinType,
|
||||
targetType: ConeKotlinType,
|
||||
shouldCheckForExactType: Boolean,
|
||||
): Boolean {
|
||||
return if (shouldCheckForExactType) {
|
||||
isExactTypeCast(context, candidateType, targetType)
|
||||
} else {
|
||||
isUpcast(context, candidateType, targetType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isExactTypeCast(context: CheckerContext, candidateType: ConeKotlinType, targetType: ConeKotlinType): Boolean {
|
||||
if (!AbstractTypeChecker.equalTypes(context.session.typeContext, candidateType, targetType, stubTypesEqualToAnything = false))
|
||||
return false
|
||||
// See comments at [isUpcast] why we need to check the existence of @ExtensionFunctionType
|
||||
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
|
||||
}
|
||||
|
||||
private fun isUpcast(context: CheckerContext, candidateType: ConeKotlinType, targetType: ConeKotlinType): Boolean {
|
||||
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, candidateType, targetType, stubTypesEqualToAnything = false))
|
||||
return false
|
||||
|
||||
// E.g., foo(p1: (X) -> Y), where p1 has a functional type whose receiver type is X and return type is Y.
|
||||
// For bar(p2: X.() -> Y), p2 has the same functional type (with same receiver and return types).
|
||||
// The only difference is the existence of type annotation, @ExtensionFunctionType,
|
||||
// which indicates that the annotated type represents an extension function.
|
||||
// If one casts p1 to p2 (or vice versa), it is _not_ up cast, i.e., not redundant, yet meaningful.
|
||||
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -28,7 +28,7 @@ class ExpressionCheckersDiagnosticComponent(
|
||||
}
|
||||
|
||||
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: CheckerContext) {
|
||||
checkers.allBasicExpressionCheckers.check(typeOperatorCall, data, reporter)
|
||||
checkers.allTypeOperatorCallCheckers.check(typeOperatorCall, data, reporter)
|
||||
}
|
||||
|
||||
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: CheckerContext) {
|
||||
|
||||
+6
@@ -282,8 +282,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USAGE_IS_NOT_INLINABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_CAST
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS_RIGHT_IS_NULL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_IS_CHECK
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_VARARG_ON_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_BE_CLONEABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION
|
||||
@@ -871,6 +873,10 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(USELESS_ELVIS, "Elvis operator (?:) always returns the left operand of non-nullable type {0}", RENDER_TYPE)
|
||||
map.put(USELESS_ELVIS_RIGHT_IS_NULL, "Right operand of elvis operator (?:) is useless if it is null")
|
||||
|
||||
// Casts and is-checks
|
||||
map.put(USELESS_CAST, "No cast needed")
|
||||
map.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING)
|
||||
|
||||
// When expressions
|
||||
map.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", WHEN_MISSING_CASES)
|
||||
map.put(INVALID_IF_AS_EXPRESSION, "'if' must have both main and 'else' branches if used as an expression")
|
||||
|
||||
+5
-1
@@ -594,7 +594,7 @@ object LightTreePositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
val USELESS_ELVIS = object : LightTreePositioningStrategy() {
|
||||
private val OPERATION_TO_END = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
@@ -605,6 +605,10 @@ object LightTreePositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
val AS_TYPE = OPERATION_TO_END
|
||||
|
||||
val USELESS_ELVIS = OPERATION_TO_END
|
||||
|
||||
val RETURN_WITH_LABEL = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
|
||||
+5
-1
@@ -118,7 +118,6 @@ object SourceElementPositioningStrategies {
|
||||
PositioningStrategies.SUSPEND_MODIFIER
|
||||
)
|
||||
|
||||
|
||||
val OPERATOR = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.OPERATOR,
|
||||
PositioningStrategies.OPERATOR
|
||||
@@ -194,6 +193,11 @@ object SourceElementPositioningStrategies {
|
||||
PositioningStrategies.SAFE_ACCESS
|
||||
)
|
||||
|
||||
val AS_TYPE = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.AS_TYPE,
|
||||
PositioningStrategies.AS_TYPE
|
||||
)
|
||||
|
||||
val USELESS_ELVIS = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.USELESS_ELVIS,
|
||||
PositioningStrategies.USELESS_ELVIS
|
||||
|
||||
+5
@@ -94,6 +94,11 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirAnonymousFunctionChecker,
|
||||
)
|
||||
|
||||
override val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker>
|
||||
get() = setOf(
|
||||
FirUselessTypeOperationCallChecker,
|
||||
)
|
||||
|
||||
override val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker>
|
||||
get() = setOf(
|
||||
FirStandaloneQualifierChecker,
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ fun test() : Unit {
|
||||
checkSubtype<Int?>(x)
|
||||
checkSubtype<Int>(y)
|
||||
checkSubtype<Int>(x as Int)
|
||||
checkSubtype<Int>(y as Int)
|
||||
checkSubtype<Int>(y <!USELESS_CAST!>as Int<!>)
|
||||
checkSubtype<Int?>(x as Int?)
|
||||
checkSubtype<Int?>(y as Int?)
|
||||
checkSubtype<Int?>(x as? Int)
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ fun test() {
|
||||
checkSubtype<Float>(<!ARGUMENT_TYPE_MISMATCH!>1<!>)
|
||||
|
||||
1 as Byte
|
||||
1 as Int
|
||||
1 <!USELESS_CAST!>as Int<!>
|
||||
0xff as Long
|
||||
|
||||
1.1 as Int
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
// FILE: KotlinFile.kt
|
||||
|
||||
fun test() {
|
||||
if (1 is Int) {
|
||||
if (<!USELESS_IS_CHECK!>1 is Int<!>) {
|
||||
if (1 is Boolean) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
A.create() is A
|
||||
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
|
||||
x is String
|
||||
<!USELESS_IS_CHECK!>x is String<!>
|
||||
}
|
||||
|
||||
fun foo(): Any = ""
|
||||
@@ -23,4 +23,4 @@ fun foo(): Any = ""
|
||||
// FILE: A.java
|
||||
class A {
|
||||
static A create() { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ fun test(a: Any) {
|
||||
.0fin a
|
||||
.0<!UNRESOLVED_REFERENCE!>din<!> a
|
||||
|
||||
1is Any
|
||||
<!USELESS_IS_CHECK!>1is Any<!>
|
||||
1as Any
|
||||
1as? Any
|
||||
|
||||
1!is Any
|
||||
<!USELESS_IS_CHECK!>1!is Any<!>
|
||||
1!in a
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ fun test(a: Any) {
|
||||
a !in's'
|
||||
a !in<!EMPTY_CHARACTER_LITERAL!>''<!>
|
||||
|
||||
if("s"is Any) {}
|
||||
if("s"is Any) {}
|
||||
if(<!USELESS_IS_CHECK!>"s"is Any<!>) {}
|
||||
if(<!USELESS_IS_CHECK!>"s"is Any<!>) {}
|
||||
test("s"as Any)
|
||||
|
||||
a foo""<!SYNTAX!>1<!>
|
||||
|
||||
@@ -26,7 +26,7 @@ fun foo() {
|
||||
}
|
||||
|
||||
fun bar(a: Ann = Ann()) {
|
||||
if (a is Ann) {}
|
||||
if (<!USELESS_IS_CHECK!>a is Ann<!>) {}
|
||||
}
|
||||
|
||||
operator fun String.invoke() {}
|
||||
|
||||
@@ -25,8 +25,8 @@ fun testRun() {
|
||||
}
|
||||
|
||||
run<Int?> {
|
||||
1 as Int
|
||||
1 as Int
|
||||
1 <!USELESS_CAST!>as Int<!>
|
||||
1 <!USELESS_CAST!>as Int<!>
|
||||
}
|
||||
|
||||
runWithoutReturn {
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ fun test() {
|
||||
val a = 1 as Any?
|
||||
val b: Number = 1 as Number
|
||||
val c = null as String?
|
||||
val d: Number = 1 as Int
|
||||
val d: Number = 1 <!USELESS_CAST!>as Int<!>
|
||||
}
|
||||
|
||||
val c1 get() = 1 as Number
|
||||
@@ -14,4 +14,4 @@ val d: Number
|
||||
get() {
|
||||
1 as Number
|
||||
return 1 as Number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ public class Foo {
|
||||
fun test() {
|
||||
Foo.create() as Foo
|
||||
Foo.createN() as Foo
|
||||
Foo.createNN() as Foo
|
||||
Foo.createNN() <!USELESS_CAST!>as Foo<!>
|
||||
|
||||
Foo.create() as Foo?
|
||||
Foo.createN() as Foo?
|
||||
Foo.create() <!USELESS_CAST!>as Foo?<!>
|
||||
Foo.createN() <!USELESS_CAST!>as Foo?<!>
|
||||
Foo.createNN() as Foo?
|
||||
}
|
||||
}
|
||||
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
open class Base<A>
|
||||
class Some: Base<Int>()
|
||||
|
||||
// a is Some => a is Base<Int>
|
||||
fun f(a: Some) = a is Base<Int>
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
open class Base<A>
|
||||
class Some: Base<Int>()
|
||||
|
||||
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
open class A
|
||||
open class B: A()
|
||||
|
||||
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>
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
open class A
|
||||
open class B: A()
|
||||
|
||||
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
open class A
|
||||
open class B: A()
|
||||
|
||||
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>
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
open class A
|
||||
open class B: A()
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
fun f(a: MutableList<out Number>) = a is MutableList<out Any>
|
||||
@@ -1 +1,2 @@
|
||||
// FIR_IDENTICAL
|
||||
fun f(a: MutableList<out Number>) = <!USELESS_IS_CHECK!>a is MutableList<out Any><!>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
fun f(a: MutableList<String>) = a is MutableList<out CharSequence>
|
||||
@@ -1 +1,2 @@
|
||||
// FIR_IDENTICAL
|
||||
fun f(a: MutableList<String>) = <!USELESS_IS_CHECK!>a is MutableList<out CharSequence><!>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
fun f(a: List<Number>) = a is List<Any>
|
||||
@@ -1 +1,2 @@
|
||||
// FIR_IDENTICAL
|
||||
fun f(a: List<Number>) = <!USELESS_IS_CHECK!>a is List<Any><!>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
fun <T> testing(a: T) = a is T
|
||||
@@ -1 +1,2 @@
|
||||
// FIR_IDENTICAL
|
||||
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 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?<!>
|
||||
|
||||
null as T
|
||||
null 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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNUSED_VARIABLE
|
||||
|
||||
fun test(x: Int?) {
|
||||
val a1 = x as? Int
|
||||
val a2 = x as? Int?
|
||||
val a1 = x <!USELESS_CAST!>as? Int<!>
|
||||
val a2 = x <!USELESS_CAST!>as? Int?<!>
|
||||
val a3 = x as? Number
|
||||
val a4 = x as? Number?
|
||||
val a5: Int? = x as? Int
|
||||
val a6: Number? = x as? Int
|
||||
val a5: Int? = x <!USELESS_CAST!>as? Int<!>
|
||||
val a6: Number? = x <!USELESS_CAST!>as? Int<!>
|
||||
val a7: Number? = 1 as? Number
|
||||
|
||||
run { x as? Int }
|
||||
run { x <!USELESS_CAST!>as? Int<!> }
|
||||
run { x as? Number }
|
||||
|
||||
foo(x as? Number)
|
||||
|
||||
@@ -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?
|
||||
y2 is S?
|
||||
<!USELESS_IS_CHECK!>x1 is T?<!>
|
||||
<!USELESS_IS_CHECK!>x2 is T?<!>
|
||||
<!USELESS_IS_CHECK!>y1 is S?<!>
|
||||
<!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_IS_CHECK!>f3 is Int?<!>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun asCall() {
|
||||
1 as Int
|
||||
1 <!USELESS_CAST!>as Int<!>
|
||||
1 as Byte
|
||||
1 as Short
|
||||
1 as Long
|
||||
@@ -12,7 +12,7 @@ fun asCall() {
|
||||
1.0 as Short
|
||||
1.0 as Long
|
||||
1.0 as Char
|
||||
1.0 as Double
|
||||
1.0 <!USELESS_CAST!>as Double<!>
|
||||
1.0 as Float
|
||||
|
||||
1f as Int
|
||||
@@ -21,7 +21,7 @@ fun asCall() {
|
||||
1f as Long
|
||||
1f as Char
|
||||
1f as Double
|
||||
1f as Float
|
||||
1f <!USELESS_CAST!>as Float<!>
|
||||
}
|
||||
|
||||
fun asSafe() {
|
||||
@@ -48,4 +48,4 @@ fun asSafe() {
|
||||
1f as? Char
|
||||
1f as? Double
|
||||
1f as? Float
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
open class C {
|
||||
}
|
||||
|
||||
fun C.foo() {}
|
||||
|
||||
open class X {
|
||||
companion object : C() {}
|
||||
}
|
||||
|
||||
open class Y {
|
||||
companion object : C() {}
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
val x = X
|
||||
x.foo()
|
||||
X.foo()
|
||||
(X as C).foo()
|
||||
((if (1<2) X else Y) as C).foo()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
open class C {
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -33,8 +33,18 @@ inline fun <reified T> case_5() {
|
||||
|
||||
val z = x.test()
|
||||
|
||||
if (z is T) {
|
||||
if (<!USELESS_IS_CHECK!>z is T<!>) {
|
||||
// z is {T!! & T!!} (smart cast from T)
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(z)
|
||||
}
|
||||
|
||||
val a = object<A> {
|
||||
fun test() = 42 as <!UNRESOLVED_REFERENCE!>A<!>
|
||||
}
|
||||
|
||||
val b = a.test()
|
||||
|
||||
if (a is T) {
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(a)
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -37,4 +37,14 @@ inline fun <reified T> case_5() {
|
||||
// z is {T!! & T!!} (smart cast from T)
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(z)
|
||||
}
|
||||
|
||||
val a = object<!TYPE_PARAMETERS_IN_ANONYMOUS_OBJECT!><A><!> {
|
||||
fun test() = 42 <!UNCHECKED_CAST!>as A<!>
|
||||
}
|
||||
|
||||
val b = a.test()
|
||||
|
||||
if (a is T) {
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(a)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+11
-1
@@ -33,8 +33,18 @@ inline fun <reified T> case_5() {
|
||||
|
||||
val z = x.test()
|
||||
|
||||
if (z is T) {
|
||||
if (<!USELESS_IS_CHECK!>z is T<!>) {
|
||||
// z is {T!! & T!!} (smart cast from T)
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(z)
|
||||
}
|
||||
|
||||
val a = object<A> {
|
||||
fun test() = 42 as <!UNRESOLVED_REFERENCE!>A<!>
|
||||
}
|
||||
|
||||
val b = a.test()
|
||||
|
||||
if (a is T) {
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(a)
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -37,4 +37,14 @@ inline fun <reified T> case_5() {
|
||||
// z is {T!! & T!!} (smart cast from T)
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(z)
|
||||
}
|
||||
|
||||
val a = object<!TYPE_PARAMETERS_IN_OBJECT!><A><!> {
|
||||
fun test() = 42 <!UNCHECKED_CAST!>as A<!>
|
||||
}
|
||||
|
||||
val b = a.test()
|
||||
|
||||
if (a is T) {
|
||||
<!UNRESOLVED_REFERENCE!>println<!>(a)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -39,7 +39,7 @@ fun t1(b : Boolean) {
|
||||
return;
|
||||
}
|
||||
doSmth(i)
|
||||
if (i is Int) {
|
||||
if (<!USELESS_IS_CHECK!>i is Int<!>) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ fun t1(x: Int) = when(x) {
|
||||
}
|
||||
|
||||
fun t5(x: Int) = <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||
is Int -> 1
|
||||
<!USELESS_IS_CHECK!>is Int<!> -> 1
|
||||
2 -> 2
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ fun f2(s: Number?) {
|
||||
}
|
||||
|
||||
fun f3(s: Number?) {
|
||||
if (s is Int && s as Int == 42);
|
||||
if (s is Int && s <!USELESS_CAST!>as Int<!> == 42);
|
||||
checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>s<!>)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
fun foo(o: Any) {
|
||||
if (o is String) {
|
||||
val s = o as String
|
||||
val s = o <!USELESS_CAST!>as String<!>
|
||||
s.length
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,4 @@ fun foo1(o: Any) {
|
||||
val s = o
|
||||
s.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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>(x)
|
||||
}
|
||||
checkSubtype<Int>(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<!>) {
|
||||
} } } } } } } } } } } } } } } } } } } } } } } } }
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ enum class En { A, B, С }
|
||||
fun foo() {
|
||||
// nullable variable
|
||||
val en2: Any? = En.A
|
||||
if (en2 is En) {
|
||||
if (<!USELESS_IS_CHECK!>en2 is En<!>) {
|
||||
when (en2) {
|
||||
En.A -> {}
|
||||
En.B -> {}
|
||||
@@ -15,7 +15,7 @@ fun foo() {
|
||||
|
||||
// not nullable variable
|
||||
val en1: Any = En.A
|
||||
if (en1 is En) {
|
||||
if (<!USELESS_IS_CHECK!>en1 is En<!>) {
|
||||
when (en1) {
|
||||
En.A -> {}
|
||||
En.B -> {}
|
||||
@@ -37,4 +37,4 @@ fun bar(x: Any) {
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ fun <T> foo() = foo() as T
|
||||
|
||||
fun <T> foo2(): T = TODO()
|
||||
|
||||
val test = foo2().plus("") as String
|
||||
val test = foo2().plus("") <!USELESS_CAST!>as String<!>
|
||||
|
||||
fun <T> T.bar() = this
|
||||
val barTest = "".bar() as Number
|
||||
|
||||
@@ -17,5 +17,5 @@ val asStarList = foo() as List<*>
|
||||
|
||||
val safeAs = foo() as? String
|
||||
|
||||
val fromIs = foo() is String
|
||||
val fromNoIs = foo() !is String
|
||||
val fromIs = <!USELESS_IS_CHECK!>foo() is String<!>
|
||||
val fromNoIs = <!USELESS_IS_CHECK!>foo() !is String<!>
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !LANGUAGE: +ExpectedTypeFromCast
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -DEBUG_INFO_LEAKING_THIS
|
||||
|
||||
// FILE: a/View.java
|
||||
package a;
|
||||
|
||||
public class View {
|
||||
|
||||
}
|
||||
|
||||
// FILE: a/Test.java
|
||||
package a;
|
||||
|
||||
public class Test {
|
||||
public <T extends View> T findViewById(int id);
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
package a
|
||||
|
||||
|
||||
class X : View()
|
||||
|
||||
class Y<T> : View()
|
||||
|
||||
val xExplicit: X = Test().findViewById(0)
|
||||
val xCast = Test().findViewById(0) as X
|
||||
|
||||
val xCastExplicitType = Test().findViewById<X>(0) as X
|
||||
val xSafeCastExplicitType = Test().findViewById<X>(0) as? X
|
||||
|
||||
val yExplicit: Y<String> = Test().findViewById(0)
|
||||
val yCast = Test().findViewById(0) as Y<String>
|
||||
|
||||
|
||||
class TestChild : Test() {
|
||||
val xExplicit: X = findViewById(0)
|
||||
val xCast = findViewById(0) as X
|
||||
|
||||
val yExplicit: Y<String> = findViewById(0)
|
||||
val yCast = findViewById(0) as Y<String>
|
||||
}
|
||||
|
||||
fun test(t: Test) {
|
||||
val xExplicit: X = t.findViewById(0)
|
||||
val xCast = t.findViewById(0) as X
|
||||
|
||||
val yExplicit: Y<String> = t.findViewById(0)
|
||||
val yCast = t.findViewById(0) as Y<String>
|
||||
}
|
||||
|
||||
fun test2(t: Test?) {
|
||||
val xSafeCallSafeCast = t?.findViewById(0) as? X
|
||||
val xSafeCallSafeCastExplicitType = t?.findViewById<X>(0) as? X
|
||||
|
||||
val xSafeCallCast = t?.findViewById(0) as X
|
||||
val xSafeCallCastExplicitType = t<!UNNECESSARY_SAFE_CALL!>?.<!>findViewById<X>(0) as X
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !LANGUAGE: +ExpectedTypeFromCast
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -DEBUG_INFO_LEAKING_THIS
|
||||
|
||||
@@ -36,7 +36,7 @@ fun f10(init : A?) {
|
||||
if (!(a is B)) {
|
||||
return;
|
||||
}
|
||||
if (!(a is B)) {
|
||||
if (!(<!USELESS_IS_CHECK!>a is B<!>)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ fun f11(a : A?) {
|
||||
is B -> a.bar()
|
||||
is A -> a.foo()
|
||||
is Any -> a.foo()
|
||||
is Any? -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
<!USELESS_IS_CHECK!>is Any?<!> -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
else -> a?.foo()
|
||||
}
|
||||
}
|
||||
@@ -68,12 +68,12 @@ fun f12(a : A?) {
|
||||
is B -> a.bar()
|
||||
is A -> a.foo()
|
||||
is Any -> a.foo();
|
||||
is Any? -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
<!USELESS_IS_CHECK!>is Any?<!> -> a.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
is C -> a.bar()
|
||||
else -> a?.foo()
|
||||
}
|
||||
|
||||
if (a is Any?) {
|
||||
if (<!USELESS_IS_CHECK!>a is Any?<!>) {
|
||||
a?.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
}
|
||||
if (a is B) {
|
||||
@@ -198,7 +198,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 i: Int = a.compareTo("")
|
||||
}
|
||||
if (a is String && a.compareTo("") == 0) {}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
inline public fun reg(converter: (Any) -> Any, flag: Boolean) {
|
||||
flag
|
||||
converter("")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
inline public fun reg(converter: (Any) -> Any, flag: Boolean) {
|
||||
flag
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
inline public fun reg(converter: (Any) -> Any) {
|
||||
converter("")
|
||||
}
|
||||
|
||||
public inline fun register(converter: (Any) -> Any) {
|
||||
reg(when(<!USAGE_IS_NOT_INLINABLE!>converter<!>) {
|
||||
is (Any) -> Any -> <!USAGE_IS_NOT_INLINABLE!>converter<!>
|
||||
else -> <!USAGE_IS_NOT_INLINABLE!>converter<!>
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
inline public fun reg(converter: (Any) -> Any) {
|
||||
converter("")
|
||||
|
||||
@@ -6,7 +6,7 @@ class A
|
||||
|
||||
fun <T> test(v: T): T {
|
||||
val a = if (v !is A) {
|
||||
foo(v) as T
|
||||
foo(v) <!USELESS_CAST!>as T<!>
|
||||
}
|
||||
else {
|
||||
v
|
||||
@@ -18,7 +18,7 @@ fun <T> test(v: T): T {
|
||||
|
||||
fun <T> test2(v: T): T {
|
||||
val a = if (v !is A) {
|
||||
foo(v) as T
|
||||
foo(v) <!USELESS_CAST!>as T<!>
|
||||
}
|
||||
else {
|
||||
v as T
|
||||
@@ -42,7 +42,7 @@ fun <T> test3(v: T): T {
|
||||
|
||||
fun <T> test4(v: T): T {
|
||||
val a: T = if (v !is A) {
|
||||
foo(v) as T
|
||||
foo(v) <!USELESS_CAST!>as T<!>
|
||||
}
|
||||
else {
|
||||
v
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
sealed class Stmt
|
||||
|
||||
class ForStmt : Stmt()
|
||||
|
||||
sealed class Expr : Stmt() {
|
||||
object BinExpr : Expr()
|
||||
}
|
||||
|
||||
fun test(x: Stmt): String =
|
||||
when (x) {
|
||||
is Expr -> "expr"
|
||||
is Stmt -> "stmt"
|
||||
}
|
||||
|
||||
fun test2(x: Stmt): String =
|
||||
<!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||
is Expr -> "expr"
|
||||
}
|
||||
|
||||
fun test3(x: Expr): String =
|
||||
when (x) {
|
||||
is Stmt -> "stmt"
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
sealed class Stmt
|
||||
|
||||
class ForStmt : Stmt()
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
sealed class Sealed {
|
||||
object First: Sealed()
|
||||
open class NonFirst: Sealed() {
|
||||
object Second: NonFirst()
|
||||
object Third: NonFirst()
|
||||
}
|
||||
}
|
||||
|
||||
fun foo(s: Sealed): Int {
|
||||
return <!NO_ELSE_IN_WHEN!>when<!>(s) {
|
||||
is Sealed.First -> 1
|
||||
!is Any -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
sealed class Sealed {
|
||||
object First: Sealed()
|
||||
open class NonFirst: Sealed() {
|
||||
|
||||
@@ -17,7 +17,7 @@ fun String?.gav() {}
|
||||
fun bar(s: String?) {
|
||||
if (s != null) return
|
||||
s.gav()
|
||||
s as? String
|
||||
s as String?
|
||||
s <!USELESS_CAST!>as? String<!>
|
||||
s <!USELESS_CAST!>as String?<!>
|
||||
s as String
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ fun g(a: SomeClass?) {
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
(a <!USELESS_CAST!>as SomeSubClass<!>).foo
|
||||
}
|
||||
val b = (a as? SomeSubClass)?.foo
|
||||
if (b != null) {
|
||||
@@ -22,7 +22,7 @@ fun g(a: SomeClass?) {
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
(a <!USELESS_CAST!>as SomeSubClass<!>).foo
|
||||
}
|
||||
val c = a as? SomeSubClass
|
||||
if (c != null) {
|
||||
@@ -33,4 +33,4 @@ fun g(a: SomeClass?) {
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ fun g(a: SomeClass?) {
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
(a <!USELESS_CAST!>as SomeSubClass<!>).foo
|
||||
}
|
||||
val b = (a as? SomeSubClass)?.foo
|
||||
if (b != null) {
|
||||
@@ -22,7 +22,7 @@ fun g(a: SomeClass?) {
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
(a <!USELESS_CAST!>as SomeSubClass<!>).foo
|
||||
}
|
||||
val c = a as? SomeSubClass
|
||||
if (c != null) {
|
||||
@@ -33,4 +33,4 @@ fun g(a: SomeClass?) {
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// !LANGUAGE: +SafeCastCheckBoundSmartCasts
|
||||
// See KT-20752
|
||||
|
||||
class Unstable {
|
||||
val first: String? get() = null
|
||||
}
|
||||
|
||||
class StringList {
|
||||
fun remove(s: String) = s
|
||||
}
|
||||
|
||||
fun StringList.remove(s: String?) = s ?: ""
|
||||
|
||||
fun foo(list: StringList, arg: Unstable) {
|
||||
list.remove(arg.first)
|
||||
if (arg.first as? String != null) {
|
||||
// Should be still resolved to extension, without smart cast or smart cast impossible
|
||||
list.remove(arg.first)
|
||||
}
|
||||
val s = arg.first as? String
|
||||
if (s != null) {
|
||||
// Should be still resolved to extension, without smart cast or smart cast impossible
|
||||
list.remove(arg.first)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +SafeCastCheckBoundSmartCasts
|
||||
// See KT-20752
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ fun <T> T?.let(f: (T) -> Unit) {
|
||||
}
|
||||
|
||||
fun test(your: Your?) {
|
||||
(your?.foo() as? Any)?.let {}
|
||||
(your?.foo() <!USELESS_CAST!>as? Any<!>)?.let {}
|
||||
// strange smart cast to 'Your' at this point
|
||||
your<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// Type inference failed after smart cast
|
||||
|
||||
interface A<T>
|
||||
interface B<T> : A<T>
|
||||
|
||||
fun <T> foo(b: A<T>) = b
|
||||
|
||||
fun <T> test(a: A<T>) {
|
||||
if (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)
|
||||
}
|
||||
foo(a) // ok
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// Type inference failed after smart cast
|
||||
|
||||
interface A<T>
|
||||
|
||||
@@ -19,10 +19,10 @@ fun foo(a: A) {
|
||||
|
||||
fun foo2(a: A) {
|
||||
if (a is C) {
|
||||
if (a is B) {
|
||||
if (<!USELESS_IS_CHECK!>a is B<!>) {
|
||||
val t = when (a) {
|
||||
is CC -> "CC"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ object DD : D()
|
||||
fun foo1(a: A) {
|
||||
if (a is B) {
|
||||
if (a is D) {
|
||||
if (a is C) {
|
||||
if (<!USELESS_IS_CHECK!>a is C<!>) {
|
||||
val t =
|
||||
when (a) {
|
||||
is DD -> "DD"
|
||||
@@ -25,7 +25,7 @@ fun foo1(a: A) {
|
||||
fun foo2(a: A) {
|
||||
if (a is B) {
|
||||
if (a is D) {
|
||||
if (a is C) {
|
||||
if (<!USELESS_IS_CHECK!>a is C<!>) {
|
||||
val t =
|
||||
when (a) {
|
||||
is DD -> "DD"
|
||||
@@ -33,4 +33,4 @@ fun foo2(a: A) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
//KT-5455 Need warning about redundant type cast
|
||||
fun foo(o: Any): Int {
|
||||
if (o is String) {
|
||||
return (o as String).length
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
open class A {
|
||||
fun foo() {}
|
||||
}
|
||||
class B: A()
|
||||
|
||||
fun test(a: Any?) {
|
||||
if (a is B) {
|
||||
(a as A).foo()
|
||||
}
|
||||
}
|
||||
|
||||
fun test1(a: B) {
|
||||
(a as A?)?.foo()
|
||||
}
|
||||
|
||||
fun test2(b: B?) {
|
||||
if (b != null) {
|
||||
(b as A).foo()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
//KT-5455 Need warning about redundant type cast
|
||||
fun foo(o: Any): Int {
|
||||
if (o is String) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// See also KT-10992: we should have no errors for all unsafe hashCode() calls
|
||||
|
||||
fun foo(arg: Any?) {
|
||||
val x = arg as? Any ?: return
|
||||
val x = arg <!USELESS_CAST!>as? Any<!> ?: return
|
||||
arg.hashCode()
|
||||
x.hashCode()
|
||||
}
|
||||
|
||||
fun bar(arg: Any?) {
|
||||
arg as? Any ?: return
|
||||
arg <!USELESS_CAST!>as? Any<!> ?: return
|
||||
arg.hashCode()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
class C {
|
||||
fun foo(): String?? = null as Nothing??
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
class C {
|
||||
fun foo(): String?? = null <!USELESS_CAST!>as Nothing??<!>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
class C {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
companion object {
|
||||
val foo: String?? = null as Nothing??
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class C {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
companion object {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
fun foo(): Any? {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
return null as Nothing??
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun foo(): Any? {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
return null <!USELESS_CAST!>as Nothing??<!>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
class C {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
fun foo(): String?? = null as Nothing??
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class C {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
fun foo(): String?? = null <!USELESS_CAST!>as Nothing??<!>
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
class C {
|
||||
fun foo(): Any? {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
val v: String?? = null as Nothing??
|
||||
return v
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class C {
|
||||
fun foo(): Any? {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
object C {
|
||||
fun foo(): String?? = null as Nothing??
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
object C {
|
||||
fun foo(): String?? = null <!USELESS_CAST!>as Nothing??<!>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
class C {
|
||||
fun foo(@Suppress("REDUNDANT_NULLABLE") p: String?? = null as Nothing??) = p
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class C {
|
||||
fun foo(@Suppress("REDUNDANT_NULLABLE") p: String?? = null <!USELESS_CAST!>as Nothing??<!>) = p
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
class C {
|
||||
@Suppress("REDUNDANT_NULLABLE")
|
||||
val foo: String?? = null as Nothing?
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user