[Wasm] PublishedApi and Intrinsic leak diagnostic for stdlib
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 6105af1..7811084 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
@@ -76,4 +76,8 @@
val ASSOCIATED_OBJECTS by object : DiagnosticGroup("Associated object") {
val ASSOCIATED_OBJECT_INVALID_BINDING by error<KtElement>()
}
+
+ val WASM_INTERNAL by object : DiagnosticGroup("Internals") {
+ val INTRINSICS_INLINED_IN_KLIB by error<PsiElement>()
+ }
}
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 7fd595f..5d99c60 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
@@ -63,5 +63,8 @@
// Associated object
val ASSOCIATED_OBJECT_INVALID_BINDING: KtDiagnosticFactory0 = KtDiagnosticFactory0("ASSOCIATED_OBJECT_INVALID_BINDING", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ // Internals
+ val INTRINSICS_INLINED_IN_KLIB: KtDiagnosticFactory0 = KtDiagnosticFactory0("INTRINSICS_INLINED_IN_KLIB", ERROR, SourceElementPositioningStrategies.DEFAULT, PsiElement::class, getRendererFactory())
+
override fun getRendererFactory(): BaseDiagnosticRendererFactory = 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 17ae592..d8ea2cd1 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
@@ -28,6 +28,7 @@
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.EXPORT_DECLARATION_WITH_CONTEXT_PARAMETERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_EXPORT_ON_EXTERNAL_DECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.EXTERNAL_DECLARATION_WITH_CONTEXT_PARAMETERS
+import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.INTRINSICS_INLINED_IN_KLIB
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_PARAMETER_DEFAULT_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_UNSUPPORTED_PARAMETER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_UNSUPPORTED_RETURN_TYPE
@@ -112,5 +113,7 @@
map.put(EXTERNAL_DECLARATION_WITH_CONTEXT_PARAMETERS, "External declaration cannot have context parameters.")
map.put(EXPORT_DECLARATION_WITH_CONTEXT_PARAMETERS, "Exported declaration cannot have context parameters.")
+
+ map.put(INTRINSICS_INLINED_IN_KLIB, "Wasm intrinsics should not be inlined into KLib")
}
}
diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt
index ff1af1e..d7a22e2 100644
--- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt
+++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt
@@ -9,6 +9,7 @@
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyAccessorChecker
+import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirSimpleFunctionChecker
import org.jetbrains.kotlin.fir.analysis.wasm.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsExportAnnotationChecker
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirWebCommonExternalPropertyAccessorChecker
@@ -43,6 +44,11 @@
FirWasmExternalFileChecker,
FirWasmJsAssociatedObjectChecker,
)
+
+ override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
+ get() = setOf(
+ FirWasmIntrinsicInlineFunctionChecker,
+ )
}
object WasmWasiDeclarationCheckers : DeclarationCheckers() {
@@ -50,4 +56,9 @@
get() = setOf(
FirWasmWasiExternalDeclarationChecker,
)
+
+ override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
+ get() = setOf(
+ FirWasmIntrinsicInlineFunctionChecker,
+ )
}
diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmIntrinsicInlineFunctionChecker.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmIntrinsicInlineFunctionChecker.kt
new file mode 100644
index 0000000..7402cae
--- /dev/null
+++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmIntrinsicInlineFunctionChecker.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010-2025 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.declaration
+
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
+import org.jetbrains.kotlin.diagnostics.reportOn
+import org.jetbrains.kotlin.fir.FirElement
+import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirSimpleFunctionChecker
+import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.INTRINSICS_INLINED_IN_KLIB
+import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
+import org.jetbrains.kotlin.fir.declarations.hasAnnotation
+import org.jetbrains.kotlin.fir.declarations.utils.isInline
+import org.jetbrains.kotlin.fir.declarations.utils.visibility
+import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
+import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
+import org.jetbrains.kotlin.fir.moduleData
+import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.name.StandardClassIds
+
+object FirWasmIntrinsicInlineFunctionChecker : FirSimpleFunctionChecker(MppCheckerKind.Platform) {
+ private val wasmInternal = FqName("kotlin.wasm.internal")
+ private val excludedFromCodegenFqName = ClassId(wasmInternal, Name.identifier("ExcludedFromCodegen"))
+ private val wasmOpFqName = ClassId(wasmInternal, Name.identifier("WasmOp"))
+ private val wasmNoOpCastFqName = ClassId(wasmInternal, Name.identifier("WasmNoOpCast"))
+ private val noKlibInlining = ClassId(FqName("kotlin"), Name.identifier("NoKlibInlining"))
+
+ context(context: CheckerContext, reporter: DiagnosticReporter)
+ override fun check(declaration: FirSimpleFunction) {
+ if (context.session.moduleData.name.toString() != "<kotlin>") return
+ if (!declaration.isInline) return
+ if (declaration.visibility != Visibilities.Public && !declaration.hasAnnotation(StandardClassIds.Annotations.PublishedApi, context.session)) return
+ if (declaration.hasAnnotation(noKlibInlining, context.session)) return
+
+ val body = declaration.body ?: return
+
+ val intrinsicCallFinder = object : FirDefaultVisitorVoid() {
+ override fun visitElement(element: FirElement) {
+ element.acceptChildren(this)
+ }
+
+ override fun visitFunctionCall(functionCall: FirFunctionCall) {
+ val resolvedSymbol = functionCall.toResolvedCallableSymbol() ?: return
+
+ val hasWasmIntrinsicCall =
+ resolvedSymbol.hasAnnotation(excludedFromCodegenFqName, context.session) ||
+ resolvedSymbol.hasAnnotation(wasmOpFqName, context.session) ||
+ resolvedSymbol.hasAnnotation(wasmNoOpCastFqName, context.session) ||
+ resolvedSymbol.hasAnnotation(StandardClassIds.Annotations.PublishedApi, context.session)
+
+ if (hasWasmIntrinsicCall) {
+ reporter.reportOn(functionCall.source, INTRINSICS_INLINED_IN_KLIB)
+ }
+
+ super.visitFunctionCall(functionCall)
+ }
+ }
+
+ body.accept(intrinsicCallFinder)
+ }
+}
\ No newline at end of file
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
index 90dfdf9..2287155 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
@@ -875,5 +875,6 @@
"WASI_EXTERNAL_NOT_TOP_LEVEL_FUNCTION",
"WASI_EXTERNAL_FUNCTION_WITHOUT_IMPORT",
"ASSOCIATED_OBJECT_INVALID_BINDING",
+ "INTRINSICS_INLINED_IN_KLIB",
"SYNTAX",
)
diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt
index bb77b0e..8560e1c 100644
--- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt
+++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt
@@ -56,6 +56,10 @@
"Parameters passed to js(code) should have a valid JavaScript name"
)
+ put(
+ ErrorsWasm.INTRINSICS_INLINED_IN_KLIB,
+ "Wasm intrinsics should not be inlined into KLib"
+ )
}
}
diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java
index e1b5d54..ba34075 100644
--- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java
+++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java
@@ -43,6 +43,8 @@
DiagnosticFactory1<PsiElement, String> JSCODE_UNSUPPORTED_FUNCTION_KIND = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> JSCODE_INVALID_PARAMETER_NAME = DiagnosticFactory0.create(ERROR);
+ DiagnosticFactory0<PsiElement> INTRINSICS_INLINED_IN_KLIB = DiagnosticFactory0.create(ERROR);
+
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
{