From f9378a3ab72745d2f7f717eb681e0dbbc13b2e9a Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 19 Jan 2021 15:41:33 -0800 Subject: [PATCH] FIR checker: add diagnostic EXPECTED_DECLARATION_WITH_BODY --- .../declaration/FirDeclarationCheckerUtils.kt | 14 ++++++++++++++ .../declaration/FirMemberFunctionChecker.kt | 5 +++++ .../declaration/FirTopLevelFunctionChecker.kt | 5 ++++- .../diagnostics/FirDefaultErrorMessages.kt | 4 ++++ .../kotlin/fir/analysis/diagnostics/FirErrors.kt | 3 +++ .../tests/modifiers/openInExpectInterface.fir.kt | 2 +- .../headerClass/headerClassWithFunctionBody.fir.kt | 2 +- .../topLevelFun/headerDeclarationWithBody.fir.kt | 9 --------- .../topLevelFun/headerDeclarationWithBody.kt | 1 + 9 files changed, 33 insertions(+), 12 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.fir.kt 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 13a4196d6e3..7c7aef1b0b5 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,10 +5,24 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.extended.report +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.hasBody import org.jetbrains.kotlin.fir.declarations.isExpect // Note that the class that contains the currently visiting declaration will *not* be in the context's containing declarations *yet*. 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) { + val source = function.source ?: return + if (source.kind is FirFakeSourceElementKind) return + if (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 7046416221f..8c23982db76 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 @@ -60,6 +60,11 @@ object FirMemberFunctionChecker : FirRegularClassChecker() { reporter.report(FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(source, function)) } } + + val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true + if (isExpect) { + checkExpectFunction(function, reporter) + } } } 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 ec8b47ec082..6f237bc0914 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 @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.extended.report import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.* @@ -35,5 +34,9 @@ object FirTopLevelFunctionChecker : FirFileChecker() { if (!function.hasBody && !hasAbstractModifier && !isExternal && !isExpect) { reporter.report(FirErrors.NON_MEMBER_FUNCTION_NO_BODY.on(source, function)) } + + if (isExpect) { + checkExpectFunction(function, 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 3d795c8ecac..2cff65fc736 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 @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_E import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EMPTY_RANGE 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.EXPLICIT_DELEGATION_CALL_REQUIRED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_FUNCTION_RETURN_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PARAMETER_TYPE @@ -394,6 +395,9 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY, "Private setters are not allowed for abstract properties") map.put(PRIVATE_SETTER_FOR_OPEN_PROPERTY, "Private setters are not allowed for open properties") + // Multi-platform projects + map.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body") + // Destructuring declaration map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration") map.put( 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 7450b82105e..e987ed91adf 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 @@ -180,6 +180,9 @@ object FirErrors { val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error0() val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error0() + // Multi-platform projects + val EXPECTED_DECLARATION_WITH_BODY by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + // Destructuring declaration val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() val COMPONENT_FUNCTION_MISSING by error2() diff --git a/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt b/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt index 9e7525245ad..1957883d6de 100644 --- a/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt +++ b/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt @@ -5,7 +5,7 @@ expect interface My { open fun bar() - open fun bas() {} + open fun bas() {} open abstract fun bat(): Int fun foo() diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/headerClassWithFunctionBody.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/headerClassWithFunctionBody.fir.kt index 359647a50ee..7f3380f618c 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/headerClassWithFunctionBody.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/headerClassWithFunctionBody.fir.kt @@ -21,7 +21,7 @@ expect class Foo( get() = "no" set(value) {} - fun functionWithBody(x: Int): Int { + fun functionWithBody(x: Int): Int { return x + 1 } } diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.fir.kt deleted file mode 100644 index b7917046dff..00000000000 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -// !LANGUAGE: +MultiPlatformProjects -// MODULE: m1-common -// FILE: common.kt - -expect fun foo() - -expect fun foo() {} - -expect fun bar() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.kt index 6751e0bd017..80e55c41d2a 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerDeclarationWithBody.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +MultiPlatformProjects // MODULE: m1-common // FILE: common.kt