[FIR] Fix redundant explicit type checker
This commit is contained in:
committed by
Mikhail Glukhikh
parent
eecb43d4c9
commit
a988234bbf
+49
-17
@@ -1,3 +1,33 @@
|
|||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
annotation class A
|
||||||
|
|
||||||
|
fun annotated() {
|
||||||
|
val x: @A Int /* NOT redundant */ = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
object SomeObj
|
||||||
|
fun fer() {
|
||||||
|
val x: Any /* NOT redundant */ = SomeObj
|
||||||
|
}
|
||||||
|
|
||||||
|
fun f2(y: String?): String {
|
||||||
|
val f: KClass<*> = (y ?: return "")::class
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
object Obj {}
|
||||||
|
|
||||||
|
interface IA
|
||||||
|
interface IB : IA
|
||||||
|
|
||||||
|
fun IA.extFun(x: IB) {}
|
||||||
|
|
||||||
|
fun testWithExpectedType() {
|
||||||
|
val extFun_AB_A: IA.(IB) -> Unit = IA::extFun
|
||||||
|
}
|
||||||
|
|
||||||
interface Point {
|
interface Point {
|
||||||
val x: Int
|
val x: Int
|
||||||
val y: Int
|
val y: Int
|
||||||
@@ -6,35 +36,37 @@ interface Point {
|
|||||||
class PointImpl(override val x: Int, override val y: Int) : Point
|
class PointImpl(override val x: Int, override val y: Int) : Point
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
|
val s: <!REDUNDANT_EXPLICIT_TYPE!>String<!> = "Hello ${10+1}"
|
||||||
|
val str: String? = ""
|
||||||
|
|
||||||
|
val o: <!REDUNDANT_EXPLICIT_TYPE!>Obj<!> = Obj
|
||||||
|
|
||||||
val p: Point = PointImpl(1, 2)
|
val p: Point = PointImpl(1, 2)
|
||||||
val a: <!REDUNDANT_EXPLICIT_TYPE!>Boolean<!> = true
|
val a: <!REDUNDANT_EXPLICIT_TYPE!>Boolean<!> = true
|
||||||
val i: Int = 2 * 2
|
val i: Int = 2 * 2
|
||||||
val l: <!REDUNDANT_EXPLICIT_TYPE!>Long<!> = 1234567890123L
|
val l: <!REDUNDANT_EXPLICIT_TYPE!>Long<!> = 1234567890123L
|
||||||
val s: String? = null
|
val s: String? = null
|
||||||
val sh: Short = 42
|
val sh: Short = 42
|
||||||
|
|
||||||
|
val integer: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 42
|
||||||
|
val piFloat: <!REDUNDANT_EXPLICIT_TYPE!>Float<!> = 3.14f
|
||||||
|
val piDouble: <!REDUNDANT_EXPLICIT_TYPE!>Double<!> = 3.14
|
||||||
|
val charZ: <!REDUNDANT_EXPLICIT_TYPE!>Char<!> = 'z'
|
||||||
|
var alpha: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(boolean: Boolean) {
|
||||||
|
val expectedLong: Long = if (boolean) {
|
||||||
|
42
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class My {
|
class My {
|
||||||
val x: Int = 1
|
val x: Int = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
object Obj {}
|
|
||||||
|
|
||||||
fun bar() {
|
|
||||||
val o: <!REDUNDANT_EXPLICIT_TYPE!>Obj<!> = Obj
|
|
||||||
}
|
|
||||||
|
|
||||||
fun doo() {
|
|
||||||
val i: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 42
|
|
||||||
val pi: <!REDUNDANT_EXPLICIT_TYPE!>Float<!> = 3.14f
|
|
||||||
val pi2: <!REDUNDANT_EXPLICIT_TYPE!>Double<!> = 3.14
|
|
||||||
val ch: <!REDUNDANT_EXPLICIT_TYPE!>Char<!> = 'z'
|
|
||||||
}
|
|
||||||
|
|
||||||
fun soo() {
|
|
||||||
val s: <!REDUNDANT_EXPLICIT_TYPE!>String<!> = "Hello ${10+1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
val ZERO: Int = 0
|
val ZERO: Int = 0
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
|||||||
+56
-18
@@ -1,4 +1,41 @@
|
|||||||
FILE: RedundantExplicitTypeChecker.kt
|
FILE: RedundantExplicitTypeChecker.kt
|
||||||
|
@R|kotlin/annotation/Target|(vararg(Q|kotlin/annotation/AnnotationTarget|.R|kotlin/annotation/AnnotationTarget.TYPE|)) public final annotation class A : R|kotlin/Annotation| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun annotated(): R|kotlin/Unit| {
|
||||||
|
lval x: @R|A|() R|kotlin/Int| = Int(1)
|
||||||
|
}
|
||||||
|
public final object SomeObj : R|kotlin/Any| {
|
||||||
|
private constructor(): R|SomeObj| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun fer(): R|kotlin/Unit| {
|
||||||
|
lval x: R|kotlin/Any| = Q|SomeObj|
|
||||||
|
}
|
||||||
|
public final fun f2(y: R|kotlin/String?|): R|kotlin/String| {
|
||||||
|
lval f: R|kotlin/reflect/KClass<*>| = <getClass>(R|<local>/y| ?: ^f2 String())
|
||||||
|
^f2 String()
|
||||||
|
}
|
||||||
|
public final object Obj : R|kotlin/Any| {
|
||||||
|
private constructor(): R|Obj| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public abstract interface IA : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public abstract interface IB : R|IA| {
|
||||||
|
}
|
||||||
|
public final fun R|IA|.extFun(x: R|IB|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun testWithExpectedType(): R|kotlin/Unit| {
|
||||||
|
lval extFun_AB_A: R|IA.(IB) -> kotlin/Unit| = Q|IA|::R|/extFun|
|
||||||
|
}
|
||||||
public abstract interface Point : R|kotlin/Any| {
|
public abstract interface Point : R|kotlin/Any| {
|
||||||
public abstract val x: R|kotlin/Int|
|
public abstract val x: R|kotlin/Int|
|
||||||
public get(): R|kotlin/Int|
|
public get(): R|kotlin/Int|
|
||||||
@@ -20,12 +57,31 @@ FILE: RedundantExplicitTypeChecker.kt
|
|||||||
|
|
||||||
}
|
}
|
||||||
public final fun foo(): R|kotlin/Unit| {
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
|
lval s: R|kotlin/String| = <strcat>(String(Hello ), Int(10).R|kotlin/Int.plus|(Int(1)).R|kotlin/Any.toString|())
|
||||||
|
lval str: R|kotlin/String?| = String()
|
||||||
|
lval o: R|Obj| = Q|Obj|
|
||||||
lval p: R|Point| = R|/PointImpl.PointImpl|(Int(1), Int(2))
|
lval p: R|Point| = R|/PointImpl.PointImpl|(Int(1), Int(2))
|
||||||
lval a: R|kotlin/Boolean| = Boolean(true)
|
lval a: R|kotlin/Boolean| = Boolean(true)
|
||||||
lval i: R|kotlin/Int| = Int(2).R|kotlin/Int.times|(Int(2))
|
lval i: R|kotlin/Int| = Int(2).R|kotlin/Int.times|(Int(2))
|
||||||
lval l: R|kotlin/Long| = Long(1234567890123)
|
lval l: R|kotlin/Long| = Long(1234567890123)
|
||||||
lval s: R|kotlin/String?| = Null(null)
|
lval s: R|kotlin/String?| = Null(null)
|
||||||
lval sh: R|kotlin/Short| = Short(42)
|
lval sh: R|kotlin/Short| = Short(42)
|
||||||
|
lval integer: R|kotlin/Int| = Int(42)
|
||||||
|
lval piFloat: R|kotlin/Float| = Float(3.14)
|
||||||
|
lval piDouble: R|kotlin/Double| = Double(3.14)
|
||||||
|
lval charZ: R|kotlin/Char| = Char(z)
|
||||||
|
lvar alpha: R|kotlin/Int| = Int(0)
|
||||||
|
}
|
||||||
|
public final fun test(boolean: R|kotlin/Boolean|): R|kotlin/Unit| {
|
||||||
|
lval expectedLong: R|kotlin/Long| = when () {
|
||||||
|
R|<local>/boolean| -> {
|
||||||
|
Int(42)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
^test Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public final class My : R|kotlin/Any| {
|
public final class My : R|kotlin/Any| {
|
||||||
public constructor(): R|My| {
|
public constructor(): R|My| {
|
||||||
@@ -36,24 +92,6 @@ FILE: RedundantExplicitTypeChecker.kt
|
|||||||
public get(): R|kotlin/Int|
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
}
|
}
|
||||||
public final object Obj : R|kotlin/Any| {
|
|
||||||
private constructor(): R|Obj| {
|
|
||||||
super<R|kotlin/Any|>()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
public final fun bar(): R|kotlin/Unit| {
|
|
||||||
lval o: R|Obj| = Q|Obj|
|
|
||||||
}
|
|
||||||
public final fun doo(): R|kotlin/Unit| {
|
|
||||||
lval i: R|kotlin/Int| = Int(42)
|
|
||||||
lval pi: R|kotlin/Float| = Float(3.14)
|
|
||||||
lval pi2: R|kotlin/Double| = Double(3.14)
|
|
||||||
lval ch: R|kotlin/Char| = Char(z)
|
|
||||||
}
|
|
||||||
public final fun soo(): R|kotlin/Unit| {
|
|
||||||
lval s: R|kotlin/String| = <strcat>(String(Hello ), Int(10).R|kotlin/Int.plus|(Int(1)).R|kotlin/Any.toString|())
|
|
||||||
}
|
|
||||||
public final val ZERO: R|kotlin/Int| = Int(0)
|
public final val ZERO: R|kotlin/Int| = Int(0)
|
||||||
public get(): R|kotlin/Int|
|
public get(): R|kotlin/Int|
|
||||||
public final fun main(): R|kotlin/Unit| {
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
|||||||
+29
-11
@@ -14,15 +14,16 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
|
||||||
import org.jetbrains.kotlin.fir.psi
|
import org.jetbrains.kotlin.fir.psi
|
||||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.classId
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
|
object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
|
||||||
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
@@ -37,32 +38,33 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
|
|||||||
val type = declaration.returnTypeRef.coneType
|
val type = declaration.returnTypeRef.coneType
|
||||||
|
|
||||||
if (typeReference is FirTypeAlias) return
|
if (typeReference is FirTypeAlias) return
|
||||||
|
if (typeReference.annotations.isNotEmpty()) return
|
||||||
|
|
||||||
when (initializer) {
|
when (initializer) {
|
||||||
is FirConstExpression<*> -> {
|
is FirConstExpression<*> -> {
|
||||||
when (initializer.source?.elementType) {
|
when (initializer.source?.elementType) {
|
||||||
KtNodeTypes.BOOLEAN_CONSTANT -> {
|
KtNodeTypes.BOOLEAN_CONSTANT -> {
|
||||||
if (type.classId != StandardClassIds.Boolean) return
|
if (!type.isSame(StandardClassIds.Boolean)) return
|
||||||
}
|
}
|
||||||
KtNodeTypes.INTEGER_CONSTANT -> {
|
KtNodeTypes.INTEGER_CONSTANT -> {
|
||||||
if (initializer.text?.endsWith("L") == true) {
|
if (initializer.text?.endsWith("L") == true) {
|
||||||
if (type.classId != StandardClassIds.Long) return
|
if (!type.isSame(StandardClassIds.Long)) return
|
||||||
} else {
|
} else {
|
||||||
if (type.classId != StandardClassIds.Int) return
|
if (!type.isSame(StandardClassIds.Int)) return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KtNodeTypes.FLOAT_CONSTANT -> {
|
KtNodeTypes.FLOAT_CONSTANT -> {
|
||||||
if (initializer.text?.endsWith("f", ignoreCase = true) == true) {
|
if (initializer.text?.endsWith("f", ignoreCase = true) == true) {
|
||||||
if (type.classId != StandardClassIds.Float) return
|
if (!type.isSame(StandardClassIds.Float)) return
|
||||||
} else {
|
} else {
|
||||||
if (type.classId != StandardClassIds.Double) return
|
if (!type.isSame(StandardClassIds.Double)) return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KtNodeTypes.CHARACTER_CONSTANT -> {
|
KtNodeTypes.CHARACTER_CONSTANT -> {
|
||||||
if (type.classId != StandardClassIds.Char) return
|
if (!type.isSame(StandardClassIds.Char)) return
|
||||||
}
|
}
|
||||||
KtNodeTypes.STRING_TEMPLATE -> {
|
KtNodeTypes.STRING_TEMPLATE -> {
|
||||||
if (type.classId != StandardClassIds.String) return
|
if (!type.isSame(StandardClassIds.String)) return
|
||||||
}
|
}
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
@@ -71,8 +73,18 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
|
|||||||
if (typeReference.text != initializer.name.identifier) return
|
if (typeReference.text != initializer.name.identifier) return
|
||||||
}
|
}
|
||||||
is FirFunctionCall -> {
|
is FirFunctionCall -> {
|
||||||
if (typeReference.text != initializer.calleeReference.name.identifier) return
|
if (typeReference.text != initializer.calleeReference.name.asString()) return
|
||||||
}
|
}
|
||||||
|
is FirGetClassCall -> {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
is FirResolvedQualifier -> {
|
||||||
|
if (!type.isSame(initializer.classId)) return
|
||||||
|
}
|
||||||
|
is FirStringConcatenationCall -> {
|
||||||
|
if (!type.isSame(StandardClassIds.String)) return
|
||||||
|
}
|
||||||
|
else -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
reporter.report(declaration.returnTypeRef.source, FirErrors.REDUNDANT_EXPLICIT_TYPE)
|
reporter.report(declaration.returnTypeRef.source, FirErrors.REDUNDANT_EXPLICIT_TYPE)
|
||||||
@@ -84,4 +96,10 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
|
|||||||
private val FirTypeRef.text
|
private val FirTypeRef.text
|
||||||
get() = this.psi?.text
|
get() = this.psi?.text
|
||||||
|
|
||||||
|
private fun ConeKotlinType.isSame(other: ClassId?): Boolean {
|
||||||
|
if (this.nullability.isNullable) return false
|
||||||
|
if (this.type.classId == other) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user