[FIR Java] Hide function in scope in case it's an accessor by fact
#KT-42116 Fixed
This commit is contained in:
+26
@@ -0,0 +1,26 @@
|
||||
// FILE: PropertyDescriptor.java
|
||||
|
||||
public interface PropertyDescriptor extends DescriptorWithAccessor {
|
||||
String getSetter();
|
||||
boolean isDelegated();
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
interface DescriptorWithAccessor {
|
||||
val setter: String
|
||||
val isDelegated: Boolean
|
||||
}
|
||||
|
||||
class WrappedPropertyDescriptor : PropertyDescriptor {
|
||||
override val setter: String get() = "K"
|
||||
override val isDelegated: Boolean get() = false
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val descriptor = WrappedPropertyDescriptor()
|
||||
val res1 = descriptor.setter
|
||||
val res2 = descriptor.<!UNRESOLVED_REFERENCE!>getSetter<!>() // Should be error
|
||||
val res3 = descriptor.isDelegated
|
||||
val res4 = descriptor.<!UNRESOLVED_REFERENCE!>isDelegated<!>() // Should be error
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
FILE: test.kt
|
||||
public abstract interface DescriptorWithAccessor : R|kotlin/Any| {
|
||||
public abstract val setter: R|kotlin/String|
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
public abstract val isDelegated: R|kotlin/Boolean|
|
||||
public get(): R|kotlin/Boolean|
|
||||
|
||||
}
|
||||
public final class WrappedPropertyDescriptor : R|PropertyDescriptor| {
|
||||
public constructor(): R|WrappedPropertyDescriptor| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final override val setter: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(K)
|
||||
}
|
||||
|
||||
public final override val isDelegated: R|kotlin/Boolean|
|
||||
public get(): R|kotlin/Boolean| {
|
||||
^ Boolean(false)
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval descriptor: R|WrappedPropertyDescriptor| = R|/WrappedPropertyDescriptor.WrappedPropertyDescriptor|()
|
||||
lval res1: R|kotlin/String| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.setter|
|
||||
lval res2: R|ERROR CLASS: Unresolved name: getSetter| = R|<local>/descriptor|.<Unresolved name: getSetter>#()
|
||||
lval res3: R|kotlin/Boolean| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.isDelegated|
|
||||
lval res4: R|ERROR CLASS: Unresolved name: isDelegated| = R|<local>/descriptor|.<Unresolved name: isDelegated>#()
|
||||
}
|
||||
Generated
+5
@@ -1989,6 +1989,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/flexibleTypeVarAgainstNull.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inaccessibleJavaGetter.kt")
|
||||
public void testInaccessibleJavaGetter() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerClassHierarchy.kt")
|
||||
public void testInnerClassHierarchy() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/innerClassHierarchy.kt");
|
||||
|
||||
+5
@@ -1989,6 +1989,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/flexibleTypeVarAgainstNull.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inaccessibleJavaGetter.kt")
|
||||
public void testInaccessibleJavaGetter() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerClassHierarchy.kt")
|
||||
public void testInnerClassHierarchy() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/innerClassHierarchy.kt");
|
||||
|
||||
@@ -318,7 +318,7 @@ internal fun FirProperty.generateOverriddenAccessorSymbols(
|
||||
scope.processPropertiesByName(name) {}
|
||||
val overriddenSet = mutableSetOf<IrSimpleFunctionSymbol>()
|
||||
scope.processDirectlyOverriddenProperties(symbol) {
|
||||
if (it.fir.visibility == Visibilities.Private) {
|
||||
if (it is FirAccessorSymbol || it.fir.visibility == Visibilities.Private) {
|
||||
return@processDirectlyOverriddenProperties ProcessorAction.NEXT
|
||||
}
|
||||
val overriddenProperty = declarationStorage.getIrPropertySymbol(it.unwrapSubstitutionOverrides()) as IrPropertySymbol
|
||||
|
||||
+30
-3
@@ -9,11 +9,13 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.FirValueParameterBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.FirJavaSyntheticNamesProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.syntheticNamesProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getContainingCallableNamesIfPresent
|
||||
@@ -58,7 +60,6 @@ class JavaClassUseSiteMemberScope(
|
||||
private fun generateAccessorSymbol(
|
||||
functionSymbol: FirFunctionSymbol<*>,
|
||||
syntheticPropertyName: Name,
|
||||
overrideCandidates: MutableSet<FirCallableSymbol<*>>,
|
||||
isGetter: Boolean
|
||||
): FirAccessorSymbol? {
|
||||
if (functionSymbol !is FirNamedFunctionSymbol) {
|
||||
@@ -76,7 +77,6 @@ class JavaClassUseSiteMemberScope(
|
||||
return null
|
||||
}
|
||||
}
|
||||
overrideCandidates += functionSymbol
|
||||
return buildSyntheticProperty {
|
||||
session = this@JavaClassUseSiteMemberScope.session
|
||||
name = syntheticPropertyName
|
||||
@@ -105,7 +105,7 @@ class JavaClassUseSiteMemberScope(
|
||||
for (getterName in getterNames) {
|
||||
declaredMemberScope.processFunctionsByName(getterName) { functionSymbol ->
|
||||
val accessorSymbol = generateAccessorSymbol(
|
||||
functionSymbol, propertyName, overrideCandidates, isGetter = true
|
||||
functionSymbol, propertyName, isGetter = true
|
||||
)
|
||||
if (accessorSymbol != null) {
|
||||
// NB: accessor should not be processed directly unless we find matching property symbol in supertype
|
||||
@@ -162,6 +162,33 @@ class JavaClassUseSiteMemberScope(
|
||||
return processAccessorFunctionsAndPropertiesByName(name, getterNames, processor)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) {
|
||||
if (symbol.fir !is FirJavaClass) {
|
||||
return super.processFunctionsByName(name, processor)
|
||||
}
|
||||
val potentialPropertyName = session.syntheticNamesProvider.propertyNameByAccessorName(name)
|
||||
?: return super.processFunctionsByName(name, processor)
|
||||
val accessors = mutableListOf<FirAccessorSymbol>()
|
||||
processAccessorFunctionsAndPropertiesByName(potentialPropertyName, listOf(name)) {
|
||||
if (it is FirAccessorSymbol) {
|
||||
accessors += it
|
||||
}
|
||||
}
|
||||
if (accessors.isEmpty()) {
|
||||
return super.processFunctionsByName(name, processor)
|
||||
}
|
||||
super.processFunctionsByName(name) { functionSymbol ->
|
||||
if (accessors.none { accessorSymbol ->
|
||||
val syntheticProperty = accessorSymbol.fir as FirSyntheticProperty
|
||||
syntheticProperty.getter.delegate === functionSymbol.fir ||
|
||||
syntheticProperty.setter?.delegate === functionSymbol.fir
|
||||
}
|
||||
) {
|
||||
processor(functionSymbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SETTER_PREFIX = "set"
|
||||
}
|
||||
|
||||
+16
-3
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeFirstWord
|
||||
@NoMutableState
|
||||
object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
||||
private const val GETTER_PREFIX = "get"
|
||||
private const val SETTER_PREFIX = "set"
|
||||
private const val IS_PREFIX = "is"
|
||||
|
||||
override fun possibleGetterNamesByPropertyName(name: Name): List<Name> {
|
||||
@@ -34,11 +35,23 @@ object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
||||
override fun setterNameByGetterName(name: Name): Name {
|
||||
val identifier = name.identifier
|
||||
val prefix = when {
|
||||
identifier.startsWith("get") -> "get"
|
||||
identifier.startsWith("is") -> "is"
|
||||
identifier.startsWith(GETTER_PREFIX) -> GETTER_PREFIX
|
||||
identifier.startsWith(IS_PREFIX) -> IS_PREFIX
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
return Name.identifier("set" + identifier.removePrefix(prefix))
|
||||
return Name.identifier(SETTER_PREFIX + identifier.removePrefix(prefix))
|
||||
}
|
||||
|
||||
override fun propertyNameByAccessorName(name: Name): Name? {
|
||||
if (name.isSpecial) return null
|
||||
val identifier = name.identifier
|
||||
val prefix = when {
|
||||
identifier.startsWith(GETTER_PREFIX) -> GETTER_PREFIX
|
||||
identifier.startsWith(IS_PREFIX) -> ""
|
||||
identifier.startsWith(SETTER_PREFIX) -> SETTER_PREFIX
|
||||
else -> return null
|
||||
}
|
||||
return Name.identifier(identifier.removePrefix(prefix).decapitalize())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
abstract class FirSyntheticNamesProvider : FirSessionComponent {
|
||||
abstract fun possibleGetterNamesByPropertyName(name: Name): List<Name>
|
||||
abstract fun setterNameByGetterName(name: Name): Name
|
||||
abstract fun propertyNameByAccessorName(name: Name): Name?
|
||||
}
|
||||
|
||||
val FirSession.syntheticNamesProvider: FirSyntheticNamesProvider by FirSession.sessionComponentAccessor()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
Reference in New Issue
Block a user