diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt index 40f83044790..5ab049ef4a9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt @@ -24,8 +24,7 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.outerType import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.scope -import org.jetbrains.kotlin.fir.scopes.CallableCopyTypeCalculator -import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope import org.jetbrains.kotlin.fir.scopes.impl.TypeAliasConstructorsSubstitutingScope import org.jetbrains.kotlin.fir.scopes.impl.toConeType @@ -151,32 +150,72 @@ class FirDeclarationCollector>( fun FirDeclarationCollector>.collectClassMembers(klass: FirRegularClassSymbol) { val otherDeclarations = mutableMapOf>>() val functionDeclarations = mutableMapOf>>() + val scope = klass.unsubstitutedScope(context) - // TODO, KT-61243: Use declaredMemberScope - @OptIn(SymbolInternals::class) - for (it in klass.fir.declarations) { - if (!it.symbol.isCollectable()) continue + scope.collectLeafFunctions().forEach { + if (it.isCollectable() && it.isVisibleInClass(klass)) { + collect(it, FirRedeclarationPresenter.represent(it), functionDeclarations) + } + } - when (it) { - is FirSimpleFunction -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), functionDeclarations) - is FirRegularClass -> { - collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), otherDeclarations) + val visitedProperties = mutableSetOf>() - // Objects have implicit FirPrimaryConstructors - if (it.symbol.classKind == ClassKind.OBJECT) { - continue - } + scope.collectLeafProperties().forEach { + if (it.isCollectable() && it.isVisibleInClass(klass)) { + collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations) + } + visitedProperties.add(it) + } - it.symbol.expandedClassWithConstructorsScope(context)?.let { (_, scopeWithConstructors) -> - scopeWithConstructors.processDeclaredConstructors { constructor -> - collect(constructor, FirRedeclarationPresenter.represent(constructor, it.symbol), functionDeclarations) - } - } - } - is FirTypeAlias -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), otherDeclarations) - is FirVariable -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), otherDeclarations) + klass.declaredMemberScope(context).processAllProperties { + if (it !in visitedProperties && it.isCollectable()) { + collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations) + } + } + + fun processClassifier(it: FirClassifierSymbol<*>) { + when { + !it.isCollectable() || !it.isVisibleInClass(klass) -> return + it is FirRegularClassSymbol -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations) + it is FirTypeAliasSymbol -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations) else -> {} } + + // This `if` can't be merged with the `when` + // above, because otherwise the smartcast + // below doesn't work. + if (it !is FirClassLikeSymbol<*>) { + return + } + + it.expandedClassWithConstructorsScope(context)?.let { (expandedClass, scopeWithConstructors) -> + // Objects have implicit FirPrimaryConstructors + if (expandedClass.classKind == ClassKind.OBJECT) { + return@let + } + + scopeWithConstructors.processDeclaredConstructors { constructor -> + collect(constructor, FirRedeclarationPresenter.represent(constructor, it), functionDeclarations) + } + } + } + + val visitedClassifiers = mutableSetOf>() + + scope.processAllClassifiers { + processClassifier(it) + visitedClassifiers.add(it) + } + + // Scopes refer to inner classifiers + // through maps indexed by names, + // so only the last declaration is + // observed when processing all + // classifiers + for (it in klass.declarationSymbols) { + if (it is FirClassifierSymbol<*> && it !in visitedClassifiers) { + processClassifier(it) + } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index dfd4f14b8c2..daccb8ab80f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.scopes.* +import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -74,6 +75,12 @@ fun FirClassSymbol<*>.unsubstitutedScope(context: CheckerContext): FirTypeScope memberRequiredPhase = FirResolvePhase.STATUS, ) +fun FirClassSymbol<*>.declaredMemberScope(context: CheckerContext): FirContainingNamesAwareScope = + this.declaredMemberScope( + context.sessionHolder.session, + memberRequiredPhase = FirResolvePhase.STATUS, + ) + fun FirTypeRef.toClassLikeSymbol(session: FirSession): FirClassLikeSymbol<*>? { return coneTypeSafe()?.toSymbol(session) } @@ -302,10 +309,15 @@ fun FirCallableDeclaration.isVisibleInClass(parentClass: FirClass): Boolean { return symbol.isVisibleInClass(parentClass.symbol) } -fun FirCallableSymbol<*>.isVisibleInClass(parentClassSymbol: FirClassSymbol<*>): Boolean { +fun FirBasedSymbol<*>.isVisibleInClass(parentClassSymbol: FirClassSymbol<*>): Boolean { val classPackage = parentClassSymbol.classId.packageFqName + val (visibility, packageName) = when (this) { + is FirCallableSymbol<*> -> visibility to callableId.packageName + is FirClassLikeSymbol<*> -> visibility to classId.packageFqName + else -> return true + } if (visibility == Visibilities.Private || - !visibility.visibleFromPackage(classPackage, callableId.packageName) + !visibility.visibleFromPackage(classPackage, packageName) ) return false if ( visibility == Visibilities.Internal && diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt index 8fcfc5ac923..df597748731 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt @@ -86,6 +86,10 @@ internal object FirRedeclarationPresenter { fun represent(it: FirVariableSymbol<*>) = buildString { appendRepresentationBeforeCallableId(it) appendRepresentation(it.callableId) + + if (it is FirFieldSymbol) { + append("#f") + } } fun represent(it: FirTypeAliasSymbol) = representClassLike(it) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt index fa149de3e46..7b99ae85c58 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt @@ -18,9 +18,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope import org.jetbrains.kotlin.fir.scopes.impl.PACKAGE_MEMBER import org.jetbrains.kotlin.fir.scopes.impl.typeAliasForConstructor import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.utils.SmartSet @@ -30,7 +28,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { is FirFile -> { val inspector = FirDeclarationCollector>(context) checkFile(declaration, inspector, context) - reportConflicts(reporter, context, inspector.declarationConflictingSymbols) + reportConflicts(reporter, context, inspector.declarationConflictingSymbols, declaration) } is FirRegularClass -> { if (declaration.source?.kind !is KtFakeSourceElementKind) { @@ -38,7 +36,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { } val inspector = FirDeclarationCollector>(context) inspector.collectClassMembers(declaration.symbol) - reportConflicts(reporter, context, inspector.declarationConflictingSymbols) + reportConflicts(reporter, context, inspector.declarationConflictingSymbols, declaration) } else -> { if (declaration.source?.kind !is KtFakeSourceElementKind && declaration is FirTypeParameterRefsOwner) { @@ -55,16 +53,24 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { reporter: DiagnosticReporter, context: CheckerContext, declarationConflictingSymbols: Map, SmartSet>>, + container: FirDeclaration, ) { declarationConflictingSymbols.forEach { (conflictingDeclaration, symbols) -> val typeAliasForConstructorSource = (conflictingDeclaration as? FirConstructorSymbol)?.typeAliasForConstructor?.source - val source = typeAliasForConstructorSource ?: conflictingDeclaration.source + val origin = conflictingDeclaration.origin + val source = when { + conflictingDeclaration !is FirCallableSymbol<*> -> conflictingDeclaration.source + origin == FirDeclarationOrigin.Source -> conflictingDeclaration.source + origin == FirDeclarationOrigin.Library -> return@forEach + origin == FirDeclarationOrigin.Synthetic.TypeAliasConstructor -> typeAliasForConstructorSource + else -> container.source + } if ( symbols.isEmpty() || - // For every implicit constructor there is a parent, + // For every primary constructor there is a parent, // FirRegularClass declaration, and those clash too, // resulting in REDECLARATION. - conflictingDeclaration.isImplicitConstructor && symbols.all { it.isImplicitConstructor } + conflictingDeclaration.isPrimaryConstructor && symbols.all { it.isPrimaryConstructor } ) return@forEach val factory = @@ -83,7 +89,8 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { } } - private val FirBasedSymbol<*>.isImplicitConstructor get() = source?.kind is KtFakeSourceElementKind.ImplicitConstructor + private val FirBasedSymbol<*>.isPrimaryConstructor: Boolean + get() = this is FirConstructorSymbol && isPrimary || origin == FirDeclarationOrigin.Synthetic.TypeAliasConstructor private fun checkFile(file: FirFile, inspector: FirDeclarationCollector>, context: CheckerContext) { val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt index 33f0ec41dd1..58060511d98 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirContainingNamesAwareScope.kt @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.fir.scopes -import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.name.Name abstract class FirContainingNamesAwareScope : FirScope() { @@ -35,6 +33,56 @@ fun FirContainingNamesAwareScope.processAllCallables(processor: (FirCallableSymb } } +fun FirContainingNamesAwareScope.processAllClassifiers(processor: (FirClassifierSymbol<*>) -> Unit) { + for (name in getClassifierNames()) { + processClassifiersByName(name, processor) + } +} + +inline fun > collectLeafCallablesByName( + name: Name, + processCallablesByName: (Name, (T) -> Unit) -> Unit, + crossinline processDirectlyOverriddenCallables: (T, (T) -> ProcessorAction) -> Unit, +): List { + val collected = mutableSetOf() + val bases = mutableSetOf() + + processCallablesByName(name) { function -> + processDirectlyOverriddenCallables(function) { + bases.add(it) + ProcessorAction.NEXT + } + + if (function !in bases) { + collected.add(function) + } + } + + return collected.filter { it !in bases } +} + +fun FirTypeScope.collectLeafFunctionsByName(name: Name): List = + collectLeafCallablesByName(name, ::processFunctionsByName, ::processDirectlyOverriddenFunctions) + +fun FirTypeScope.collectLeafPropertiesByName(name: Name): List> = + collectLeafCallablesByName(name, ::processPropertiesByName) { variable, process -> + if (variable is FirPropertySymbol) { + processDirectlyOverriddenProperties(variable, process) + } + } + +fun FirTypeScope.collectLeafFunctions(): List = buildList { + for (name in getCallableNames()) { + this += collectLeafFunctionsByName(name) + } +} + +fun FirTypeScope.collectLeafProperties(): List> = buildList { + for (name in getCallableNames()) { + this += collectLeafPropertiesByName(name) + } +} + fun FirContainingNamesAwareScope.collectAllProperties(): Collection> { return mutableListOf>().apply { processAllProperties(this::add) diff --git a/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.fir.kt b/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.fir.kt new file mode 100644 index 00000000000..39eedb05912 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.fir.kt @@ -0,0 +1,55 @@ +open class Final { + fun foo() {} + val bar: Int = 0 + var qux: Int = 0 +} + +open class Derived : Final() + +interface IFoo { + fun foo() +} + +class CFoo : IFoo { + override fun foo() {} +} + +interface IBar { + val bar: Int +} + +class CBar : IBar { + override val bar: Int get() = 0 +} + +interface IQux { + val qux: Int +} + +class CQux : IQux { + override val qux: Int get() = 0 +} + +interface IBarT { + val bar: T +} + +class CBarT : IBarT { + override val bar: T get() = null!! +} + +class Test1 : Final(), IFoo by CFoo() + +class Test2 : Final(), IBar by CBar() + +class Test3 : Final(), IQux by CQux() + +class Test4 : Derived(), IFoo by CFoo() + +class Test5 : Derived(), IBar by CBar() + +class Test6 : Derived(), IQux by CQux() + +class Test7 : Final(), IBarT by CBarT() + +class Test8 : Final(), IBarT by CBar() diff --git a/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.kt b/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.kt index 36416cea52c..5a99e5f74f4 100644 --- a/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.kt +++ b/compiler/testData/diagnostics/tests/delegation/clashes/finalMemberOverridden.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL open class Final { fun foo() {} val bar: Int = 0 diff --git a/compiler/testData/diagnostics/tests/redeclarations/EnumName.fir.kt b/compiler/testData/diagnostics/tests/redeclarations/EnumName.fir.kt index 9aa96f3064e..646f2f5b8a6 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/EnumName.fir.kt +++ b/compiler/testData/diagnostics/tests/redeclarations/EnumName.fir.kt @@ -1,3 +1,5 @@ -enum class A { - name +enum class A { + name, + ordinal, + entries, } diff --git a/compiler/testData/diagnostics/tests/redeclarations/EnumName.kt b/compiler/testData/diagnostics/tests/redeclarations/EnumName.kt index b0e491b10ca..b2e5b23817d 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/EnumName.kt +++ b/compiler/testData/diagnostics/tests/redeclarations/EnumName.kt @@ -1,3 +1,5 @@ enum class A { - name + name, + ordinal, + entries, } diff --git a/compiler/testData/diagnostics/tests/redeclarations/EnumName.txt b/compiler/testData/diagnostics/tests/redeclarations/EnumName.txt index 3cd84a9102b..21f54b75921 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/EnumName.txt +++ b/compiler/testData/diagnostics/tests/redeclarations/EnumName.txt @@ -3,6 +3,10 @@ package public final enum class A : kotlin.Enum { enum entry name + enum entry ordinal + + enum entry entries + private constructor A() @kotlin.internal.IntrinsicConstEvaluation public final override /*1*/ /*fake_override*/ val name: kotlin.String public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int diff --git a/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt b/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt deleted file mode 100644 index 70a4910d45b..00000000000 --- a/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt +++ /dev/null @@ -1,14 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY -class C(val x: Int) - -typealias CC = C - -fun CC(x: Int) = x - -class Outer { - class C(val x: Int) - - typealias CC = C - - fun CC(x: Int) = x -} diff --git a/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.kt b/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.kt index cfc7154da29..f724f711c06 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.kt +++ b/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY class C(val x: Int) diff --git a/compiler/testData/diagnostics/tests/suspendConflictingOverloads.fir.kt b/compiler/testData/diagnostics/tests/suspendConflictingOverloads.fir.kt deleted file mode 100644 index cf576941654..00000000000 --- a/compiler/testData/diagnostics/tests/suspendConflictingOverloads.fir.kt +++ /dev/null @@ -1,14 +0,0 @@ -// ISSUE: KT-57100 -// WITH_STDLIB - -interface C07I01{ - fun some() {} -} - -interface C07I02{ - suspend fun some() {} -} - -class C07C01: C07I01, C07I02 { - override fun some() {} -} diff --git a/compiler/testData/diagnostics/tests/suspendConflictingOverloads.kt b/compiler/testData/diagnostics/tests/suspendConflictingOverloads.kt index fcbad256706..8167db43658 100644 --- a/compiler/testData/diagnostics/tests/suspendConflictingOverloads.kt +++ b/compiler/testData/diagnostics/tests/suspendConflictingOverloads.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // ISSUE: KT-57100 // WITH_STDLIB @@ -10,5 +11,5 @@ interface C07I02{ } class C07C01: C07I01, C07I02 { - override fun some() {} + override fun some() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt deleted file mode 100644 index 9872eaf8f64..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.fir.kt +++ /dev/null @@ -1,6 +0,0 @@ -interface AsyncVal { suspend fun getVal(): Int = 1} -interface SyncVal { fun getVal(): Int = 1 } - -class MixSuspend : AsyncVal, SyncVal { - -} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.kt index 09b234d6b86..ef8236f4800 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/mixingSuspendability.kt @@ -1,6 +1,7 @@ +// FIR_IDENTICAL interface AsyncVal { suspend fun getVal(): Int = 1} interface SyncVal { fun getVal(): Int = 1 } -class MixSuspend : AsyncVal, SyncVal { +class MixSuspend : AsyncVal, SyncVal { } diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.fir.kt deleted file mode 100644 index a830cbed5f3..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.fir.kt +++ /dev/null @@ -1,37 +0,0 @@ -// FILE: main.kt -interface A { - suspend fun foo() - fun bar() -} - -interface B : A { - override fun foo() { - - } - - override suspend fun bar() { - - } -} - -interface C : A { - suspend override fun foo() { - - } - - override fun bar() { - - } -} - -class D : J { - suspend override fun foo() { - - } -} - -// FILE: J.java - -public interface J extends A { - Object foo(kotlin.coroutines.Continuation y); -} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt index fe6b33661c9..e9b8f971f93 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: main.kt interface A { suspend fun foo() @@ -5,11 +6,11 @@ interface A { } interface B : A { - override fun foo() { + override fun foo() { } - override suspend fun bar() { + override suspend fun bar() { } } diff --git a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/GetterGenerator.kt b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/GetterGenerator.kt index ccfee16af49..47ea44a5a78 100644 --- a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/GetterGenerator.kt +++ b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/GetterGenerator.kt @@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.java.declarations.FirJavaField import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.scopes.collectAllFunctions +import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol @@ -37,26 +39,30 @@ class GetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(s private val lombokService: LombokService get() = session.lombokService - private val cache: FirCache, Map?, Nothing?> = - session.firCachesFactory.createCache(::createGetters) + private val cache: FirCache, FirClassDeclaredMemberScope?>, Map?, Nothing?> = + session.firCachesFactory.createCache(uncurry(::createGetters)) override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set { if (!classSymbol.isSuitableJavaClass()) return emptySet() - return cache.getValue(classSymbol)?.keys ?: emptySet() + return cache.getValue(classSymbol to context.declaredScope)?.keys ?: emptySet() } override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List { val owner = context?.owner if (owner == null || !owner.isSuitableJavaClass()) return emptyList() - val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList() + val getter = cache.getValue(owner to context.declaredScope)?.get(callableId.callableName) ?: return emptyList() return listOf(getter.symbol) } - private fun createGetters(classSymbol: FirClassSymbol<*>): Map? { + private fun createGetters(classSymbol: FirClassSymbol<*>, declaredScope: FirClassDeclaredMemberScope?): Map? { val fieldsWithGetter = computeFieldsWithGetter(classSymbol) ?: return null val globalAccessors = lombokService.getAccessors(classSymbol) + val explicitlyDeclaredFunctions = declaredScope?.collectAllFunctions()?.associateBy { it.name }.orEmpty() return fieldsWithGetter.mapNotNull { (field, getterInfo) -> val getterName = computeGetterName(field, getterInfo, globalAccessors) ?: return@mapNotNull null + if (explicitlyDeclaredFunctions[getterName]?.valueParameterSymbols?.isEmpty() == true) { + return@mapNotNull null + } val function = buildJavaMethod { moduleData = field.moduleData returnTypeRef = field.returnTypeRef diff --git a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/SetterGenerator.kt b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/SetterGenerator.kt index 96c7bcd93d1..5ec3cc82c52 100644 --- a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/SetterGenerator.kt +++ b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/SetterGenerator.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.scopes.collectAllFunctions +import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol @@ -40,18 +42,18 @@ class SetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(s private val lombokService: LombokService get() = session.lombokService - private val cache: FirCache, Map?, Nothing?> = - session.firCachesFactory.createCache(::createSetters) + private val cache: FirCache, FirClassDeclaredMemberScope?>, Map?, Nothing?> = + session.firCachesFactory.createCache(uncurry(::createSetters)) override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set { if (!classSymbol.isSuitableForSetters()) return emptySet() - return cache.getValue(classSymbol)?.keys ?: emptySet() + return cache.getValue(classSymbol to context.declaredScope)?.keys ?: emptySet() } override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List { val owner = context?.owner if (owner == null || !owner.isSuitableForSetters()) return emptyList() - val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList() + val getter = cache.getValue(owner to context.declaredScope)?.get(callableId.callableName) ?: return emptyList() return listOf(getter.symbol) } @@ -59,12 +61,17 @@ class SetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(s return isSuitableJavaClass() && classKind != ClassKind.ENUM_CLASS } - private fun createSetters(classSymbol: FirClassSymbol<*>): Map? { + private fun createSetters(classSymbol: FirClassSymbol<*>, declaredScope: FirClassDeclaredMemberScope?): Map? { val fieldsWithSetter = computeFieldsWithSetters(classSymbol) ?: return null val globalAccessors = lombokService.getAccessors(classSymbol) + val explicitlyDeclaredFunctions = declaredScope?.collectAllFunctions()?.associateBy { it.name }.orEmpty() return fieldsWithSetter.mapNotNull { (field, setterInfo) -> val accessors = lombokService.getAccessorsIfAnnotated(field.symbol) ?: globalAccessors val setterName = computeSetterName(field, setterInfo, accessors) ?: return@mapNotNull null + val existing = explicitlyDeclaredFunctions[setterName] + if (existing != null && existing.valueParameterSymbols.size == 1) { + return@mapNotNull null + } val function = buildJavaMethod { moduleData = field.moduleData returnTypeRef = if (accessors.chain) { diff --git a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/utils.kt b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/utils.kt index bfc4e3044c7..a7fed7d34a8 100644 --- a/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/utils.kt +++ b/plugins/lombok/lombok.k2/src/org/jetbrains/kotlin/lombok/k2/generators/utils.kt @@ -81,3 +81,5 @@ private fun sameSignature(a: FirFunction, b: FirFunction): Boolean { bVararg && aSize >= (bSize - 1) || aSize == bSize } + +internal inline fun uncurry(crossinline f: (A, B) -> C): (Pair) -> C = { (a, b) -> f(a, b) } diff --git a/plugins/lombok/testData/diagnostics/clashAccessors.fir.kt b/plugins/lombok/testData/diagnostics/clashAccessors.fir.kt index d7127a5e8a6..e15d9d844b0 100644 --- a/plugins/lombok/testData/diagnostics/clashAccessors.fir.kt +++ b/plugins/lombok/testData/diagnostics/clashAccessors.fir.kt @@ -39,6 +39,11 @@ public class ClashTest extends SuperClass { return human; } + private int score; + + public void setScore(int score, int times) { + + } static void test() { val obj = new ClashTest(); @@ -82,11 +87,14 @@ class KotlinChildClass : ClashTest() { fun test() { val obj = ClashTest() - obj.getAge() + obj.getAge() //thats shouldn't work because lombok doesn't generate clashing method - obj.setAge(41) - obj.age = 12 - val age = obj.age + obj.setAge(41) + obj.age = 12 + val age = obj.age + + obj.setScore(41) + obj.score = 12 obj.getName() diff --git a/plugins/lombok/testData/diagnostics/clashAccessors.kt b/plugins/lombok/testData/diagnostics/clashAccessors.kt index c74b622b6dd..fabf49e99ea 100644 --- a/plugins/lombok/testData/diagnostics/clashAccessors.kt +++ b/plugins/lombok/testData/diagnostics/clashAccessors.kt @@ -39,6 +39,11 @@ public class ClashTest extends SuperClass { return human; } + private int score; + + public void setScore(int score, int times) { + + } static void test() { val obj = new ClashTest(); @@ -88,6 +93,9 @@ fun test() { obj.age = 12 val age = obj.age + obj.setScore(41) + obj.score = 12 + obj.getName() obj.setName("Al") diff --git a/plugins/lombok/testData/diagnostics/clashAccessors.txt b/plugins/lombok/testData/diagnostics/clashAccessors.txt index 233155ede57..77a9143aae8 100644 --- a/plugins/lombok/testData/diagnostics/clashAccessors.txt +++ b/plugins/lombok/testData/diagnostics/clashAccessors.txt @@ -8,10 +8,12 @@ public open class ChildClass : ClashTest { invisible_fake final override /*1*/ /*fake_override*/ var age: kotlin.Int invisible_fake final override /*1*/ /*fake_override*/ var human: kotlin.Boolean invisible_fake final override /*1*/ /*fake_override*/ var name: kotlin.String! + invisible_fake final override /*1*/ /*fake_override*/ var score: kotlin.Int invisible_fake final override /*1*/ /*fake_override*/ var toOverride: kotlin.Int! public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun getAge(): kotlin.Int public open override /*1*/ /*fake_override*/ fun getName(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getScore(): kotlin.Int @java.lang.Override public open override /*1*/ fun getToOverride(): kotlin.Int! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun isHuman(): kotlin.Boolean @@ -19,6 +21,8 @@ public open class ChildClass : ClashTest { public open override /*1*/ /*fake_override*/ fun setAge(/*0*/ age: kotlin.String!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setHuman(/*0*/ human: kotlin.Boolean): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setName(/*0*/ name: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setScore(/*0*/ score: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setScore(/*0*/ score: kotlin.Int, /*1*/ times: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setToOverride(/*0*/ toOverride: kotlin.Int!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String @@ -31,10 +35,12 @@ public open class ChildClass : ClashTest { private final var age: kotlin.Int private final var human: kotlin.Boolean private final var name: kotlin.String! + private final var score: kotlin.Int private final var toOverride: kotlin.Int! public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open fun getAge(): kotlin.Int public open /*synthesized*/ fun getName(): kotlin.String! + public open /*synthesized*/ fun getScore(): kotlin.Int public open /*synthesized*/ fun getToOverride(): kotlin.Int! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open /*synthesized*/ fun isHuman(): kotlin.Boolean @@ -42,6 +48,8 @@ public open class ChildClass : ClashTest { public open fun setAge(/*0*/ age: kotlin.String!): kotlin.Unit public open /*synthesized*/ fun setHuman(/*0*/ human: kotlin.Boolean): kotlin.Unit public open override /*1*/ /*synthesized*/ fun setName(/*0*/ name: kotlin.String!): kotlin.Unit + public open /*synthesized*/ fun setScore(/*0*/ score: kotlin.Int): kotlin.Unit + public open fun setScore(/*0*/ score: kotlin.Int, /*1*/ times: kotlin.Int): kotlin.Unit public open /*synthesized*/ fun setToOverride(/*0*/ toOverride: kotlin.Int!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String @@ -54,10 +62,12 @@ public final class KotlinChildClass : ClashTest { invisible_fake final override /*1*/ /*fake_override*/ var age: kotlin.Int invisible_fake final override /*1*/ /*fake_override*/ var human: kotlin.Boolean invisible_fake final override /*1*/ /*fake_override*/ var name: kotlin.String! + invisible_fake final override /*1*/ /*fake_override*/ var score: kotlin.Int invisible_fake final override /*1*/ /*fake_override*/ var toOverride: kotlin.Int! public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun getAge(): kotlin.Int public open override /*1*/ /*fake_override*/ fun getName(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getScore(): kotlin.Int public open override /*1*/ fun getToOverride(): kotlin.Int? public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun isHuman(): kotlin.Boolean @@ -65,6 +75,8 @@ public final class KotlinChildClass : ClashTest { public open override /*1*/ /*fake_override*/ fun setAge(/*0*/ age: kotlin.String!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setHuman(/*0*/ human: kotlin.Boolean): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setName(/*0*/ name: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setScore(/*0*/ score: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setScore(/*0*/ score: kotlin.Int, /*1*/ times: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setToOverride(/*0*/ toOverride: kotlin.Int!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -76,3 +88,4 @@ public open class SuperClass { public open fun setName(/*0*/ name: kotlin.String!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +