diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt index c8a1206944f..f6d3127b423 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt @@ -210,21 +210,22 @@ class FunctionReader( FunctionWithWrapper(functionExpr, null) } val moduleReference = moduleNameMap[tag]?.deepCopy() ?: currentModuleName.makeRef() + val wrapperStatements = wrapper?.statements?.filter { it !is JsReturn } val sourceMap = info.sourceMap if (sourceMap != null) { val remapper = SourceMapLocationRemapper(sourceMap) remapper.remap(function) - wrapper?.let { remapper.remap(it) } + wrapperStatements?.forEach { remapper.remap(it) } } val replacements = hashMapOf(info.moduleVariable to moduleReference, info.kotlinVariable to Namer.kotlinObject()) replaceExternalNames(function, replacements) - wrapper?.let { replaceExternalNames(it, replacements) } + wrapperStatements?.forEach { replaceExternalNames(it, replacements) } function.markInlineArguments(descriptor) - val namesWithoutSizeEffects = wrapper?.statements.orEmpty().asSequence() + val namesWithoutSizeEffects = wrapperStatements.orEmpty().asSequence() .flatMap { collectDefinedNames(it).asSequence() } .toSet() function.accept(object : RecursiveJsVisitor() { diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/NameReplacingVisitor.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/NameReplacingVisitor.kt index 0a38948cff0..a819754977d 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/NameReplacingVisitor.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/NameReplacingVisitor.kt @@ -23,8 +23,11 @@ class NameReplacingVisitor(private val replaceMap: Map) : override fun endVisit(x: JsNameRef, ctx: JsContext) { if (x.qualifier != null) return val replacement = replaceMap[x.name] ?: return - val replacementCopy = accept(replacement.deepCopy().source(x.source)) - ctx.replaceMe(replacementCopy) + val replacementCopy = replacement.deepCopy() + if (x.source != null) { + replacementCopy.source = x.source + } + ctx.replaceMe(accept(replacementCopy)) } override fun endVisit(x: JsVars.JsVar, ctx: JsContext<*>) = applyToNamedNode(x) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsLineNumberTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsLineNumberTest.kt index 6f1e9afe348..efd9f343e02 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsLineNumberTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsLineNumberTest.kt @@ -40,8 +40,6 @@ import org.jetbrains.kotlin.js.test.utils.LineCollector import org.jetbrains.kotlin.js.test.utils.LineOutputToStringVisitor import org.jetbrains.kotlin.js.util.TextOutputImpl import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor -import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestWithEnvironment @@ -91,17 +89,13 @@ abstract class AbstractJsLineNumberTest : KotlinTestWithEnvironment() { writeText(generatedCode) } - File(baseOutputPath + ".js").writeText(translationResult.program.globalBlock.toString()) - - val moduleDescription = JsModuleDescriptor( - name = module.name, - data = translationResult.moduleDescriptor, - kind = ModuleKind.PLAIN, - imported = emptyList() - ) - val metaFileContent = KotlinJavascriptSerializationUtil.metadataAsString( - translationResult.bindingContext, moduleDescription) - File(baseOutputPath + ".meta.js").writeText(metaFileContent) + val baseDir = File(baseOutputPath).parentFile + for (outputFile in translationResult.getOutputFiles(File(baseOutputPath + ".js"), null, null).asList()) { + with (File(baseDir, outputFile.relativePath)) { + parentFile.mkdirs() + writeBytes(outputFile.asByteArray()) + } + } val linesMatcher = module.files .mapNotNull { LINES_PATTERN.find(File(it.fileName).readText()) } @@ -118,15 +112,12 @@ abstract class AbstractJsLineNumberTest : KotlinTestWithEnvironment() { } } - private fun TestModule.outputFileName(file: File): String { - return outputPath(file) + "-" + name - } + private fun TestModule.outputFileName(file: File): String = outputPath(file) + "-" + name private fun outputPath(file: File) = File(OUT_PATH, file.relativeTo(File(BASE_PATH)).path.removeSuffix(".kt")).path - override fun createEnvironment(): KotlinCoreEnvironment { - return KotlinCoreEnvironment.createForTests(testRootDisposable, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES) - } + override fun createEnvironment(): KotlinCoreEnvironment = + KotlinCoreEnvironment.createForTests(testRootDisposable, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES) private fun createConfig(module: TestModule, inputFile: File, modules: Map): JsConfig { val dependencies = module.dependencies @@ -135,13 +126,14 @@ abstract class AbstractJsLineNumberTest : KotlinTestWithEnvironment() { val configuration = environment.configuration.copy() - configuration.put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST + dependencies ) + configuration.put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST + dependencies) configuration.put(CommonConfigurationKeys.MODULE_NAME, module.name) configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN) configuration.put(JSConfigurationKeys.TARGET, EcmaVersion.v5) configuration.put(JSConfigurationKeys.SOURCE_MAP, true) + configuration.put(JSConfigurationKeys.META_INFO, true) return JsConfig(project, configuration) } @@ -154,8 +146,8 @@ abstract class AbstractJsLineNumberTest : KotlinTestWithEnvironment() { } private inner class TestFileFactoryImpl : KotlinTestUtils.TestFileFactory, Closeable { - val tmpDir = KotlinTestUtils.tmpDir("js-tests") - val defaultModule = TestModule(BasicBoxTest.TEST_MODULE, emptyList()) + private val tmpDir = KotlinTestUtils.tmpDir("js-tests") + private val defaultModule = TestModule(BasicBoxTest.TEST_MODULE, emptyList()) override fun createFile(module: TestModule?, fileName: String, text: String, directives: Map): TestFile? { val currentModule = module ?: defaultModule @@ -168,9 +160,7 @@ abstract class AbstractJsLineNumberTest : KotlinTestWithEnvironment() { return TestFile(temporaryFile.absolutePath, currentModule) } - override fun createModule(name: String, dependencies: List, friends: List): TestModule? { - return TestModule(name, dependencies) - } + override fun createModule(name: String, dependencies: List, friends: List) = TestModule(name, dependencies) override fun close() { FileUtil.delete(tmpDir) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt index 15d9a359756..830692a1af7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt @@ -500,7 +500,7 @@ abstract class BasicBoxTest( configuration.put(JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER, IncrementalResultsConsumerImpl()) } - configuration.put(JSConfigurationKeys.SOURCE_MAP, hasFilesToRecompile || generateSourceMap) + configuration.put(JSConfigurationKeys.SOURCE_MAP, true) configuration.put(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, sourceDirs) configuration.put(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, module.sourceMapSourceEmbedding) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt index b86e1aadfb3..0519f5a183b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi +import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.PsiSourceFile fun TranslationContext.translateAndAliasParameters( @@ -101,9 +102,10 @@ fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, fun } fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: FunctionDescriptor): JsExpression { + val sourceInfo = descriptor.source.getPsi() return if (descriptor.isInline && descriptor.isEffectivelyPublicApi) { val metadata = InlineMetadata.compose(function, descriptor, this) - val functionWithMetadata = metadata.functionWithMetadata + val functionWithMetadata = metadata.functionWithMetadata(sourceInfo) config.configuration[JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER]?.apply { val psiFile = (descriptor.source.containingFile as? PsiSourceFile)?.psiFile ?: return@apply @@ -134,6 +136,6 @@ fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: else { null } - if (block != null) InlineMetadata.wrapFunction(FunctionWithWrapper(function, block)) else function + if (block != null) InlineMetadata.wrapFunction(FunctionWithWrapper(function, block), sourceInfo) else function } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/InlineMetadata.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/InlineMetadata.kt index e797461b6ae..6398f583e8a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/InlineMetadata.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/InlineMetadata.kt @@ -78,15 +78,22 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper } @JvmStatic - fun wrapFunction(function: FunctionWithWrapper): JsExpression { + fun wrapFunction(function: FunctionWithWrapper, sourceInfo: Any?): JsExpression { val wrapperBody = function.wrapperBody ?: JsBlock(JsReturn(function.function)) val wrapper = JsFunction(function.function.scope, wrapperBody, "") - return JsInvocation(Namer.wrapFunction(), wrapper) + function.wrapperBody?.statements?.forEach { + if (it is JsExpressionStatement) { + it.expression.source = sourceInfo + } + else { + it.source = sourceInfo + } + } + + return JsInvocation(Namer.wrapFunction(), wrapper).source(sourceInfo) } } - val functionWithMetadata: JsExpression - get() { - return JsInvocation(Namer.createInlineFunction(), tag, wrapFunction(function)) - } + fun functionWithMetadata(sourceInfo: Any?): JsExpression = + JsInvocation(Namer.createInlineFunction(), tag, wrapFunction(function, sourceInfo)) } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt index e506c93ff78..b958f44c4ca 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunc import org.jetbrains.kotlin.js.translate.utils.addFunctionButNotExport import org.jetbrains.kotlin.js.translate.utils.fillCoroutineMetadata import org.jetbrains.kotlin.js.translate.utils.finalElement +import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils @@ -77,7 +78,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato name.staticRef = lambdaCreator lambdaCreator.fillCoroutineMetadata(invokingContext, descriptor) lambdaCreator.source = declaration - return lambdaCreator.withCapturedParameters(functionContext, name, invokingContext) + return lambdaCreator.withCapturedParameters(functionContext, name, invokingContext, declaration) } if (descriptor in tracker.capturedDescriptors) { @@ -89,7 +90,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato lambda.isLocal = true - invokingContext.addFunctionDeclaration(name, lambda) + invokingContext.addFunctionDeclaration(name, lambda, declaration) lambda.fillCoroutineMetadata(invokingContext, descriptor) name.staticRef = lambda return JsAstUtils.pureFqn(name, null) @@ -111,9 +112,9 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato } } -private fun TranslationContext.addFunctionDeclaration(name: JsName, function: JsFunction) { +private fun TranslationContext.addFunctionDeclaration(name: JsName, function: JsFunction, source: Any?) { addFunctionButNotExport(name, if (isPublicInlineFunction) { - InlineMetadata.wrapFunction(FunctionWithWrapper(function, null)) + InlineMetadata.wrapFunction(FunctionWithWrapper(function, null), source) } else { function @@ -123,9 +124,10 @@ private fun TranslationContext.addFunctionDeclaration(name: JsName, function: Js fun JsFunction.withCapturedParameters( context: TranslationContext, functionName: JsName, - invokingContext: TranslationContext + invokingContext: TranslationContext, + source: KtDeclaration ): JsExpression { - context.addFunctionDeclaration(functionName, this) + context.addFunctionDeclaration(functionName, this, source) val ref = JsAstUtils.pureFqn(functionName, null) val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index f9c00294905..45ccb8921e0 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.js.translate.utils; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; @@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; +import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; @@ -62,7 +64,8 @@ public final class TranslationUtils { JsExpression functionExpression = function; if (InlineUtil.isInline(descriptor)) { InlineMetadata metadata = InlineMetadata.compose(function, descriptor, context); - functionExpression = metadata.getFunctionWithMetadata(); + PsiElement sourceInfo = KotlinSourceElementKt.getPsi(descriptor.getSource()); + functionExpression = metadata.functionWithMetadata(sourceInfo); } if (DescriptorUtils.isExtension(descriptor) || diff --git a/js/js.translator/testData/lineNumbers/charBoxing.kt b/js/js.translator/testData/lineNumbers/charBoxing.kt index 1469ab9b2ae..021a40e63d9 100644 --- a/js/js.translator/testData/lineNumbers/charBoxing.kt +++ b/js/js.translator/testData/lineNumbers/charBoxing.kt @@ -17,4 +17,4 @@ fun bar(a: String, b: Char, x: Int) { a.foo(b) } -// LINES: 6 4 4 5 5 11 9 9 10 10 18 14 14 14 14 14 15 17 17 9 9 14 10 17 10 14 14 * 1 * 1 \ No newline at end of file +// LINES: 6 4 4 5 5 8 8 8 8 8 11 9 9 10 10 18 14 14 14 14 14 15 17 17 9 9 14 10 17 10 14 14 * 1 * 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlineLocalVarsRef.kt b/js/js.translator/testData/lineNumbers/inlineLocalVarsRef.kt index ba859705f8a..490dd46f90f 100644 --- a/js/js.translator/testData/lineNumbers/inlineLocalVarsRef.kt +++ b/js/js.translator/testData/lineNumbers/inlineLocalVarsRef.kt @@ -9,4 +9,4 @@ fun bar() { foo(42) } -// LINES: 6 2 2 3 3 4 4 10 2 2 9 2 3 3 4 4 \ No newline at end of file +// LINES: 1 1 1 1 1 6 2 2 3 3 4 4 10 2 2 9 2 3 3 4 4 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlineMultiModule/simple.kt b/js/js.translator/testData/lineNumbers/inlineMultiModule/simple.kt index c038c6490c3..dd0faaf7daf 100644 --- a/js/js.translator/testData/lineNumbers/inlineMultiModule/simple.kt +++ b/js/js.translator/testData/lineNumbers/inlineMultiModule/simple.kt @@ -8,7 +8,7 @@ inline fun foo(x: String) { println("foo2($x);") } -// LINES: 9 7 7 8 8 +// LINES: 6 6 6 6 6 9 7 7 8 8 // MODULE: main(lib) // FILE: main.kt @@ -21,4 +21,4 @@ fun box() { foo("42") } -// LINES: 22 7 7 20 7 8 8 20 8 7 7 21 7 8 8 21 8 \ No newline at end of file +// LINES: 6 6 22 7 7 20 7 8 8 20 8 7 7 21 7 8 8 21 8 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlineReturn.kt b/js/js.translator/testData/lineNumbers/inlineReturn.kt index e97a0a24111..f090e20b336 100644 --- a/js/js.translator/testData/lineNumbers/inlineReturn.kt +++ b/js/js.translator/testData/lineNumbers/inlineReturn.kt @@ -21,4 +21,4 @@ fun bar(x: Int) { println("%") } -// LINES: 17 2 2 3 3 4 7 7 9 9 10 10 11 14 14 16 16 22 20 20 20 20 2 2 3 3 4 3 7 7 9 9 10 10 11 10 14 14 16 16 * 20 21 21 \ No newline at end of file +// LINES: 1 1 1 1 1 1 1 17 2 2 3 3 4 7 7 9 9 10 10 11 14 14 16 16 22 20 20 20 20 2 2 3 3 4 3 7 7 9 9 10 10 11 10 14 14 16 16 * 20 21 21 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlining.kt b/js/js.translator/testData/lineNumbers/inlining.kt index 135094db7b6..6d2f4359a9b 100644 --- a/js/js.translator/testData/lineNumbers/inlining.kt +++ b/js/js.translator/testData/lineNumbers/inlining.kt @@ -11,4 +11,4 @@ inline fun bar() { println("bar2") } -// LINES: 7 2 2 10 10 11 11 4 4 10 10 11 11 6 6 12 10 10 11 11 +// LINES: 7 2 2 10 10 11 11 4 4 10 10 11 11 6 6 9 9 9 9 9 12 10 10 11 11 diff --git a/js/js.translator/testData/lineNumbers/inliningWithLambda.kt b/js/js.translator/testData/lineNumbers/inliningWithLambda.kt index 38d5bd3afe3..e2cda349b96 100644 --- a/js/js.translator/testData/lineNumbers/inliningWithLambda.kt +++ b/js/js.translator/testData/lineNumbers/inliningWithLambda.kt @@ -16,4 +16,4 @@ inline fun foo(f: () -> Unit) { println("after") } -// LINES: 11 2 2 14 14 4 4 16 16 6 6 14 14 8 8 16 16 10 10 17 14 14 15 15 16 16 \ No newline at end of file +// LINES: 11 2 2 14 14 4 4 16 16 6 6 14 14 8 8 16 16 10 10 13 13 13 13 13 17 14 14 15 15 16 16 \ No newline at end of file