diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt index 74994af056f..21197e79034 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt @@ -5,12 +5,11 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics -import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.diagnostics.error1 +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.util.PrivateForInline @Suppress("ClassName", "unused") @@ -23,5 +22,6 @@ object WASM_DIAGNOSTICS_LIST : DiagnosticList("FirWasmErrors") { val EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE by error(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) { parameter("superType") } + val CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION by error() } } diff --git a/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt b/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt index c5318a10c77..c6d7880a869 100644 --- a/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt +++ b/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.wasm +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.diagnostics.* import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory @@ -21,6 +22,7 @@ object FirWasmErrors { // Externals val NON_EXTERNAL_TYPE_EXTENDS_EXTERNAL_TYPE by error1(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) val EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE by error1(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) + val CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION by error0() init { RootDiagnosticRendererFactory.registerFactory(FirWasmErrorsDefaultMessages) diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt index d5ce51a31f1..23037ebaba6 100644 --- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.wasm import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers +import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.NON_EXTERNAL_TYPE_EXTENDS_EXTERNAL_TYPE @@ -16,5 +17,6 @@ object FirWasmErrorsDefaultMessages : BaseDiagnosticRendererFactory() { override val MAP = KtDiagnosticFactoryToRendererMap("FIR").also { map -> map.put(NON_EXTERNAL_TYPE_EXTENDS_EXTERNAL_TYPE, "Non-external type extends external type {0}", FirDiagnosticRenderers.RENDER_TYPE) map.put(EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE, "External type extends non-external type {0}", FirDiagnosticRenderers.RENDER_TYPE) + map.put(CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION, "This property can only be used from external declarations.") } } diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmExpressionCheckers.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmExpressionCheckers.kt index f91fff85b36..3d0df4d61bb 100644 --- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmExpressionCheckers.kt +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmExpressionCheckers.kt @@ -6,6 +6,11 @@ package org.jetbrains.kotlin.fir.analysis.wasm.checkers import org.jetbrains.kotlin.fir.analysis.checkers.expression.* +import org.jetbrains.kotlin.fir.analysis.wasm.checkers.expression.FirWasmDefinedExternallyCallChecker object WasmExpressionCheckers : ExpressionCheckers() { + override val basicExpressionCheckers: Set + get() = setOf( + FirWasmDefinedExternallyCallChecker, + ) } diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/expression/FirWasmDefinedExternallyCallChecker.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/expression/FirWasmDefinedExternallyCallChecker.kt new file mode 100644 index 00000000000..aa59bbb52d8 --- /dev/null +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/expression/FirWasmDefinedExternallyCallChecker.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.wasm.checkers.expression + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.closestNonLocal +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors +import org.jetbrains.kotlin.fir.declarations.utils.isEffectivelyExternal +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.expressions.calleeReference +import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol +import org.jetbrains.kotlin.name.WasmStandardClassIds + +object FirWasmDefinedExternallyCallChecker : FirBasicExpressionChecker() { + override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) { + val symbol = expression.calleeReference?.toResolvedCallableSymbol() ?: return + + if (symbol.callableId != WasmStandardClassIds.Callables.JsDefinedExternally) { + return + } + + val container = context.closestNonLocal?.symbol ?: return + + if (!container.isEffectivelyExternal(context.session)) { + reporter.reportOn(expression.source, FirWasmErrors.CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION, context) + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/wasmTests/jsInterop/definedExternally.kt b/compiler/testData/diagnostics/wasmTests/jsInterop/definedExternally.kt new file mode 100644 index 00000000000..dc69e84ef9b --- /dev/null +++ b/compiler/testData/diagnostics/wasmTests/jsInterop/definedExternally.kt @@ -0,0 +1,39 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER -UNUSED_PARAMETER, -UNREACHABLE_CODE + +val prop: String = definedExternally + +val prop2: String + get() = definedExternally + +fun foo(x: Int, y: String = definedExternally) { + println("Hello") + println("world") + + object { + fun bar(): Any = definedExternally + } + + listOf() + .map { definedExternally } + .filter(fun(x: String): Boolean { definedExternally }) + + definedExternally +} + +open class A(val x: Int) + +open class B() : A(definedExternally) { + constructor(y: String) : this() + + constructor(y: String, z: String) : this(y + z + definedExternally) +} + +private fun exposeClassS() = run { + class S { + inner class W { + val v: String = definedExternally + } + } + S() +} diff --git a/compiler/testData/diagnostics/wasmTests/wasmInterop/wasmExport.fir.kt b/compiler/testData/diagnostics/wasmTests/wasmInterop/wasmExport.fir.kt index 55327ca7e32..bb5fe28cb74 100644 --- a/compiler/testData/diagnostics/wasmTests/wasmInterop/wasmExport.fir.kt +++ b/compiler/testData/diagnostics/wasmTests/wasmInterop/wasmExport.fir.kt @@ -53,6 +53,6 @@ fun fooGeneric(x: T): T { return x } @WasmExport("a") fun fooDeafultAndVararg( -a: Int = definedExternally, +a: Int = definedExternally, vararg b: Int ): Unit { b.toString() } diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsFirWasmTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsFirWasmTestGenerated.java index 9f2ce65daab..824d2a22cf5 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsFirWasmTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsFirWasmTestGenerated.java @@ -33,6 +33,12 @@ public class DiagnosticsFirWasmTestGenerated extends AbstractDiagnosticsFirWasmT KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/wasmTests/jsInterop"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("definedExternally.kt") + public void testDefinedExternally() throws Exception { + runTest("compiler/testData/diagnostics/wasmTests/jsInterop/definedExternally.kt"); + } + @Test @TestMetadata("dynamicUnsupported.kt") public void testDynamicUnsupported() throws Exception { diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsWasmTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsWasmTestGenerated.java index bb1ac8e796d..4e93ec0ab5f 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsWasmTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/diagnostics/DiagnosticsWasmTestGenerated.java @@ -33,6 +33,12 @@ public class DiagnosticsWasmTestGenerated extends AbstractDiagnosticsWasmTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/wasmTests/jsInterop"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("definedExternally.kt") + public void testDefinedExternally() throws Exception { + runTest("compiler/testData/diagnostics/wasmTests/jsInterop/definedExternally.kt"); + } + @Test @TestMetadata("dynamicUnsupported.kt") public void testDynamicUnsupported() throws Exception {