Skip to content

Commit 1480fb4

Browse files
JSMonkSpace Team
authored andcommitted
[K/JS] Introduce a checker for @JsExport.Default usage in a single file
^KT-80401
1 parent b88a59f commit 1480fb4

File tree

21 files changed

+118
-47
lines changed

21 files changed

+118
-47
lines changed

analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7211,6 +7211,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KaDiagnosticConverterBuilder.buildConvert
72117211
token,
72127212
)
72137213
}
7214+
add(FirWebCommonErrors.MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE) { firDiagnostic ->
7215+
MultipleJsExportDefaultInOneFileImpl(
7216+
firDiagnostic as KtPsiDiagnostic,
7217+
token,
7218+
)
7219+
}
72147220
add(FirJsErrors.DELEGATION_BY_DYNAMIC) { firDiagnostic ->
72157221
DelegationByDynamicImpl(
72167222
firDiagnostic as KtPsiDiagnostic,

analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5045,6 +5045,10 @@ sealed interface KaFirDiagnostic<PSI : PsiElement> : KaDiagnosticWithPsi<PSI> {
50455045
override val diagnosticClass get() = NestedJsExport::class
50465046
}
50475047

5048+
interface MultipleJsExportDefaultInOneFile : KaFirDiagnostic<KtElement> {
5049+
override val diagnosticClass get() = MultipleJsExportDefaultInOneFile::class
5050+
}
5051+
50485052
interface DelegationByDynamic : KaFirDiagnostic<KtElement> {
50495053
override val diagnosticClass get() = DelegationByDynamic::class
50505054
}

analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6067,6 +6067,11 @@ internal class NestedJsExportImpl(
60676067
token: KaLifetimeToken,
60686068
) : KaAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KaFirDiagnostic.NestedJsExport
60696069

6070+
internal class MultipleJsExportDefaultInOneFileImpl(
6071+
firDiagnostic: KtPsiDiagnostic,
6072+
token: KaLifetimeToken,
6073+
) : KaAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KaFirDiagnostic.MultipleJsExportDefaultInOneFile
6074+
60706075
internal class DelegationByDynamicImpl(
60716076
firDiagnostic: KtPsiDiagnostic,
60726077
token: KaLifetimeToken,

compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWebCommonDiagnosticList.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ object WEB_COMMON_DIAGNOSTICS_LIST : DiagnosticList("FirWebCommonErrors") {
4949

5050
val EXPORT by object : DiagnosticGroup("Export") {
5151
val NESTED_JS_EXPORT by error<KtElement>()
52+
val MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE by error<KtElement>()
5253
}
5354

5455
val JSCODE by object : DiagnosticGroup("JsCode") {

compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.js.checkers
88
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
99
import org.jetbrains.kotlin.fir.analysis.js.checkers.declaration.*
1010
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsExportAnnotationChecker
11+
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirMultipleJsExportDefaultAnnotationChecker
1112
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirWebCommonExternalPropertyAccessorChecker
1213

1314
object JsDeclarationCheckers : DeclarationCheckers() {
@@ -60,6 +61,7 @@ object JsDeclarationCheckers : DeclarationCheckers() {
6061
override val fileCheckers: Set<FirFileChecker>
6162
get() = setOf(
6263
FirJsPackageDirectiveChecker,
64+
FirMultipleJsExportDefaultAnnotationChecker,
6365
FirJsNameClashFileTopLevelDeclarationsChecker
6466
)
6567

compiler/fir/checkers/checkers.web.common/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/web/common/FirWebCommonErrors.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ object FirWebCommonErrors : KtDiagnosticsContainer() {
5151

5252
// Export
5353
val NESTED_JS_EXPORT: KtDiagnosticFactory0 = KtDiagnosticFactory0("NESTED_JS_EXPORT", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
54+
val MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE: KtDiagnosticFactory0 = KtDiagnosticFactory0("MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
5455

5556
// JsCode
5657
val JSCODE_ARGUMENT_NON_CONST_EXPRESSION: KtDiagnosticFactory0 = KtDiagnosticFactory0("JSCODE_ARGUMENT_NON_CONST_EXPRESSION", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())

compiler/fir/checkers/checkers.web.common/src/org/jetbrains/kotlin/fir/analysis/diagnostics/web/common/FirWebCommonErrorsDefaultMessages.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErro
1919
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT
2020
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.INLINE_EXTERNAL_DECLARATION
2121
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.JSCODE_ARGUMENT_NON_CONST_EXPRESSION
22+
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE
2223
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NAMED_COMPANION_IN_EXTERNAL_INTERFACE
2324
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_CLASS_IN_EXTERNAL_INTERFACE
2425
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_EXTERNAL_DECLARATION
@@ -77,6 +78,10 @@ object FirWebCommonErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
7778

7879

7980
map.put(NESTED_JS_EXPORT, "'@JsExport' is only allowed on files and top-level declarations.")
81+
map.put(
82+
MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE,
83+
"Only one declaration with '@JsExport.Default' is allowed per file."
84+
)
8085

8186
map.put(JSCODE_ARGUMENT_NON_CONST_EXPRESSION, "An argument for the 'js()' function must be a constant string expression.")
8287
map.put(NAMED_COMPANION_IN_EXTERNAL_INTERFACE, "Named companions are not allowed inside external interfaces.")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration
7+
8+
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
9+
import org.jetbrains.kotlin.diagnostics.reportOn
10+
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
11+
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
12+
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
13+
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFileChecker
14+
import org.jetbrains.kotlin.fir.analysis.checkers.isTopLevel
15+
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors
16+
import org.jetbrains.kotlin.fir.declarations.DirectDeclarationsAccess
17+
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
18+
import org.jetbrains.kotlin.fir.declarations.FirFile
19+
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
20+
import org.jetbrains.kotlin.name.StandardClassIds
21+
22+
object FirMultipleJsExportDefaultAnnotationChecker : FirFileChecker(MppCheckerKind.Common) {
23+
@OptIn(DirectDeclarationsAccess::class)
24+
context(context: CheckerContext, reporter: DiagnosticReporter)
25+
override fun check(declaration: FirFile) {
26+
val declarationsWithJsExportDefault = declaration.declarations.filter {
27+
it.getAnnotationByClassId(StandardClassIds.Annotations.jsExportDefault, context.session) != null
28+
}
29+
30+
if (declarationsWithJsExportDefault.size > 1) {
31+
declarationsWithJsExportDefault.forEach {
32+
reporter.reportOn(it.source, FirWebCommonErrors.MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE)
33+
}
34+
}
35+
}
36+
}

compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
798798
"NAMED_COMPANION_IN_EXPORTED_INTERFACE",
799799
"NOT_EXPORTED_ACTUAL_DECLARATION_WHILE_EXPECT_IS_EXPORTED",
800800
"NESTED_JS_EXPORT",
801+
"MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE",
801802
"DELEGATION_BY_DYNAMIC",
802803
"PROPERTY_DELEGATION_BY_DYNAMIC",
803804
"SPREAD_OPERATOR_IN_DYNAMIC_CALL",

compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclaration.fir.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ inline class <!WRONG_EXPORTED_DECLARATION("value class")!>B(val b: Int)<!>
5151
@JsExport
5252
<!INCOMPATIBLE_MODIFIERS("inline; value")!>inline<!> <!INCOMPATIBLE_MODIFIERS("value; inline")!>value<!> class <!WRONG_EXPORTED_DECLARATION("value class")!>C(val c: Int)<!>
5353

54-
@JsExport.Default
55-
<!INCOMPATIBLE_MODIFIERS("value; inline")!>value<!> <!INCOMPATIBLE_MODIFIERS("inline; value")!>inline<!> class <!WRONG_EXPORTED_DECLARATION("value class")!>D(val d: Int)<!>
54+
<!MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE!>@JsExport.Default
55+
<!INCOMPATIBLE_MODIFIERS("value; inline")!>value<!> <!INCOMPATIBLE_MODIFIERS("inline; value")!>inline<!> class <!WRONG_EXPORTED_DECLARATION("value class")!>D(val d: Int)<!><!>
5656

5757
@JsExport
5858
external interface ExternalInterface
5959

60-
@JsExport.Default
61-
external interface DefaultExternalInterface
60+
<!MULTIPLE_JS_EXPORT_DEFAULT_IN_ONE_FILE!>@JsExport.Default
61+
external interface DefaultExternalInterface<!>
6262

6363
@JsExport
6464
external enum class <!ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING, WRONG_EXPORTED_DECLARATION("external enum class")!>ExternalEnum<!> {

0 commit comments

Comments
 (0)