FIR: Fix another inconsistency with FE1.0 in synthetic properties resolution

This commit is contained in:
Denis.Zharkov
2021-10-22 14:28:58 +03:00
parent fe1b4d61c2
commit 52c2908bb7
8 changed files with 67 additions and 119 deletions
@@ -29874,6 +29874,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt"); runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt");
} }
@Test
@TestMetadata("nonAsciiSecondChar.kt")
public void testNonAsciiSecondChar() throws Exception {
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/nonAsciiSecondChar.kt");
}
@Test @Test
@TestMetadata("OnlyAscii.kt") @TestMetadata("OnlyAscii.kt")
public void testOnlyAscii() throws Exception { public void testOnlyAscii() throws Exception {
@@ -29874,6 +29874,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt"); runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt");
} }
@Test
@TestMetadata("nonAsciiSecondChar.kt")
public void testNonAsciiSecondChar() throws Exception {
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/nonAsciiSecondChar.kt");
}
@Test @Test
@TestMetadata("OnlyAscii.kt") @TestMetadata("OnlyAscii.kt")
public void testOnlyAscii() throws Exception { public void testOnlyAscii() throws Exception {
@@ -29874,6 +29874,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt"); runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt");
} }
@Test
@TestMetadata("nonAsciiSecondChar.kt")
public void testNonAsciiSecondChar() throws Exception {
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/nonAsciiSecondChar.kt");
}
@Test @Test
@TestMetadata("OnlyAscii.kt") @TestMetadata("OnlyAscii.kt")
public void testOnlyAscii() throws Exception { public void testOnlyAscii() throws Exception {
@@ -7,98 +7,14 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.NoMutableState import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticNamesProvider import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticNamesProvider
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName
import org.jetbrains.kotlin.load.java.possibleGetMethodNames
import org.jetbrains.kotlin.load.java.setMethodName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeAsciiOnly
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toUpperCaseAsciiOnly
@NoMutableState @NoMutableState
object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() { object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
private const val GETTER_PREFIX = "get" override fun possibleGetterNamesByPropertyName(name: Name): List<Name> = possibleGetMethodNames(name)
private const val SETTER_PREFIX = "set" override fun setterNameByGetterName(name: Name): Name = setMethodName(getMethodName = name)
private const val IS_PREFIX = "is" override fun possiblePropertyNamesByAccessorName(name: Name): List<Name> = getPropertyNamesCandidatesByAccessorName(name)
@Suppress("NOTHING_TO_INLINE")
private inline fun Char.isAsciiUpperCase() = this in 'A'..'Z'
@Suppress("NOTHING_TO_INLINE")
private inline fun Char.isAsciiLowerCase() = this in 'a'..'z'
override fun possibleGetterNamesByPropertyName(name: Name): List<Name> {
if (name.isSpecial) return emptyList()
val identifier = name.identifier
if (identifier.isEmpty()) return emptyList()
val firstChar = identifier[0]
if (!firstChar.isJavaIdentifierStart() || firstChar in 'A'..'Z') return emptyList()
val result = ArrayList<Name>(3)
val standardName = Name.identifier(GETTER_PREFIX + identifier.capitalizeAsciiOnly())
val length = identifier.length
if (length == 1) {
if (identifier[0].isAsciiLowerCase()) {
// 'x' --> 'getX' but not 'X' --> 'getX'
result += standardName
}
} else if (identifier[1].isAsciiLowerCase()) {
if (identifier[0].isAsciiLowerCase()) {
// 'something' --> 'getSomething' classic case
result += standardName
}
var secondWordStart = 2
while (secondWordStart < length && identifier[secondWordStart].isAsciiLowerCase()) {
secondWordStart++
}
val capitalizedFirstWordName = Name.identifier(
GETTER_PREFIX + identifier.substring(0, secondWordStart).toUpperCaseAsciiOnly() + identifier.substring(secondWordStart)
)
if (secondWordStart >= length || identifier[secondWordStart].isAsciiUpperCase()) {
// 'xyz' --> 'getXYZ' or 'xyzOfSomething' --> 'getXYZOfSomething'
result += capitalizedFirstWordName
}
} else if (length < 3 || !identifier[2].isAsciiUpperCase()) {
// 'xOfSomething' --> 'getXOfSomething' but not 'xYZ' --> 'getXYZ'
result += standardName
}
if (length > IS_PREFIX.length && identifier.startsWith(IS_PREFIX) && !identifier[IS_PREFIX.length].isAsciiLowerCase()) {
// 'isSomething' (but not 'is' or 'issomething')
result += name
}
return result
}
override fun setterNameByGetterName(name: Name): Name? {
val identifier = name.identifier
val prefix = when {
identifier.startsWith(GETTER_PREFIX) -> GETTER_PREFIX
identifier.startsWith(IS_PREFIX) -> IS_PREFIX
else -> return null
}
return Name.identifier(SETTER_PREFIX + identifier.removePrefix(prefix))
}
override fun getterNameBySetterName(name: Name): Name? {
val identifier = name.identifier
val prefix = when {
identifier.startsWith(SETTER_PREFIX) -> SETTER_PREFIX
else -> return null
}
return Name.identifier(GETTER_PREFIX + identifier.removePrefix(prefix))
}
override fun possiblePropertyNamesByAccessorName(name: Name): List<Name> {
if (name.isSpecial) return emptyList()
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 emptyList()
}
val withoutPrefix = identifier.removePrefix(prefix)
val withoutPrefixName = Name.identifier(withoutPrefix.decapitalizeAsciiOnly())
return if (prefix == SETTER_PREFIX) {
listOf(withoutPrefixName, Name.identifier(IS_PREFIX + withoutPrefix))
} else {
listOf(withoutPrefixName)
}
}
} }
@@ -11,8 +11,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 getterNameBySetterName(name: Name): Name?
abstract fun possiblePropertyNamesByAccessorName(name: Name): List<Name> abstract fun possiblePropertyNamesByAccessorName(name: Name): List<Name>
} }
@@ -85,7 +85,6 @@ class FirSyntheticPropertiesScope(
var matchingSetter: FirSimpleFunction? = null var matchingSetter: FirSimpleFunction? = null
if (getterReturnType != null) { if (getterReturnType != null) {
val setterName = syntheticNamesProvider.setterNameByGetterName(getterName) val setterName = syntheticNamesProvider.setterNameByGetterName(getterName)
if (setterName != null) {
baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirFunctionSymbol<*>) { baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirFunctionSymbol<*>) {
if (matchingSetter != null) return if (matchingSetter != null) return
val setter = setterSymbol.fir as? FirSimpleFunction ?: return val setter = setterSymbol.fir as? FirSimpleFunction ?: return
@@ -112,7 +111,6 @@ class FirSyntheticPropertiesScope(
matchingSetter = setter matchingSetter = setter
}) })
} }
}
val classLookupTag = getterSymbol.originalOrSelf().dispatchReceiverClassOrNull() val classLookupTag = getterSymbol.originalOrSelf().dispatchReceiverClassOrNull()
val packageName = classLookupTag?.classId?.packageFqName ?: getterSymbol.callableId.packageName val packageName = classLookupTag?.classId?.packageFqName ?: getterSymbol.callableId.packageName
@@ -0,0 +1,11 @@
// FIR_IDENTICAL
// SKIP_TXT
// FILE: A.java
public class A {
public String getS4ClassRepresentation() { return ""; }
}
// FILE: main.kt
fun foo(a: A) {
a.s4ClassRepresentation.length
}
@@ -29970,6 +29970,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt"); runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava5.kt");
} }
@Test
@TestMetadata("nonAsciiSecondChar.kt")
public void testNonAsciiSecondChar() throws Exception {
runTest("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/nonAsciiSecondChar.kt");
}
@Test @Test
@TestMetadata("OnlyAscii.kt") @TestMetadata("OnlyAscii.kt")
public void testOnlyAscii() throws Exception { public void testOnlyAscii() throws Exception {