[JS IR] Take into account file annotations for calculating symbol hashes

^KT-55367 Fixed
This commit is contained in:
Alexander Korepanov
2022-12-09 13:06:34 +01:00
committed by Space Team
parent 4136189114
commit 48daf0befe
39 changed files with 280 additions and 81 deletions
@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.converters.ClassicJsBackendFacade
import org.jetbrains.kotlin.js.test.utils.MODULE_EMULATION_FILE
import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
@@ -49,9 +51,9 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
private const val BOX_FUNCTION_NAME = "box"
private const val STDLIB_MODULE_NAME = "kotlin-kotlin-stdlib-js-ir"
private val KT_FILE_IGNORE_PATTERN = Regex("^.*\\..+\\.kt$")
private val TEST_FILE_IGNORE_PATTERN = Regex("^.*\\..+\\.\\w\\w$")
private val JS_MODULE_KIND = ModuleKind.PLAIN
private val JS_MODULE_KIND = ModuleKind.COMMON_JS
}
override fun createEnvironment(): KotlinCoreEnvironment {
@@ -66,6 +68,9 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
return ModuleInfoParser(infoFile).parse(moduleName)
}
private val File.filesInDir
get() = listFiles() ?: error("cannot retrieve the file list for $absolutePath directory")
protected fun doTest(testPath: String) {
val testDirectory = File(testPath)
val testName = testDirectory.name
@@ -84,10 +89,11 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
val workingDir = testWorkingDir(projectInfo.name)
val sourceDir = File(workingDir, "sources").also { it.invalidateDir() }
val buildDir = File(workingDir, "build").also { it.invalidateDir() }
val jsDir = File(workingDir, "js").also { it.invalidateDir() }
initializeWorkingDir(projectInfo, testDirectory, sourceDir, buildDir)
ProjectStepsExecutor(projectInfo, modulesInfos, testDirectory, sourceDir, buildDir).execute()
ProjectStepsExecutor(projectInfo, modulesInfos, testDirectory, sourceDir, buildDir, jsDir).execute()
}
private fun resolveModuleArtifact(moduleName: String, buildDir: File): File {
@@ -121,7 +127,8 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
private val moduleInfos: Map<String, ModuleInfo>,
private val testDir: File,
private val sourceDir: File,
private val buildDir: File
private val buildDir: File,
private val jsDir: File
) {
private inner class TestStepInfo(
val moduleName: String,
@@ -214,26 +221,46 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
}
}
fun writeJsFile(name: String, text: String): String {
val file = File(buildDir, "$name.js")
private fun File.writeAsJsModule(jsCode: String, moduleName: String) {
writeText(ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, JS_MODULE_KIND, moduleName))
}
private fun writeJsFile(name: String, text: String): String {
val moduleFileName = "./$name.js"
val file = File(jsDir, moduleFileName)
if (file.exists()) {
file.delete()
}
file.writeText(text)
file.writeAsJsModule(text, moduleFileName)
return file.canonicalPath
}
private fun prepareExternalJsFiles(): MutableList<String> {
jsDir.invalidateDir()
return testDir.filesInDir.mapNotNullTo(mutableListOf(MODULE_EMULATION_FILE)) { file ->
file.takeIf { it.name.isAllowedJsFile() }?.readText()?.let { jsCode ->
val externalModule = jsDir.resolve(file.name)
externalModule.writeAsJsModule(jsCode, file.nameWithoutExtension)
externalModule.canonicalPath
}
}
}
private fun verifyJsCode(stepId: Int, mainModuleName: String, jsOutput: CompilationOutputs) {
val files = jsOutput.dependencies.map { writeJsFile(it.first, it.second.jsCode) } + writeJsFile(mainModuleName, jsOutput.jsCode)
val files = prepareExternalJsFiles()
jsOutput.dependencies.mapTo(files) { writeJsFile(it.first, it.second.jsCode) }
files += writeJsFile(mainModuleName, jsOutput.jsCode)
try {
V8IrJsTestChecker.checkWithTestFunctionArgs(
files = files,
testModuleName = mainModuleName,
testModuleName = "./$mainModuleName.js",
testPackageName = null,
testFunctionName = BOX_FUNCTION_NAME,
testFunctionArgs = "$stepId",
expectedResult = "OK",
withModuleSystem = false
withModuleSystem = true
)
} catch (e: ComparisonFailure) {
throw ComparisonFailure("Mismatched box out at step $stepId", e.expected, e.actual)
@@ -298,7 +325,9 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
}
}
private fun String.isAllowedKtFile() = endsWith(".kt") && !KT_FILE_IGNORE_PATTERN.matches(this)
private fun String.isAllowedKtFile() = endsWith(".kt") && !TEST_FILE_IGNORE_PATTERN.matches(this)
private fun String.isAllowedJsFile() = endsWith(".js") && !TEST_FILE_IGNORE_PATTERN.matches(this)
private fun File.filteredKtFiles(): Collection<File> {
assert(isDirectory && exists())
@@ -377,11 +406,10 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
File(buildDir, module).invalidateDir()
val testModuleDir = File(testDir, module)
testModuleDir.listFiles { _, fileName -> fileName.isAllowedKtFile() }!!.forEach { file ->
assert(!file.isDirectory)
val fileName = file.name
val workingFile = File(moduleSourceDir, fileName)
file.copyTo(workingFile)
testModuleDir.filesInDir.forEach { file ->
if (file.name.isAllowedKtFile()) {
file.copyTo(moduleSourceDir.resolve(file.name))
}
}
}
}
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurato
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
import java.io.File
private const val MODULE_EMULATION_FILE = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/moduleEmulation.js"
const val MODULE_EMULATION_FILE = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/moduleEmulation.js"
fun TestModule.getNameFor(filePath: String, testServices: TestServices): String {
return JsEnvironmentConfigurator.getJsArtifactSimpleName(testServices, name) + "-js-" + filePath
@@ -250,6 +250,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
runTest("js/js.translator/testData/incremental/invalidation/moveAndModifyInlineFunction/");
}
@TestMetadata("moveExternalDeclarationsBetweenJsModules")
public void testMoveExternalDeclarationsBetweenJsModules() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/moveExternalDeclarationsBetweenJsModules/");
}
@TestMetadata("moveFilesBetweenModules")
public void testMoveFilesBetweenModules() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/moveFilesBetweenModules/");
@@ -3,3 +3,4 @@ STEP 0:
added file: m.kt
STEP 1:
dependencies: lib1
updated imports: m.kt
@@ -1,8 +1,5 @@
MODULES: lib1, main
STEP 0:
STEP 0..1:
libs: lib1, main
dirty js: lib1, main
STEP 1:
libs: lib1, main
dirty js: lib1
@@ -0,0 +1,8 @@
(function (_) {
'use strict';
function externalDemoFunction() { return 3; }
_.externalDemoFunction = externalDemoFunction;
return _
}(module.exports));
@@ -0,0 +1,8 @@
(function (_) {
'use strict';
function externalDemoFunction() { return 0; }
_.externalDemoFunction = externalDemoFunction;
return _
}(module.exports));
@@ -0,0 +1,8 @@
(function (_) {
'use strict';
function externalDemoFunction() { return 2; }
_.externalDemoFunction = externalDemoFunction;
return _
}(module.exports));
@@ -0,0 +1,8 @@
(function (_) {
'use strict';
function externalDemoFunction() { return 1; }
_.externalDemoFunction = externalDemoFunction;
return _
}(module.exports));
@@ -0,0 +1,8 @@
(function (_) {
'use strict';
function externalDemoFunction() { return 5; }
_.externalDemoFunction = externalDemoFunction;
return _
}(module.exports));
@@ -0,0 +1,8 @@
(function (_) {
'use strict';
function externalDemoFunction() { return 4; }
_.externalDemoFunction = externalDemoFunction;
return _
}(module.exports));
@@ -0,0 +1,3 @@
@file:JsModule("js-module-a")
external fun externalDemoFunction(): Int
@@ -0,0 +1 @@
@file:JsModule("js-module-a")
@@ -0,0 +1,3 @@
@file:JsModule("js-module-a-new")
external fun externalDemoFunction(): Int
@@ -0,0 +1 @@
@file:JsModule("js-module-b")
@@ -0,0 +1,3 @@
@file:JsModule("js-module-b")
external fun externalDemoFunction(): Int
@@ -0,0 +1,3 @@
@file:JsModule("js-module-b-new")
external fun externalDemoFunction(): Int
@@ -0,0 +1 @@
fun demoFunction() = externalDemoFunction()
@@ -0,0 +1 @@
fun demoFunction() = -1
@@ -0,0 +1,32 @@
STEP 0:
modifications:
U : JsModuleA.0.kt -> JsModuleA.kt
U : JsModuleB.0.kt -> JsModuleB.kt
U : demo.0.kt -> demo.kt
added file: JsModuleA.kt, JsModuleB.kt, demo.kt
STEP 1:
modifications:
U : JsModuleA.1.kt -> JsModuleA.kt
U : JsModuleB.1.kt -> JsModuleB.kt
modified ir: JsModuleA.kt, JsModuleB.kt
updated imports: demo.kt
STEP 2:
modifications:
U : JsModuleB.2.kt -> JsModuleB.kt
modified ir: JsModuleB.kt
updated imports: demo.kt
STEP 3:
modifications:
U : demo.3.kt -> demo.kt
modified ir: demo.kt
STEP 4:
modifications:
U : JsModuleA.4.kt -> JsModuleA.kt
U : JsModuleB.0.kt -> JsModuleB.kt
modified ir: JsModuleA.kt, JsModuleB.kt
STEP 5:
modifications:
U : JsModuleA.1.kt -> JsModuleA.kt
modified ir: JsModuleA.kt
updated exports: JsModuleA.kt
STEP 6:
@@ -0,0 +1,3 @@
@file:JsModule("js-module-c")
external fun externalDemoFunction(): Int
@@ -0,0 +1,3 @@
@file:JsModule("js-module-c-new")
external fun externalDemoFunction(): Int
@@ -0,0 +1,28 @@
STEP 0:
dependencies: lib1
modifications:
U : test.0.kt -> test.kt
added file: test.kt
STEP 1..2:
dependencies: lib1
STEP 3:
dependencies: lib1
modifications:
U : test.3.kt -> test.kt
modified ir: test.kt
STEP 4:
dependencies: lib1
updated imports: test.kt
STEP 5:
dependencies: lib1
modifications:
U : JsModuleC.5.kt -> JsModuleC.kt
added file: JsModuleC.kt
updated exports: JsModuleC.kt
updated imports: test.kt
STEP 6:
dependencies: lib1
modifications:
U : JsModuleC.6.kt -> JsModuleC.kt
modified ir: JsModuleC.kt
updated imports: test.kt
@@ -0,0 +1 @@
fun testFunction() = demoFunction()
@@ -0,0 +1 @@
fun testFunction() = externalDemoFunction() + 1
@@ -0,0 +1,7 @@
fun box(stepId: Int): String {
val x = testFunction()
if (x != stepId) {
return "Fail: $x != $stepId"
}
return "OK"
}
@@ -0,0 +1,5 @@
STEP 0:
dependencies: lib1, lib2
added file: m.kt
STEP 1..6:
dependencies: lib1, lib2
@@ -0,0 +1,14 @@
MODULES: lib1, lib2, main
STEP 0:
libs: lib1, lib2, main
dirty js: lib1, lib2, main
STEP 1..2:
libs: lib1, lib2, main
dirty js: lib1
STEP 3..5:
libs: lib1, lib2, main
dirty js: lib1, lib2
STEP 6:
libs: lib1, lib2, main
dirty js: lib2
@@ -1,4 +1,2 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
function box(stepId: number): string;
}
type Nullable<T> = T | null | undefined
export declare function box(stepId: number): string;
@@ -1,5 +1,3 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
function foo(): number;
function box(stepId: number): string;
}
type Nullable<T> = T | null | undefined
export declare function foo(): number;
export declare function box(stepId: number): string;
@@ -1,5 +1,3 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
function bar(): number;
function box(stepId: number): string;
}
type Nullable<T> = T | null | undefined
export declare function bar(): number;
export declare function box(stepId: number): string;
@@ -1,10 +1,8 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
function bar(): number;
class MyClass {
constructor(stepId: number);
get stepId(): number;
qux(): number;
}
function box(stepId: number): string;
type Nullable<T> = T | null | undefined
export declare function bar(): number;
export declare class MyClass {
constructor(stepId: number);
get stepId(): number;
qux(): number;
}
export declare function box(stepId: number): string;
@@ -1,9 +1,7 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
class MyClass {
constructor(stepId: number);
get stepId(): number;
qux(): number;
}
function box(stepId: number): string;
type Nullable<T> = T | null | undefined
export declare class MyClass {
constructor(stepId: number);
get stepId(): number;
qux(): number;
}
export declare function box(stepId: number): string;
@@ -1,9 +1,7 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
class MyClass {
constructor(stepId: number);
get stepId(): number;
baz(): number;
}
function box(stepId: number): string;
type Nullable<T> = T | null | undefined
export declare class MyClass {
constructor(stepId: number);
get stepId(): number;
baz(): number;
}
export declare function box(stepId: number): string;
@@ -1,9 +1,7 @@
declare namespace kotlin_main {
type Nullable<T> = T | null | undefined
class MyClass {
constructor(stepId: number);
get stepId(): number;
bar(): number;
}
function box(stepId: number): string;
type Nullable<T> = T | null | undefined
export declare class MyClass {
constructor(stepId: number);
get stepId(): number;
bar(): number;
}
export declare function box(stepId: number): string;