diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt index 36faf79c062..b4bdcd6c01d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.extended.report @@ -19,10 +20,23 @@ import org.jetbrains.kotlin.lexer.KtTokens internal fun isInsideExpectClass(containingDeclaration: FirRegularClass, context: CheckerContext): Boolean = containingDeclaration.isExpect || context.containingDeclarations.asReversed().any { it is FirRegularClass && it.isExpect } -internal fun checkExpectFunction(function: FirSimpleFunction, reporter: DiagnosticReporter) { +// TODO: check class too +internal fun checkPrivateExpectedDeclaration(declaration: FirMemberDeclaration, reporter: DiagnosticReporter) { + val source = declaration.source ?: return + if (source.kind is FirFakeSourceElementKind) return + val modifierList = with(FirModifierList) { source.getModifierList() } + val isExpect = declaration.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true + if (isExpect && Visibilities.isPrivate(declaration.visibility)) { + reporter.report(source, FirErrors.EXPECTED_PRIVATE_DECLARATION) + } +} + +internal fun checkExpectFunctionHasBody(function: FirSimpleFunction, reporter: DiagnosticReporter) { val source = function.source ?: return if (source.kind is FirFakeSourceElementKind) return - if (function.hasBody) { + val modifierList = with(FirModifierList) { source.getModifierList() } + val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true + if (isExpect && function.hasBody) { reporter.report(source, FirErrors.EXPECTED_DECLARATION_WITH_BODY) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberFunctionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberFunctionChecker.kt index 8c23982db76..7d34523465e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberFunctionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberFunctionChecker.kt @@ -61,10 +61,8 @@ object FirMemberFunctionChecker : FirRegularClassChecker() { } } - val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true - if (isExpect) { - checkExpectFunction(function, reporter) - } + checkExpectFunctionHasBody(function, reporter) + checkPrivateExpectedDeclaration(function, reporter) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt index cd3036ece87..04ed7eba00f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt @@ -98,6 +98,8 @@ object FirMemberPropertyChecker : FirRegularClassChecker() { } } } + + checkPrivateExpectedDeclaration(property, reporter) } private fun checkAccessor( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelFunctionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelFunctionChecker.kt index 6f237bc0914..4630b3d471e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelFunctionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelFunctionChecker.kt @@ -35,8 +35,7 @@ object FirTopLevelFunctionChecker : FirFileChecker() { reporter.report(FirErrors.NON_MEMBER_FUNCTION_NO_BODY.on(source, function)) } - if (isExpect) { - checkExpectFunction(function, reporter) - } + checkExpectFunctionHasBody(function, reporter) + checkPrivateExpectedDeclaration(function, reporter) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt index c1c5c4246e1..cf0c09e9d44 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt @@ -22,5 +22,6 @@ object FirTopLevelPropertyChecker : FirFileChecker() { private fun checkProperty(property: FirProperty, reporter: DiagnosticReporter) { checkPropertyInitializer(null, property, reporter) + checkPrivateExpectedDeclaration(property, reporter) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 682cf11b5cd..80afdfd30a4 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -52,6 +52,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ENUM_AS_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DECLARATION_WITH_BODY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DELEGATED_PROPERTY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PRIVATE_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PROPERTY_INITIALIZER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_FUNCTION_RETURN_TYPE @@ -401,6 +402,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body") map.put(EXPECTED_PROPERTY_INITIALIZER, "Expected property cannot have an initializer") map.put(EXPECTED_DELEGATED_PROPERTY, "Expected property cannot be delegated") + map.put(EXPECTED_PRIVATE_DECLARATION, "Expected declaration cannot be private") // Destructuring declaration map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 3d934e6174d..47bfb8a2fe3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -193,6 +193,7 @@ object FirErrors { val EXPECTED_PROPERTY_INITIALIZER by error0() // TODO: need to cover `by` as well as delegate expression val EXPECTED_DELEGATED_PROPERTY by error0() + val EXPECTED_PRIVATE_DECLARATION by error0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) // Destructuring declaration val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/privateMembers.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/privateMembers.fir.kt index fe2e20bb2ed..2637cdcae26 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/privateMembers.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/privateMembers.fir.kt @@ -3,9 +3,9 @@ // FILE: common.kt expect class A { - private fun foo() - private val bar: String - private fun Int.memExt(): Any + private fun foo() + private val bar: String + private fun Int.memExt(): Any private class Nested } diff --git a/compiler/testData/diagnostics/tests/multiplatform/privateTopLevelDeclarations.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/privateTopLevelDeclarations.fir.kt index 1b28447d41b..6b91b6b4321 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/privateTopLevelDeclarations.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/privateTopLevelDeclarations.fir.kt @@ -2,9 +2,9 @@ // MODULE: m1-common // FILE: common.kt -private expect fun foo() -private expect val bar: String -private expect fun Int.memExt(): Any +private expect fun foo() +private expect val bar: String +private expect fun Int.memExt(): Any private expect class Foo