[FIR] Support of REDECLARATION for local val/var, ^KT-54405 Fixed

This commit is contained in:
Ivan Kochurkin
2022-12-01 15:08:34 +01:00
committed by Space Team
parent 879deb90fc
commit e49bb1fe37
30 changed files with 201 additions and 85 deletions
@@ -59,10 +59,10 @@ FILE: upperBoundViolated.kt
lval o3: R|S<L, L>| = R|/S.S|<R|L|, R|L|>()
lval o4: R|S<S<K, L>, T<K, L>>| = R|/S.S|<R|S<K, L>|, R|T<K, L>|>()
lval o5: R|S<S<K, L>, T<K, K>>| = R|/S.S<Inapplicable(INAPPLICABLE): /S.S>#|<R|S<K, L>|, R|T<K, K>|>()
lval o5: R|S<S<L, L>, T<K, L>>| = R|/S.S<Inapplicable(INAPPLICABLE): /S.S>#|<R|S<L, L>|, R|T<K, L>|>()
lval o6: R|S<kotlin/Any, T<S<K, L>, kotlin/String>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/String>|>()
lval o7: R|S<kotlin/Any, T<S<K, L>, kotlin/Nothing>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/Nothing>|>()
lval o8: R|P<kotlin/String, P1<kotlin/String, kotlin/String>>| = R|/P.P<Inapplicable(INAPPLICABLE): /P.P>#|<R|kotlin/String|, R|P1<kotlin/String, kotlin/String>|>()
lval o6: R|S<S<L, L>, T<K, L>>| = R|/S.S<Inapplicable(INAPPLICABLE): /S.S>#|<R|S<L, L>|, R|T<K, L>|>()
lval o7: R|S<kotlin/Any, T<S<K, L>, kotlin/String>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/String>|>()
lval o8: R|S<kotlin/Any, T<S<K, L>, kotlin/Nothing>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/Nothing>|>()
lval o9: R|P<kotlin/String, P1<kotlin/String, kotlin/String>>| = R|/P.P<Inapplicable(INAPPLICABLE): /P.P>#|<R|kotlin/String|, R|P1<kotlin/String, kotlin/String>|>()
}
public final class NumColl<T : R|kotlin/collections/Collection<kotlin/Number>|> : R|kotlin/Any| {
public constructor<T : R|kotlin/collections/Collection<kotlin/Number>|>(): R|NumColl<T>| {
@@ -35,11 +35,11 @@ fun <K, L : K> rest() {
val o4 = S<S<K, L>, T<K, L>>()
val o5 = S<S<K, L>, <!UPPER_BOUND_VIOLATED!>T<K, K><!>>()
val o5 = S<S<L, L>, <!UPPER_BOUND_VIOLATED!>T<K, L><!>>()
val o6 = S<S<L, L>, <!UPPER_BOUND_VIOLATED!>T<K, L><!>>()
val o6 = S<Any, T<S<K, L>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
val o7 = S<Any, T<S<K, L>, Nothing>>()
val o8 = P<<!UPPER_BOUND_VIOLATED!>String<!>, P1<<!UPPER_BOUND_VIOLATED!>String<!>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
val o7 = S<Any, T<S<K, L>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
val o8 = S<Any, T<S<K, L>, Nothing>>()
val o9 = P<<!UPPER_BOUND_VIOLATED!>String<!>, P1<<!UPPER_BOUND_VIOLATED!>String<!>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
}
class NumColl<T : Collection<Number>>
@@ -32,7 +32,7 @@ FILE: missingBooleanBranch.kt
}
}
lval x: R|kotlin/Int| = when (R|<local>/cond|) {
lval y: R|kotlin/Int| = when (R|<local>/cond|) {
==($subj$, Boolean(true)) -> {
Int(1)
}
@@ -19,7 +19,7 @@ fun test_2(cond: Boolean?) {
false -> 2
}
val x = when (cond) {
val y = when (cond) {
true -> 1
false -> 2
null -> 3
@@ -74,7 +74,7 @@ FILE: exhaustiveness_enum.kt
}
}
lval a: R|kotlin/Int| = when (R|<local>/e|) {
lval b: R|kotlin/Int| = when (R|<local>/e|) {
==($subj$, Q|Enum|.R|/Enum.A|) -> {
Int(1)
}
@@ -89,7 +89,7 @@ FILE: exhaustiveness_enum.kt
}
}
lval a: R|kotlin/Int| = when (R|<local>/e|) {
lval c: R|kotlin/Int| = when (R|<local>/e|) {
==($subj$, Q|Enum|.R|/Enum.A|) -> {
Int(1)
}
@@ -33,14 +33,14 @@ fun test_2(e: Enum?) {
Enum.C -> 3
}
val a = when (e) {
val b = when (e) {
Enum.A -> 1
Enum.B -> 2
Enum.C -> 3
null -> 4
}
val a = when (e) {
val c = when (e) {
Enum.A -> 1
Enum.B -> 2
Enum.C -> 3
@@ -56,7 +56,7 @@ FILE: main.kt
}
}
.<Unresolved name: plus>#(Int(0))
lval a: R|kotlin/Int| = when (R|<local>/e|) {
lval b: R|kotlin/Int| = when (R|<local>/e|) {
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
Int(1)
}
@@ -71,7 +71,7 @@ FILE: main.kt
}
}
.R|kotlin/Int.plus|(Int(0))
lval a: R|kotlin/Int| = when (R|<local>/e|) {
lval c: R|kotlin/Int| = when (R|<local>/e|) {
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
Int(1)
}
@@ -37,14 +37,14 @@ fun test_2(e: JavaEnum?) {
JavaEnum.C -> 3
}.<!UNRESOLVED_REFERENCE!>plus<!>(0)
val a = when (e) {
val b = when (e) {
JavaEnum.A -> 1
JavaEnum.B -> 2
JavaEnum.C -> 3
null -> 4
}.plus(0)
val a = when (e) {
val c = when (e) {
JavaEnum.A -> 1
JavaEnum.B -> 2
JavaEnum.C -> 3
@@ -64,7 +64,7 @@ FILE: RedundantExplicitTypeChecker.kt
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 s1: R|kotlin/String?| = Null(null)
lval sh: R|kotlin/Short| = Short(42)
lval integer: R|kotlin/Int| = Int(42)
lval piFloat: R|kotlin/Float| = Float(3.14)
@@ -45,7 +45,7 @@ fun foo() {
val <!UNUSED_VARIABLE!>a<!>: <!REDUNDANT_EXPLICIT_TYPE!>Boolean<!> = true
val <!UNUSED_VARIABLE!>i<!>: Int = 2 * 2
val <!UNUSED_VARIABLE!>l<!>: <!REDUNDANT_EXPLICIT_TYPE!>Long<!> = 1234567890123L
val <!UNUSED_VARIABLE!>s<!>: String? = null
val <!UNUSED_VARIABLE!>s1<!>: String? = null
val <!UNUSED_VARIABLE!>sh<!>: Short = 42
val <!UNUSED_VARIABLE!>integer<!>: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 42
@@ -25770,6 +25770,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
}
@Test
@TestMetadata("RedeclaredValsAndVars.kt")
public void testRedeclaredValsAndVars() throws Exception {
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValsAndVars.kt");
}
@Test
@TestMetadata("RedeclaredValueParameters.kt")
public void testRedeclaredValueParameters() throws Exception {
@@ -25776,6 +25776,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
}
@Test
@TestMetadata("RedeclaredValsAndVars.kt")
public void testRedeclaredValsAndVars() throws Exception {
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValsAndVars.kt");
}
@Test
@TestMetadata("RedeclaredValueParameters.kt")
public void testRedeclaredValueParameters() throws Exception {
@@ -18,7 +18,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
get() = setOf(
FirModifierChecker,
FirConflictsChecker,
FirConflictsDeclarationChecker,
FirProjectionRelationChecker,
FirTypeConstraintsChecker,
FirReservedUnderscoreDeclarationChecker,
@@ -115,7 +115,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val blockCheckers: Set<FirBlockChecker>
get() = setOf(
FirForLoopChecker
FirForLoopChecker,
FirConflictsExpressionChecker
)
override val checkNotNullCallCheckers: Set<FirCheckNotNullCallChecker>
@@ -6,10 +6,17 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.util.ListMultimap
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@@ -279,3 +286,41 @@ open class FirDeclarationInspector(
else -> false
}
}
fun checkConflictingElements(elements: List<FirElement>, context: CheckerContext, reporter: DiagnosticReporter) {
if (elements.size <= 1) return
val multimap = ListMultimap<Name, FirBasedSymbol<*>>()
for (element in elements) {
val name: Name?
val symbol: FirBasedSymbol<*>?
when (element) {
is FirVariable -> {
symbol = element.symbol
name = element.name
}
is FirOuterClassTypeParameterRef -> {
continue
}
is FirTypeParameterRef -> {
symbol = element.symbol
name = symbol.name
}
else -> {
symbol = null
name = null
}
}
if (name?.isSpecial == false) {
multimap.put(name, symbol!!)
}
}
for (key in multimap.keys) {
val conflictingElements = multimap[key]
if (conflictingElements.size > 1) {
for (conflictingElement in conflictingElements) {
reporter.reportOn(conflictingElement.source, FirErrors.REDECLARATION, conflictingElements, context)
}
}
}
}
@@ -12,10 +12,10 @@ import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter
import org.jetbrains.kotlin.fir.analysis.checkers.checkConflictingElements
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
@@ -25,13 +25,12 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.util.ListMultimap
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.SmartSet
object FirConflictsChecker : FirBasicDeclarationChecker() {
object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
private class DeclarationInspector : FirDeclarationInspector() {
@@ -272,46 +271,6 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
}
}
private fun checkConflictingParameters(parameters: List<FirElement>, context: CheckerContext, reporter: DiagnosticReporter) {
if (parameters.size <= 1) return
val multimap = ListMultimap<Name, FirBasedSymbol<*>>()
for (parameter in parameters) {
val name: Name
val symbol: FirBasedSymbol<*>
when (parameter) {
is FirValueParameter -> {
symbol = parameter.symbol
name = parameter.name
}
is FirOuterClassTypeParameterRef -> {
continue
}
is FirTypeParameterRef -> {
symbol = parameter.symbol
name = symbol.name
}
else -> throw AssertionError("Invalid parameter type")
}
if (!name.isSpecial) {
multimap.put(name, symbol)
}
}
for (key in multimap.keys) {
val conflictingParameters = multimap[key]
if (conflictingParameters.size > 1) {
for (parameter in conflictingParameters) {
reporter.reportOn(
parameter.source,
FirErrors.REDECLARATION,
conflictingParameters,
context
)
}
}
}
}
private fun checkFile(file: FirFile, inspector: DeclarationInspector, context: CheckerContext) {
val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
FirPackageMemberScope(file.packageFqName, context.sessionHolder.session)
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2022 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.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.checkConflictingElements
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.expressions.FirBlock
object FirConflictsExpressionChecker : FirBlockChecker() {
override fun check(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) {
checkConflictingElements(expression.statements, context, reporter)
}
}