[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");
|
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")
|
@TestMetadata("innerClassHierarchy.kt")
|
||||||
public void testInnerClassHierarchy() throws Exception {
|
public void testInnerClassHierarchy() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/innerClassHierarchy.kt");
|
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");
|
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")
|
@TestMetadata("innerClassHierarchy.kt")
|
||||||
public void testInnerClassHierarchy() throws Exception {
|
public void testInnerClassHierarchy() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/innerClassHierarchy.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/problems/innerClassHierarchy.kt");
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ internal fun FirProperty.generateOverriddenAccessorSymbols(
|
|||||||
scope.processPropertiesByName(name) {}
|
scope.processPropertiesByName(name) {}
|
||||||
val overriddenSet = mutableSetOf<IrSimpleFunctionSymbol>()
|
val overriddenSet = mutableSetOf<IrSimpleFunctionSymbol>()
|
||||||
scope.processDirectlyOverriddenProperties(symbol) {
|
scope.processDirectlyOverriddenProperties(symbol) {
|
||||||
if (it.fir.visibility == Visibilities.Private) {
|
if (it is FirAccessorSymbol || it.fir.visibility == Visibilities.Private) {
|
||||||
return@processDirectlyOverriddenProperties ProcessorAction.NEXT
|
return@processDirectlyOverriddenProperties ProcessorAction.NEXT
|
||||||
}
|
}
|
||||||
val overriddenProperty = declarationStorage.getIrPropertySymbol(it.unwrapSubstitutionOverrides()) as IrPropertySymbol
|
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.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
|
import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
|
||||||
import org.jetbrains.kotlin.fir.declarations.builder.FirValueParameterBuilder
|
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.declarations.synthetic.buildSyntheticProperty
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirJavaSyntheticNamesProvider
|
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.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.getContainingCallableNamesIfPresent
|
import org.jetbrains.kotlin.fir.scopes.getContainingCallableNamesIfPresent
|
||||||
@@ -58,7 +60,6 @@ class JavaClassUseSiteMemberScope(
|
|||||||
private fun generateAccessorSymbol(
|
private fun generateAccessorSymbol(
|
||||||
functionSymbol: FirFunctionSymbol<*>,
|
functionSymbol: FirFunctionSymbol<*>,
|
||||||
syntheticPropertyName: Name,
|
syntheticPropertyName: Name,
|
||||||
overrideCandidates: MutableSet<FirCallableSymbol<*>>,
|
|
||||||
isGetter: Boolean
|
isGetter: Boolean
|
||||||
): FirAccessorSymbol? {
|
): FirAccessorSymbol? {
|
||||||
if (functionSymbol !is FirNamedFunctionSymbol) {
|
if (functionSymbol !is FirNamedFunctionSymbol) {
|
||||||
@@ -76,7 +77,6 @@ class JavaClassUseSiteMemberScope(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
overrideCandidates += functionSymbol
|
|
||||||
return buildSyntheticProperty {
|
return buildSyntheticProperty {
|
||||||
session = this@JavaClassUseSiteMemberScope.session
|
session = this@JavaClassUseSiteMemberScope.session
|
||||||
name = syntheticPropertyName
|
name = syntheticPropertyName
|
||||||
@@ -105,7 +105,7 @@ class JavaClassUseSiteMemberScope(
|
|||||||
for (getterName in getterNames) {
|
for (getterName in getterNames) {
|
||||||
declaredMemberScope.processFunctionsByName(getterName) { functionSymbol ->
|
declaredMemberScope.processFunctionsByName(getterName) { functionSymbol ->
|
||||||
val accessorSymbol = generateAccessorSymbol(
|
val accessorSymbol = generateAccessorSymbol(
|
||||||
functionSymbol, propertyName, overrideCandidates, isGetter = true
|
functionSymbol, propertyName, isGetter = true
|
||||||
)
|
)
|
||||||
if (accessorSymbol != null) {
|
if (accessorSymbol != null) {
|
||||||
// NB: accessor should not be processed directly unless we find matching property symbol in supertype
|
// 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)
|
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 {
|
companion object {
|
||||||
private const val SETTER_PREFIX = "set"
|
private const val SETTER_PREFIX = "set"
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-3
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeFirstWord
|
|||||||
@NoMutableState
|
@NoMutableState
|
||||||
object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
||||||
private const val GETTER_PREFIX = "get"
|
private const val GETTER_PREFIX = "get"
|
||||||
|
private const val SETTER_PREFIX = "set"
|
||||||
private const val IS_PREFIX = "is"
|
private const val IS_PREFIX = "is"
|
||||||
|
|
||||||
override fun possibleGetterNamesByPropertyName(name: Name): List<Name> {
|
override fun possibleGetterNamesByPropertyName(name: Name): List<Name> {
|
||||||
@@ -34,11 +35,23 @@ object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
|||||||
override fun setterNameByGetterName(name: Name): Name {
|
override fun setterNameByGetterName(name: Name): Name {
|
||||||
val identifier = name.identifier
|
val identifier = name.identifier
|
||||||
val prefix = when {
|
val prefix = when {
|
||||||
identifier.startsWith("get") -> "get"
|
identifier.startsWith(GETTER_PREFIX) -> GETTER_PREFIX
|
||||||
identifier.startsWith("is") -> "is"
|
identifier.startsWith(IS_PREFIX) -> IS_PREFIX
|
||||||
else -> throw IllegalArgumentException()
|
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 class FirSyntheticNamesProvider : FirSessionComponent {
|
||||||
abstract fun possibleGetterNamesByPropertyName(name: Name): List<Name>
|
abstract fun possibleGetterNamesByPropertyName(name: Name): List<Name>
|
||||||
abstract fun setterNameByGetterName(name: Name): Name
|
abstract fun setterNameByGetterName(name: Name): Name
|
||||||
|
abstract fun propertyNameByAccessorName(name: Name): Name?
|
||||||
}
|
}
|
||||||
|
|
||||||
val FirSession.syntheticNamesProvider: FirSyntheticNamesProvider by FirSession.sessionComponentAccessor()
|
val FirSession.syntheticNamesProvider: FirSyntheticNamesProvider by FirSession.sessionComponentAccessor()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|||||||
Reference in New Issue
Block a user