[FIR Java] Hide function in scope in case it's an accessor by fact

#KT-42116 Fixed
This commit is contained in:
Mikhail Glukhikh
2020-09-24 12:01:04 +03:00
parent 70095712eb
commit fe8e3e99ab
10 changed files with 116 additions and 9 deletions
@@ -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
}
@@ -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>#()
}
@@ -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");
@@ -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
@@ -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"
}
@@ -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())
}
}
@@ -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