[FIR] Add RedundantExplicitTypeChecker
This commit is contained in:
committed by
Mikhail Glukhikh
parent
3c798502c8
commit
63f7e95c89
+44
@@ -0,0 +1,44 @@
|
|||||||
|
interface Point {
|
||||||
|
val x: Int
|
||||||
|
val y: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class PointImpl(override val x: Int, override val y: Int) : Point
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val p: Point = PointImpl(1, 2)
|
||||||
|
val a: <!REDUNDANT_EXPLICIT_TYPE!>Boolean<!> = true
|
||||||
|
val i: Int = 2 * 2
|
||||||
|
val l: <!REDUNDANT_EXPLICIT_TYPE!>Long<!> = 1234567890123L
|
||||||
|
val s: String? = null
|
||||||
|
val sh: Short = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
class My {
|
||||||
|
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
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val id: Id = 11
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias Id = Int
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
FILE: RedundantExplicitTypeChecker.kt
|
||||||
|
public abstract interface Point : R|kotlin/Any| {
|
||||||
|
public abstract val x: R|kotlin/Int|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public abstract val y: R|kotlin/Int|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class PointImpl : R|Point| {
|
||||||
|
public constructor(x: R|kotlin/Int|, y: R|kotlin/Int|): R|PointImpl| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final override val x: R|kotlin/Int| = R|<local>/x|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final override val y: R|kotlin/Int| = R|<local>/y|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
|
lval p: R|Point| = R|/PointImpl.PointImpl|(Int(1), Int(2))
|
||||||
|
lval a: R|kotlin/Boolean| = Boolean(true)
|
||||||
|
lval i: R|kotlin/Int| = Int(2).R|kotlin/Int.times|(Int(2))
|
||||||
|
lval l: R|kotlin/Long| = Long(1234567890123)
|
||||||
|
lval s: R|kotlin/String?| = Null(null)
|
||||||
|
lval sh: R|kotlin/Short| = Short(42)
|
||||||
|
}
|
||||||
|
public final class My : R|kotlin/Any| {
|
||||||
|
public constructor(): R|My| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val x: R|kotlin/Int| = Int(1)
|
||||||
|
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 get(): R|kotlin/Int|
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
lval id: R|Id| = Int(11)
|
||||||
|
}
|
||||||
|
public final typealias Id = R|kotlin/Int|
|
||||||
Generated
+5
@@ -28,6 +28,11 @@ public class ExtendedFirDiagnosticsTestGenerated extends AbstractExtendedFirDiag
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/extendedCheckers"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/extendedCheckers"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantExplicitTypeChecker.kt")
|
||||||
|
public void testRedundantExplicitTypeChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantExplicitTypeChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("RedundantModalityModifierChecker.kt")
|
@TestMetadata("RedundantModalityModifierChecker.kt")
|
||||||
public void testRedundantModalityModifierChecker() throws Exception {
|
public void testRedundantModalityModifierChecker() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantModalityModifierChecker.kt");
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantModalityModifierChecker.kt");
|
||||||
|
|||||||
+3
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantExplicitTypeChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantModalityModifierChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantModalityModifierChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantReturnUnitType
|
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantReturnUnitType
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantVisibilityModifierChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantVisibilityModifierChecker
|
||||||
@@ -20,7 +21,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf(
|
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf(
|
||||||
FirInfixFunctionDeclarationChecker,
|
FirInfixFunctionDeclarationChecker,
|
||||||
FirExposedVisibilityChecker,
|
FirExposedVisibilityChecker,
|
||||||
RedundantModalityModifierChecker
|
RedundantModalityModifierChecker,
|
||||||
|
RedundantExplicitTypeChecker
|
||||||
)
|
)
|
||||||
|
|
||||||
override val constructorCheckers: List<FirConstructorChecker> = listOf(
|
override val constructorCheckers: List<FirConstructorChecker> = listOf(
|
||||||
|
|||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.extended
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
import org.jetbrains.kotlin.fir.FirFakeSourceElement
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||||
|
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.references.FirNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
|
||||||
|
object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
|
||||||
|
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if (declaration !is FirProperty) return
|
||||||
|
if (!declaration.isLocal) return
|
||||||
|
|
||||||
|
val initializer = declaration.initializer ?: return
|
||||||
|
val typeReference = declaration.returnTypeRef
|
||||||
|
|
||||||
|
if (typeReference.source is FirFakeSourceElement<*>) return
|
||||||
|
|
||||||
|
val type = declaration.returnTypeRef.coneType
|
||||||
|
|
||||||
|
if (typeReference is FirTypeAlias) return
|
||||||
|
|
||||||
|
when (initializer) {
|
||||||
|
is FirConstExpression<*> -> {
|
||||||
|
when (initializer.source?.elementType) {
|
||||||
|
KtNodeTypes.BOOLEAN_CONSTANT -> {
|
||||||
|
if (type.classId != StandardClassIds.Boolean) return
|
||||||
|
}
|
||||||
|
KtNodeTypes.INTEGER_CONSTANT -> {
|
||||||
|
if (initializer.text?.endsWith("L") == true) {
|
||||||
|
if (type.classId != StandardClassIds.Long) return
|
||||||
|
} else {
|
||||||
|
if (type.classId != StandardClassIds.Int) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KtNodeTypes.FLOAT_CONSTANT -> {
|
||||||
|
if (initializer.text?.endsWith("f", ignoreCase = true) == true) {
|
||||||
|
if (type.classId != StandardClassIds.Float) return
|
||||||
|
} else {
|
||||||
|
if (type.classId != StandardClassIds.Double) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KtNodeTypes.CHARACTER_CONSTANT -> {
|
||||||
|
if (type.classId != StandardClassIds.Char) return
|
||||||
|
}
|
||||||
|
KtNodeTypes.STRING_TEMPLATE -> {
|
||||||
|
if (type.classId != StandardClassIds.String) return
|
||||||
|
}
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is FirNamedReference -> {
|
||||||
|
if (typeReference.text != initializer.name.identifier) return
|
||||||
|
}
|
||||||
|
is FirFunctionCall -> {
|
||||||
|
if (typeReference.text != initializer.calleeReference.name.identifier) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reporter.report(declaration.returnTypeRef.source, FirErrors.REDUNDANT_EXPLICIT_TYPE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FirExpression.text
|
||||||
|
get() = this.source.psi?.text
|
||||||
|
|
||||||
|
private val FirTypeRef.text
|
||||||
|
get() = this.psi?.text
|
||||||
|
|
||||||
|
}
|
||||||
@@ -86,6 +86,7 @@ object FirErrors {
|
|||||||
val REDUNDANT_VISIBILITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
|
val REDUNDANT_VISIBILITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
|
||||||
val REDUNDANT_MODALITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
|
val REDUNDANT_MODALITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
|
||||||
val REDUNDANT_RETURN_UNIT_TYPE by warning0<FirSourceElement, PsiTypeElement>()
|
val REDUNDANT_RETURN_UNIT_TYPE by warning0<FirSourceElement, PsiTypeElement>()
|
||||||
|
val REDUNDANT_EXPLICIT_TYPE by warning0<FirSourceElement, PsiElement>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user