KT-63269: implementation for SIRGenerator with top-level functions

KT-63269: add test generator

Merge-request: KT-MR-12945
Merged-by: Artem Olkov <artem.olkov@jetbrains.com>
This commit is contained in:
Artem Olkov
2023-11-16 17:42:39 +00:00
committed by Space Team
parent cc14f11e2a
commit 7c15e3f229
18 changed files with 314 additions and 37 deletions
@@ -0,0 +1,33 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
sourceSets {
"main" { java.srcDirs("main") }
"test" { projectDefault() }
}
dependencies {
testApi(projectTests(":native:swift:sir-analysis-api"))
testImplementation(projectTests(":generators:test-generator"))
testRuntimeOnly(projectTests(":analysis:analysis-test-framework"))
testImplementation(libs.junit.jupiter.api)
}
val generateSirAnalysisApiTests by generator("org.jetbrains.kotlin.generators.tests.native.swift.sir.analysis.api.GenerateSirAnalysisApiTestsKt")
testsJar()
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-receivers")
}
}
projectTest(jUnitMode = JUnitMode.JUnit5) {
workingDir = rootDir
useJUnitPlatform { }
}
@@ -0,0 +1,26 @@
/*
* 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.generators.tests.native.swift.sir.analysis.api
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
import org.jetbrains.kotlin.sir.analysisapi.AbstractKotlinSirContextTest
fun main() {
System.setProperty("java.awt.headless", "true")
generateTestGroupSuiteWithJUnit5 {
testGroup(
"native/swift/sir-analysis-api/tests-gen/",
"native/swift/sir-analysis-api/testData"
) {
testClass<AbstractKotlinSirContextTest>(
suiteTestClassName = "SirAnalysisGeneratedTests"
) {
model("", pattern = "^([^_](.+)).kt$", recursive = false)
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
# Build Swift IR from Analysis API
This module is responsible for populating SIR tree. It is the first step in Swift Export pipeline.
Input:
It should be possible to populate SIR from two types of artefacts:
1/ Kotlin Source Module
2/ KLib (currently not supported)
## Dev guide
### How to generate tests:
```bash
./gradlew :generators:sir-analysis-api-generator:generateSirAnalysisApiTests
```
this will generate test by their input files. Input files could be found and should be placed here - `native/swift/sir-analysis-api/testData`
The test expects to find `.sir` file, containing serialized SIR for the test-case. Name of the `.sir` file should be the same as a name of corresponding `.kt` file.
The project for the generator can be found here - `generators/sir-analysis-api-generator/build.gradle.kts`
### How to run tests:
```bash
./gradlew :native:swift:sir-analysis-api:test --tests "*"
```
OR just open `SirAnalysisGeneratedTests` in IDEA and start them from gutter.
### Project Setup
No additional setup required to develop this project.
+30 -4
View File
@@ -2,19 +2,45 @@ plugins {
kotlin("jvm")
}
description = "Build Swift IR from Analysis"
description = "Build Swift IR from Analysis API"
dependencies {
compileOnly(kotlinStdlib())
api(project(":native:swift:sir"))
api(project(":analysis:analysis-api"))
implementation(project(":analysis:analysis-api-standalone"))
testImplementation(libs.junit4)
testApi(platform(libs.junit.bom))
testRuntimeOnly(libs.junit.jupiter.engine)
testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(projectTests(":analysis:low-level-api-fir"))
testRuntimeOnly(projectTests(":analysis:analysis-api-impl-base"))
testImplementation(projectTests(":analysis:analysis-api-fir"))
testImplementation(projectTests(":analysis:analysis-test-framework"))
testImplementation(projectTests(":compiler:tests-common"))
testImplementation(projectTests(":compiler:tests-common-new"))
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
"test" {
projectDefault()
generatedTestDir()
}
}
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-receivers")
}
}
projectTest(jUnitMode = JUnitMode.JUnit5) {
workingDir = rootDir
useJUnitPlatform { }
}
testsJar()
@@ -5,11 +5,41 @@
package org.jetbrains.kotlin.sir.analysisapi
import org.jetbrains.kotlin.sir.SirElement
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.isPublic
import org.jetbrains.kotlin.sir.SirDeclaration
import org.jetbrains.kotlin.sir.SirForeignFunction
/**
* A root interface for classes that produce Swift IR elements.
*/
interface SirFactory {
fun build(): SirElement
}
fun build(fromFile: KtFile): List<SirDeclaration>
}
class SirGenerator : SirFactory {
override fun build(fromFile: KtFile): List<SirDeclaration> = analyze(fromFile) {
val res = mutableListOf<SirForeignFunction>()
fromFile.accept(Visitor(res))
return res.toList()
}
private class Visitor(val res: MutableList<SirForeignFunction>) : KtTreeVisitorVoid() {
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
function
.takeIf { function.isPublic }
?.fqName
?.pathSegments()
?.toListString()
?.let { names -> SirForeignFunction(fqName = names) }
?.let { res.add(it) }
}
}
}
private fun List<Name>.toListString() = map { it.asString() }
@@ -0,0 +1,12 @@
// FILE: one.kt
package namespace
fun foo(arg1: Int) = println("")
fun foo(arg1: Double) = println("")
// FILE: two.kt
package other.namespace
fun foo(arg1: Int) = println("")
fun foo(arg1: Double) = println("")
@@ -0,0 +1,4 @@
[namespace, foo]
[namespace, foo]
[other, namespace, foo]
[other, namespace, foo]
@@ -0,0 +1,12 @@
// FILE: one.kt
package com.awesome.namespace
fun foo() = println("")
fun bar() = ""
// FILE: two.kt
package com.awesome.other.namespace
fun foo() = ""
@@ -0,0 +1,3 @@
[com, awesome, namespace, foo]
[com, awesome, namespace, bar]
[com, awesome, other, namespace, foo]
@@ -0,0 +1,3 @@
public fun foo_public() = println("")
internal fun foo_internal() = println("")
private fun foo_private() = println("")
@@ -0,0 +1 @@
[foo_public]
@@ -0,0 +1 @@
fun foo() = println("")
@@ -0,0 +1 @@
[foo]
@@ -0,0 +1,50 @@
/*
* 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.sir.analysisapi;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.native.swift.sir.analysis.api.GenerateSirAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/swift/sir-analysis-api/testData")
@TestDataPath("$PROJECT_ROOT")
public class SirAnalysisGeneratedTests extends AbstractKotlinSirContextTest {
@Test
public void testAllFilesPresentInTestData() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/swift/sir-analysis-api/testData"), Pattern.compile("^([^_](.+)).kt$"), null, false);
}
@Test
@TestMetadata("functions_overload.kt")
public void testFunctions_overload() throws Exception {
runTest("native/swift/sir-analysis-api/testData/functions_overload.kt");
}
@Test
@TestMetadata("namespaced_functions.kt")
public void testNamespaced_functions() throws Exception {
runTest("native/swift/sir-analysis-api/testData/namespaced_functions.kt");
}
@Test
@TestMetadata("should_ignore_not_public_functions.kt")
public void testShould_ignore_not_public_functions() throws Exception {
runTest("native/swift/sir-analysis-api/testData/should_ignore_not_public_functions.kt");
}
@Test
@TestMetadata("simple_function.kt")
public void testSimple_function() throws Exception {
runTest("native/swift/sir-analysis-api/testData/simple_function.kt");
}
}
@@ -0,0 +1,64 @@
/*
* 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.sir.analysisapi
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory
import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiBasedTest
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.*
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind
import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.sir.SirForeignFunction
import org.jetbrains.kotlin.sir.SirModule
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
open class AbstractKotlinSirContextTest : AbstractKotlinSirContextTestBase() {
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
with(builder) {
globalDefaults {
targetPlatform = NativePlatforms.unspecifiedNativePlatform
}
}
}
override val configurator: AnalysisApiTestConfigurator
get() = AnalysisApiFirTestConfiguratorFactory.createConfigurator(
AnalysisApiTestConfiguratorFactoryData(
FrontendKind.Fir,
TestModuleKind.Source,
AnalysisSessionMode.Normal,
AnalysisApiMode.Ide
)
);
}
abstract class AbstractKotlinSirContextTestBase : AbstractAnalysisApiBasedTest() {
override fun doTestByModuleStructure(moduleStructure: TestModuleStructure, testServices: TestServices) {
val ktFiles = moduleStructure.modules
.flatMap { testServices.ktModuleProvider.getModuleFiles(it).filterIsInstance<KtFile>() }
val module = SirModule()
val sirFactory = SirGenerator()
ktFiles.forEach { file ->
module.declarations += sirFactory.build(file)
}
val actual = buildString {
module.declarations
.filterIsInstance<SirForeignFunction>()
.forEach {
appendLine("${it.fqName}")
}
}
testServices.assertions.assertEqualsToTestDataFileSibling(actual, extension = ".sir")
}
}
@@ -1,28 +0,0 @@
/*
* 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.sir.analysisapi
import org.jetbrains.kotlin.sir.SirElement
import org.junit.Test
import kotlin.test.assertEquals
class FactoryTests {
@Test
fun smoke() {
val expectedString = "Element from factory"
val myFactory = object : SirFactory {
override fun build(): SirElement {
return object : SirElement {
override fun toString(): String {
return expectedString
}
}
}
}
val element = myFactory.build()
assertEquals(expectedString, element.toString())
}
}
@@ -9,4 +9,13 @@ package org.jetbrains.kotlin.sir
* A marker interface that denotes Swift IR elements.
*/
interface SirElement {
}
}
class SirModule : SirElement {
val declarations: MutableList<SirDeclaration> =
mutableListOf()
}
interface SirDeclaration
class SirForeignFunction(val fqName: List<String>) : SirDeclaration
+2 -1
View File
@@ -400,7 +400,8 @@ include ":plugins:compose-compiler-plugin:compiler",
// Swift Export modules
include ":native:swift:sir",
":native:swift:sir-passes",
":native:swift:sir-analysis-api"
":native:swift:sir-analysis-api",
":generators:sir-analysis-api-generator"
void intellij(String imlPath) {
File imlFile = new File("${rootDir}/intellij/community/plugins/kotlin/${imlPath}")