[FIR] Check conflicting overloads via scopes
Scopes may return private symbols from supertypes, they should not clash with symbols from the current class. For example, see: `FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated.FakeOverride#testPrivateFakeOverrides1` Lombok shouldn't generate functions if the user has defined explicit ones. In K1 generated functions are not really added to the declared members scope. ^KT-61243 Fixed
This commit is contained in:
committed by
Space Team
parent
973248f432
commit
4e58715760
+61
-22
@@ -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<D : FirBasedSymbol<*>>(
|
||||
fun FirDeclarationCollector<FirBasedSymbol<*>>.collectClassMembers(klass: FirRegularClassSymbol) {
|
||||
val otherDeclarations = mutableMapOf<String, MutableList<FirBasedSymbol<*>>>()
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirBasedSymbol<*>>>()
|
||||
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<FirVariableSymbol<*>>()
|
||||
|
||||
// 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<FirClassifierSymbol<*>>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ConeClassLikeType>()?.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 &&
|
||||
|
||||
+4
@@ -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)
|
||||
|
||||
+16
-9
@@ -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<FirBasedSymbol<*>>(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<FirBasedSymbol<*>>(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<FirBasedSymbol<*>, SmartSet<FirBasedSymbol<*>>>,
|
||||
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<FirBasedSymbol<*>>, context: CheckerContext) {
|
||||
val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
|
||||
|
||||
+51
-3
@@ -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 <reified T : FirCallableSymbol<*>> collectLeafCallablesByName(
|
||||
name: Name,
|
||||
processCallablesByName: (Name, (T) -> Unit) -> Unit,
|
||||
crossinline processDirectlyOverriddenCallables: (T, (T) -> ProcessorAction) -> Unit,
|
||||
): List<T> {
|
||||
val collected = mutableSetOf<T>()
|
||||
val bases = mutableSetOf<T>()
|
||||
|
||||
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<FirNamedFunctionSymbol> =
|
||||
collectLeafCallablesByName(name, ::processFunctionsByName, ::processDirectlyOverriddenFunctions)
|
||||
|
||||
fun FirTypeScope.collectLeafPropertiesByName(name: Name): List<FirVariableSymbol<*>> =
|
||||
collectLeafCallablesByName(name, ::processPropertiesByName) { variable, process ->
|
||||
if (variable is FirPropertySymbol) {
|
||||
processDirectlyOverriddenProperties(variable, process)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeScope.collectLeafFunctions(): List<FirNamedFunctionSymbol> = buildList {
|
||||
for (name in getCallableNames()) {
|
||||
this += collectLeafFunctionsByName(name)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirTypeScope.collectLeafProperties(): List<FirVariableSymbol<*>> = buildList {
|
||||
for (name in getCallableNames()) {
|
||||
this += collectLeafPropertiesByName(name)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirContainingNamesAwareScope.collectAllProperties(): Collection<FirVariableSymbol<*>> {
|
||||
return mutableListOf<FirVariableSymbol<*>>().apply {
|
||||
processAllProperties(this::add)
|
||||
|
||||
+55
@@ -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<T> {
|
||||
val bar: T
|
||||
}
|
||||
|
||||
class CBarT<T> : IBarT<T> {
|
||||
override val bar: T get() = null!!
|
||||
}
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class <!CONFLICTING_OVERLOADS, CONFLICTING_OVERLOADS!>Test1<!><!> : Final(), IFoo by CFoo()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class <!REDECLARATION, REDECLARATION!>Test2<!><!> : Final(), IBar by CBar()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION, VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION!>class <!REDECLARATION, REDECLARATION!>Test3<!><!> : Final(), IQux by CQux()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class <!CONFLICTING_OVERLOADS, CONFLICTING_OVERLOADS!>Test4<!><!> : Derived(), IFoo by CFoo()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class <!REDECLARATION, REDECLARATION!>Test5<!><!> : Derived(), IBar by CBar()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION, VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION!>class <!REDECLARATION, REDECLARATION!>Test6<!><!> : Derived(), IQux by CQux()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class <!REDECLARATION, REDECLARATION!>Test7<!><!> : Final(), IBarT<Int> by CBarT<Int>()
|
||||
|
||||
<!OVERRIDING_FINAL_MEMBER_BY_DELEGATION!>class <!REDECLARATION, REDECLARATION!>Test8<!><!> : Final(), IBarT<Int> by <!TYPE_MISMATCH!>CBar()<!>
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
open class Final {
|
||||
fun foo() {}
|
||||
val bar: Int = 0
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
enum class A {
|
||||
name
|
||||
enum class <!REDECLARATION, REDECLARATION!>A<!> {
|
||||
<!REDECLARATION!>name<!>,
|
||||
<!REDECLARATION!>ordinal<!>,
|
||||
<!DEPRECATED_DECLARATION_OF_ENUM_ENTRY!>entries,<!>
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
enum class A {
|
||||
<!REDECLARATION!>name<!>
|
||||
<!REDECLARATION!>name<!>,
|
||||
<!REDECLARATION!>ordinal<!>,
|
||||
<!DEPRECATED_DECLARATION_OF_ENUM_ENTRY!>entries,<!>
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ package
|
||||
public final enum class A : kotlin.Enum<A> {
|
||||
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
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY
|
||||
class C(val x: Int)
|
||||
|
||||
<!CONFLICTING_OVERLOADS!>typealias CC = C<!>
|
||||
|
||||
<!CONFLICTING_OVERLOADS!>fun CC(x: Int)<!> = x
|
||||
|
||||
class Outer {
|
||||
class C(val x: Int)
|
||||
|
||||
typealias CC = C
|
||||
|
||||
fun CC(x: Int) = x
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY
|
||||
class C(val x: Int)
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// ISSUE: KT-57100
|
||||
// WITH_STDLIB
|
||||
|
||||
@@ -10,5 +11,5 @@ interface C07I02{
|
||||
}
|
||||
|
||||
class C07C01: C07I01, C07I02 {
|
||||
<!CONFLICTING_OVERLOADS!>override fun some()<!> {}
|
||||
override fun some() {}
|
||||
}
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
interface AsyncVal { suspend fun getVal(): Int = 1}
|
||||
interface SyncVal { fun getVal(): Int = 1 }
|
||||
|
||||
<!CONFLICTING_INHERITED_MEMBERS, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class MixSuspend<!> : AsyncVal, SyncVal {
|
||||
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
// FIR_IDENTICAL
|
||||
interface AsyncVal { suspend fun getVal(): Int = 1}
|
||||
interface SyncVal { fun getVal(): Int = 1 }
|
||||
|
||||
<!CONFLICTING_INHERITED_MEMBERS!>class MixSuspend<!> : AsyncVal, SyncVal {
|
||||
<!CONFLICTING_INHERITED_MEMBERS, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class MixSuspend<!> : AsyncVal, SyncVal {
|
||||
|
||||
}
|
||||
|
||||
-37
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class D<!> : J {
|
||||
suspend override fun foo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
public interface J extends A {
|
||||
Object foo(kotlin.coroutines.Continuation<kotlin.Unit> y);
|
||||
}
|
||||
+3
-2
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: main.kt
|
||||
interface A {
|
||||
suspend fun foo()
|
||||
@@ -5,11 +6,11 @@ interface A {
|
||||
}
|
||||
|
||||
interface B : A {
|
||||
<!CONFLICTING_OVERLOADS!><!NOTHING_TO_OVERRIDE!>override<!> fun foo()<!> {
|
||||
override fun foo() {
|
||||
|
||||
}
|
||||
|
||||
<!CONFLICTING_OVERLOADS!><!NOTHING_TO_OVERRIDE!>override<!> suspend fun bar()<!> {
|
||||
override suspend fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -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<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(::createGetters)
|
||||
private val cache: FirCache<Pair<FirClassSymbol<*>, FirClassDeclaredMemberScope?>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(uncurry(::createGetters))
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set<Name> {
|
||||
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<FirNamedFunctionSymbol> {
|
||||
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<Name, FirJavaMethod>? {
|
||||
private fun createGetters(classSymbol: FirClassSymbol<*>, declaredScope: FirClassDeclaredMemberScope?): Map<Name, FirJavaMethod>? {
|
||||
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
|
||||
|
||||
+12
-5
@@ -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<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(::createSetters)
|
||||
private val cache: FirCache<Pair<FirClassSymbol<*>, FirClassDeclaredMemberScope?>, Map<Name, FirJavaMethod>?, Nothing?> =
|
||||
session.firCachesFactory.createCache(uncurry(::createSetters))
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set<Name> {
|
||||
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<FirNamedFunctionSymbol> {
|
||||
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<Name, FirJavaMethod>? {
|
||||
private fun createSetters(classSymbol: FirClassSymbol<*>, declaredScope: FirClassDeclaredMemberScope?): Map<Name, FirJavaMethod>? {
|
||||
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) {
|
||||
|
||||
@@ -81,3 +81,5 @@ private fun sameSignature(a: FirFunction, b: FirFunction): Boolean {
|
||||
bVararg && aSize >= (bSize - 1) ||
|
||||
aSize == bSize
|
||||
}
|
||||
|
||||
internal inline fun <A, B, C> uncurry(crossinline f: (A, B) -> C): (Pair<A, B>) -> C = { (a, b) -> f(a, b) }
|
||||
|
||||
+12
-4
@@ -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.<!OVERLOAD_RESOLUTION_AMBIGUITY!>getAge<!>()
|
||||
obj.getAge()
|
||||
//thats shouldn't work because lombok doesn't generate clashing method
|
||||
obj.setAge(41)
|
||||
obj.<!OVERLOAD_RESOLUTION_AMBIGUITY!>age<!> = 12
|
||||
val age = obj.<!OVERLOAD_RESOLUTION_AMBIGUITY!>age<!>
|
||||
obj.setAge(<!ARGUMENT_TYPE_MISMATCH!>41<!>)
|
||||
obj.<!VAL_REASSIGNMENT!>age<!> = 12
|
||||
val age = obj.age
|
||||
|
||||
obj.setScore(41)
|
||||
obj.score = 12
|
||||
|
||||
|
||||
obj.getName()
|
||||
|
||||
@@ -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() {
|
||||
<!VAL_REASSIGNMENT!>obj.age<!> = 12
|
||||
val age = obj.age
|
||||
|
||||
obj.setScore(41)
|
||||
obj.score = 12
|
||||
|
||||
|
||||
obj.getName()
|
||||
obj.setName("Al")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user