diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.kt b/compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.kt new file mode 100644 index 00000000000..43b5af89a04 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.kt @@ -0,0 +1,17 @@ +// WITH_RUNTIME + +fun foo(p: Int) { + val a = arrayOf(1, 2, 3) + val b = arrayOf(3, 2, 1) + + if (a == b) { } +} + +fun testsFromIdea() { + val a = arrayOf("a") + val b = a + val c: Any? = null + a == b + a == c + a != b +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.txt new file mode 100644 index 00000000000..ad6b5994878 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.txt @@ -0,0 +1,18 @@ +FILE: ArrayEqualityCanBeReplacedWithEquals.kt + public final fun foo(p: R|kotlin/Int|): R|kotlin/Unit| { + lval a: R|kotlin/Array| = R|kotlin/arrayOf|(vararg(Int(1), Int(2), Int(3))) + lval b: R|kotlin/Array| = R|kotlin/arrayOf|(vararg(Int(3), Int(2), Int(1))) + when () { + ==(R|/a|, R|/b|) -> { + } + } + + } + public final fun testsFromIdea(): R|kotlin/Unit| { + lval a: R|kotlin/Array| = R|kotlin/arrayOf|(vararg(String(a))) + lval b: R|kotlin/Array| = R|/a| + lval c: R|kotlin/Any?| = Null(null) + ==(R|/a|, R|/b|) + ==(R|/a|, R|/c|) + !=(R|/a|, R|/b|) + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java index 1b3951e6070..c4e76d6f416 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/ExtendedFirDiagnosticsTestGenerated.java @@ -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); } + @TestMetadata("ArrayEqualityCanBeReplacedWithEquals.kt") + public void testArrayEqualityCanBeReplacedWithEquals() throws Exception { + runTest("compiler/fir/analysis-tests/testData/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.kt"); + } + @TestMetadata("RedundantExplicitTypeChecker.kt") public void testRedundantExplicitTypeChecker() throws Exception { runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantExplicitTypeChecker.kt"); diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExtendedExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExtendedExpressionCheckers.kt index 317a34800cf..b43e8e1a4bd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExtendedExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExtendedExpressionCheckers.kt @@ -5,9 +5,13 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression +import org.jetbrains.kotlin.fir.analysis.checkers.extended.ArrayEqualityCanBeReplacedWithEquals import org.jetbrains.kotlin.fir.analysis.checkers.extended.CanBeReplacedWithOperatorAssignmentChecker object ExtendedExpressionCheckers : ExpressionCheckers() { + override val expressionCheckers: List = listOf( + ArrayEqualityCanBeReplacedWithEquals + ) override val variableAssignmentCheckers: List = listOf( CanBeReplacedWithOperatorAssignmentChecker ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/ArrayEqualityCanBeReplacedWithEquals.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/ArrayEqualityCanBeReplacedWithEquals.kt new file mode 100644 index 00000000000..99d4042dde0 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/ArrayEqualityCanBeReplacedWithEquals.kt @@ -0,0 +1,34 @@ +/* + * 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.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpresionChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS +import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall +import org.jetbrains.kotlin.fir.expressions.FirOperation +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.expressions.arguments +import org.jetbrains.kotlin.fir.psi +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.toFirPsiSourceElement +import org.jetbrains.kotlin.fir.types.classId +import org.jetbrains.kotlin.fir.types.coneType + +object ArrayEqualityCanBeReplacedWithEquals : FirBasicExpresionChecker() { + override fun check(equality: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) { + if (equality !is FirEqualityOperatorCall) return + if (equality.operation != FirOperation.EQ && equality.operation != FirOperation.NOT_EQ) return + val left = equality.arguments.getOrNull(0) ?: return + val right = equality.arguments.getOrNull(1) ?: return + + if (left.typeRef.coneType.classId != StandardClassIds.Array) return + if (right.typeRef.coneType.classId != StandardClassIds.Array) return + + reporter.report(equality.psi?.children?.get(1)?.toFirPsiSourceElement(), ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS) + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt index 5bbca3548fd..6d05b8282a6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt @@ -79,6 +79,10 @@ class ExpressionCheckersDiagnosticComponent(collector: AbstractDiagnosticCollect runCheck { checkers.expressionCheckers.check(getClassCall, data, it) } } + override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: CheckerContext) { + runCheck { checkers.expressionCheckers.check(equalityOperatorCall, data, it) } + } + override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) { runCheck { checkers.variableAssignmentCheckers.check(variableAssignment, data, it) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 0a2bb0bfe84..8be77f65dbd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -91,4 +91,5 @@ object FirErrors { val REDUNDANT_EXPLICIT_TYPE by warning0() val CAN_BE_VAL by warning0() val CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT by warning0() + val ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS by warning0() }