[FE] Fix checker of DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS

...not reporting on companion object members as well as other
nested classes.

Annotation classes are accepted because this is how it already worked,
see other tests, for example `annotationsViaActualTypeAlias.kt`.

Test for nested annotation classes will be added in subsequent commit,
because it currently will fail in test
`TreeCompareTest.testCompareDiagnostics` because light-tree2fir
produces different tree due to a bug when converting properties
from expect primary constructor. See subsequent commit for a fix.

Review: KT-MR-12107

^KT-61784
This commit is contained in:
Roman Efremov
2023-09-08 12:23:45 +02:00
committed by Space Team
parent e0e2a57e3d
commit c6d7f15070
7 changed files with 128 additions and 20 deletions
@@ -982,6 +982,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt");
}
@Test
@TestMetadata("companionMethodViaActualTypealias.kt")
public void testCompanionMethodViaActualTypealias() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt");
}
@Test
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
@@ -1029,6 +1035,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
public void testMethodDefaultArgsViaActualTypealias_oldLanguageVersion() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualTypealias_oldLanguageVersion.kt");
}
@Test
@TestMetadata("nestedClassMethodsViaActualTypealias.kt")
public void testNestedClassMethodsViaActualTypealias() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt");
}
}
@Nested
@@ -982,6 +982,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt");
}
@Test
@TestMetadata("companionMethodViaActualTypealias.kt")
public void testCompanionMethodViaActualTypealias() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt");
}
@Test
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
@@ -1029,6 +1035,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
public void testMethodDefaultArgsViaActualTypealias_oldLanguageVersion() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualTypealias_oldLanguageVersion.kt");
}
@Test
@TestMetadata("nestedClassMethodsViaActualTypealias.kt")
public void testNestedClassMethodsViaActualTypealias() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt");
}
}
@Nested
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors
import org.jetbrains.kotlin.fir.scopes.getSingleClassifier
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -236,16 +237,9 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
reporter: DiagnosticReporter,
) {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions)) return
if (expectSymbol !is FirClassSymbol ||
actualSymbol !is FirTypeAliasSymbol ||
expectSymbol.classKind == ClassKind.ANNOTATION_CLASS
) return
val membersWithDefaultValueParameters =
expectSymbol.declaredMemberScope(expectSymbol.moduleData.session, memberRequiredPhase = null)
.run { collectAllFunctions() + getDeclaredConstructors() }
.filter { it.valueParameterSymbols.any(FirValueParameterSymbol::hasDefaultValue) }
if (expectSymbol !is FirClassSymbol || actualSymbol !is FirTypeAliasSymbol) return
val membersWithDefaultValueParameters = getMembersWithDefaultValueParametersUnlessAnnotation(expectSymbol)
if (membersWithDefaultValueParameters.isEmpty()) return
reporter.reportOn(
@@ -257,6 +251,31 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
)
}
private fun getMembersWithDefaultValueParametersUnlessAnnotation(classSymbol: FirClassSymbol<*>): List<FirFunctionSymbol<*>> {
val result = mutableListOf<FirFunctionSymbol<*>>()
fun collectFunctions(classSymbol: FirClassSymbol<*>) {
if (classSymbol.classKind == ClassKind.ANNOTATION_CLASS) {
return
}
val memberScope = classSymbol.declaredMemberScope(classSymbol.moduleData.session, memberRequiredPhase = null)
val functionsAndConstructors = memberScope
.run { collectAllFunctions() + getDeclaredConstructors() }
functionsAndConstructors.filterTo(result) { it.valueParameterSymbols.any(FirValueParameterSymbol::hasDefaultValue) }
val nestedClasses = memberScope.getClassifierNames()
.mapNotNull { memberScope.getSingleClassifier(it) as? FirClassSymbol<*> }
for (nestedClassSymbol in nestedClasses) {
collectFunctions(nestedClassSymbol)
}
}
collectFunctions(classSymbol)
return result
}
private fun checkAnnotationsMatch(
expectSymbol: FirBasedSymbol<*>,
actualSymbol: FirBasedSymbol<*>,
@@ -244,18 +244,9 @@ class ExpectedActualDeclarationChecker(
context: DeclarationCheckerContext,
) {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions)) return
if (expectDescriptor !is ClassDescriptor ||
actualDeclaration !is KtTypeAlias ||
expectDescriptor.kind == ClassKind.ANNOTATION_CLASS
) return
val members = expectDescriptor.constructors + expectDescriptor.unsubstitutedMemberScope
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
.filterIsInstance<FunctionDescriptor>()
val membersWithDefaultValueParameters = members
.filter { it.valueParameters.any { p -> p.declaresDefaultValue() }}
if (expectDescriptor !is ClassDescriptor || actualDeclaration !is KtTypeAlias) return
val membersWithDefaultValueParameters = getMembersWithDefaultValueParametersUnlessAnnotation(expectDescriptor)
if (membersWithDefaultValueParameters.isEmpty()) return
context.trace.report(
@@ -267,6 +258,32 @@ class ExpectedActualDeclarationChecker(
)
}
private fun getMembersWithDefaultValueParametersUnlessAnnotation(classDescriptor: ClassDescriptor): List<FunctionDescriptor> {
val result = mutableListOf<FunctionDescriptor>()
fun collectFunctions(classDescriptor: ClassDescriptor) {
if (classDescriptor.kind == ClassKind.ANNOTATION_CLASS) {
return
}
val functionsAndConstructors = classDescriptor.constructors + classDescriptor.unsubstitutedMemberScope
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
.filterIsInstance<FunctionDescriptor>()
functionsAndConstructors.filterTo(result) { it.valueParameters.any { p -> p.declaresDefaultValue() } }
val nestedClasses = classDescriptor.unsubstitutedMemberScope
.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)
.filterIsInstance<ClassDescriptor>()
for (nestedClass in nestedClasses) {
collectFunctions(nestedClass)
}
}
collectFunctions(classDescriptor)
return result
}
private fun MemberDescriptor.hasNoActualWithDiagnostic(
compatibility: Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>
): Boolean {
@@ -0,0 +1,18 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class DefaultArgsInCompanion {
companion object {
fun foo(p: String = "")
}
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
class DefaultArgsInCompanionImpl {
companion object {
fun foo(p: String) {}
}
}
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias DefaultArgsInCompanion = DefaultArgsInCompanionImpl<!>
@@ -0,0 +1,18 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class DefaultArgsInNestedClass {
class Nested {
fun foo(p: String = "")
}
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
class DefaultArgsInNestedClassImpl {
class Nested {
fun foo(p: String) {}
}
}
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias DefaultArgsInNestedClass = DefaultArgsInNestedClassImpl<!>
@@ -23977,6 +23977,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt");
}
@Test
@TestMetadata("companionMethodViaActualTypealias.kt")
public void testCompanionMethodViaActualTypealias() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt");
}
@Test
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
@@ -24024,6 +24030,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
public void testMethodDefaultArgsViaActualTypealias_oldLanguageVersion() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualTypealias_oldLanguageVersion.kt");
}
@Test
@TestMetadata("nestedClassMethodsViaActualTypealias.kt")
public void testNestedClassMethodsViaActualTypealias() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt");
}
}
@Nested