Skip to content

Commit e94ca5a

Browse files
authored
Merge pull request #325 from thisisthepy/feat/ksp-root-package
KSP: skip root-package declarations with a warning (#319)
2 parents 6cf658d + df99652 commit e94ca5a

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// No `package` line on purpose (issue #319): a root-package declaration cannot be named from the
2+
// generated fragments, so the processor skips it with a warning instead of breaking this build.
3+
4+
fun rootPackageProbe(): Int = 7
5+
6+
class RootPackageThing
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package fixture.app
2+
3+
import python.multiplatform.generated.FunctionTable
4+
import kotlin.test.Test
5+
import kotlin.test.assertTrue
6+
7+
/**
8+
* Issue #319: `RootPackageDeclarations.kt` has no package. Before the fix the processor emitted an
9+
* unqualified `rootPackageProbe()` call inside `python.multiplatform.generated.fragments`, and this
10+
* module did not compile. Now the root-package declarations are skipped (with a KSP warning), the
11+
* module compiles, and neither appears in the generated table.
12+
*/
13+
class RootPackageSkipTest {
14+
15+
@Test
16+
fun rootPackageDeclarationsAreNotInTheTable() {
17+
val names = FunctionTable.fragments.flatMap { fragment -> fragment.entries().map { it.name } + fragment.classes().map { it.toString() } }
18+
assertTrue(names.isNotEmpty(), "the table is empty, so this asserts nothing")
19+
val leaked = names.filter { it == "rootPackageProbe" || it.startsWith("RootPackageThing") || it.endsWith(".rootPackageProbe") }
20+
assertTrue(leaked.isEmpty(), "root-package declarations reached the table: $leaked")
21+
}
22+
}

‎python-multiplatform-ksp/src/main/kotlin/python/multiplatform/ksp/FragmentScanner.kt‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,20 @@ class FragmentScanner(private val excludePackages: List<String>, private val log
9191
val classes = mutableListOf<ClassModel>()
9292

9393
files.flatMap { it.declarations }.forEach { declaration ->
94+
// Issue #319: Kotlin cannot name a root-package declaration from a named package, and
95+
// every generated fragment and table lives in one, so a binding could only ever be an
96+
// unresolved reference. Skipped with a warning instead of breaking the consumer's build.
97+
if (declaration.packageName.asString().isEmpty()) {
98+
if (declaration is KSFunctionDeclaration || declaration is KSPropertyDeclaration || declaration is KSClassDeclaration) {
99+
logger.warn(
100+
"python-multiplatform-ksp: ${declaration.simpleName.asString()} is in the root package " +
101+
"and is not exposed to Python (generated code in a named package cannot refer to it); " +
102+
"give its file a `package` declaration to expose it.",
103+
declaration,
104+
)
105+
}
106+
return@forEach
107+
}
94108
when (declaration) {
95109
is KSFunctionDeclaration ->
96110
if (BindingPolicy.isExposedTopLevelFunction(declaration, excludePackages) &&

0 commit comments

Comments
 (0)