From 68347e89cf242dfc664c4c035f9ce6cabc328f30 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Thu, 17 Jan 2019 12:36:06 +0300 Subject: [PATCH 01/33] Remove build script bunch for 191. The -Xjvm-default flag should be set in the whole project --- plugins/uast-kotlin/build.gradle.kts.191 | 80 ------------------------ 1 file changed, 80 deletions(-) delete mode 100644 plugins/uast-kotlin/build.gradle.kts.191 diff --git a/plugins/uast-kotlin/build.gradle.kts.191 b/plugins/uast-kotlin/build.gradle.kts.191 deleted file mode 100644 index 6bf6f04b122..00000000000 --- a/plugins/uast-kotlin/build.gradle.kts.191 +++ /dev/null @@ -1,80 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - kotlin("jvm") - id("jps-compatible") -} - -dependencies { - compile(project(":kotlin-stdlib")) - compile(project(":core:util.runtime")) - compile(project(":compiler:backend")) - compile(project(":compiler:frontend")) - compile(project(":compiler:frontend.java")) - compile(project(":compiler:light-classes")) - - Platform[181].orHigher { - // BEWARE: Uast should not depend on IDEA. - compileOnly(intellijCoreDep()) { includeJars("intellij-core") } - compileOnly(intellijDep()) { includeJars("java-api", "java-impl", "asm-all", rootProject = rootProject) } - } - - Platform[173].orLower { - compile(project(":idea:idea-core")) - compileOnly(intellijDep()) { includeJars("openapi", "idea", "util", "extensions", "asm-all", rootProject = rootProject) } - } - - testCompile(project(":kotlin-test:kotlin-test-jvm")) - testCompile(projectTests(":compiler:tests-common")) - testCompile(commonDep("junit:junit")) - testCompile(project(":compiler:util")) - testCompile(project(":compiler:cli")) - testCompile(projectTests(":idea:idea-test-framework")) - - Platform[181].orHigher { - testCompileOnly(intellijDep()) { includeJars("java-api", "java-impl") } - } - - Platform[173].orLower { - testCompileOnly(intellijDep()) { includeJars("idea_rt") } - } - - testCompile(project(":idea:idea-native")) { isTransitive = false } - testCompile(project(":idea:idea-gradle-native")) { isTransitive = false } - - testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-utils")) { isTransitive = false } - testRuntime(project(":kotlin-reflect")) - testRuntime(project(":idea:idea-android")) - testRuntime(project(":idea:idea-gradle")) - testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false } - testRuntime(project(":sam-with-receiver-ide-plugin")) - testRuntime(project(":allopen-ide-plugin")) - testRuntime(project(":noarg-ide-plugin")) - testRuntime(project(":kotlin-scripting-idea")) - testRuntime(project(":plugins:android-extensions-ide")) - testRuntime(project(":plugins:kapt3-idea")) - testRuntime(project(":kotlinx-serialization-ide-plugin")) - testRuntime(intellijDep()) - testRuntime(intellijPluginDep("junit")) - testRuntime(intellijPluginDep("gradle")) - testRuntime(intellijPluginDep("Groovy")) - testRuntime(intellijPluginDep("properties")) -} - -sourceSets { - "main" { projectDefault() } - "test" { projectDefault() } -} - -testsJar {} - -projectTest { - workingDir = rootDir -} - -val compileKotlin: KotlinCompile by tasks -compileKotlin.kotlinOptions { - freeCompilerArgs = listOf("-Xjvm-default=compatibility") -} - From 99de00362eec04efe4b4871c1d74616b8bc668e4 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Tue, 15 Jan 2019 17:02:44 +0300 Subject: [PATCH 02/33] Fix NSME during reimport of maven project #KT-29251 Fixed --- .../idea/maven/KotlinMavenImporter.kt.191 | 422 ++++++++++++++++++ 1 file changed, 422 insertions(+) create mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt.191 diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt.191 b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt.191 new file mode 100644 index 00000000000..c4f6f68bc2e --- /dev/null +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt.191 @@ -0,0 +1,422 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.maven + +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.StoragePathMacros +import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.* +import com.intellij.openapi.roots.impl.libraries.LibraryEx +import com.intellij.openapi.roots.libraries.Library +import com.intellij.util.PathUtil +import org.jdom.Element +import org.jdom.Text +import org.jetbrains.concurrency.AsyncPromise +import org.jetbrains.idea.maven.importing.MavenImporter +import org.jetbrains.idea.maven.importing.MavenRootModelAdapter +import org.jetbrains.idea.maven.model.MavenPlugin +import org.jetbrains.idea.maven.project.* +import org.jetbrains.jps.model.java.JavaSourceRootType +import org.jetbrains.jps.model.module.JpsModuleSourceRootType +import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments +import org.jetbrains.kotlin.compilerRunner.ArgumentUtils +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor +import org.jetbrains.kotlin.idea.facet.* +import org.jetbrains.kotlin.idea.framework.detectLibraryKind +import org.jetbrains.kotlin.idea.maven.configuration.KotlinMavenConfigurator +import org.jetbrains.kotlin.idea.platform.tooling +import org.jetbrains.kotlin.platform.IdePlatform +import org.jetbrains.kotlin.platform.IdePlatformKind +import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind +import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind +import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind +import org.jetbrains.kotlin.platform.impl.isCommon +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addIfNotNull +import java.io.File +import java.util.* + +interface MavenProjectImportHandler { + companion object : ProjectExtensionDescriptor( + "org.jetbrains.kotlin.mavenProjectImportHandler", + MavenProjectImportHandler::class.java + ) + + operator fun invoke(facet: KotlinFacet, mavenProject: MavenProject) +} + +class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID) { + companion object { + const val KOTLIN_PLUGIN_GROUP_ID = "org.jetbrains.kotlin" + const val KOTLIN_PLUGIN_ARTIFACT_ID = "kotlin-maven-plugin" + + const val KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG = "sourceDirs" + } + + override fun preProcess( + module: Module, + mavenProject: MavenProject, + changes: MavenProjectChanges, + modifiableModelsProvider: IdeModifiableModelsProvider + ) { + } + + override fun process( + modifiableModelsProvider: IdeModifiableModelsProvider, + module: Module, + rootModel: MavenRootModelAdapter, + mavenModel: MavenProjectsTree, + mavenProject: MavenProject, + changes: MavenProjectChanges, + mavenProjectToModuleName: MutableMap, + postTasks: MutableList + ) { + + if (changes.plugins) { + contributeSourceDirectories(mavenProject, module, rootModel) + } + } + + override fun postProcess( + module: Module, + mavenProject: MavenProject, + changes: MavenProjectChanges, + modifiableModelsProvider: IdeModifiableModelsProvider + ) { + super.postProcess(module, mavenProject, changes, modifiableModelsProvider) + + if (changes.dependencies) { + scheduleDownloadStdlibSources(mavenProject, module) + + val targetLibraryKind = detectPlatformByExecutions(mavenProject)?.tooling?.libraryKind + if (targetLibraryKind != null) { + modifiableModelsProvider.getModifiableRootModel(module).orderEntries().forEachLibrary { library -> + if ((library as LibraryEx).kind == null) { + val model = modifiableModelsProvider.getModifiableLibraryModel(library) as LibraryEx.ModifiableModelEx + detectLibraryKind(model.getFiles(OrderRootType.CLASSES))?.let { model.kind = it } + } + true + } + } + } + + configureFacet(mavenProject, modifiableModelsProvider, module) + } + + private fun scheduleDownloadStdlibSources(mavenProject: MavenProject, module: Module) { + // TODO: here we have to process all kotlin libraries but for now we only handle standard libraries + val artifacts = mavenProject.dependencyArtifactIndex.data[KOTLIN_PLUGIN_GROUP_ID]?.values?.flatMap { it.filter { it.isResolved } } + ?: emptyList() + + val librariesWithNoSources = ArrayList() + OrderEnumerator.orderEntries(module).forEachLibrary { library -> + if (library.modifiableModel.getFiles(OrderRootType.SOURCES).isEmpty()) { + librariesWithNoSources.add(library) + } + true + } + val libraryNames = librariesWithNoSources.mapTo(HashSet()) { it.name } + val toBeDownloaded = artifacts.filter { it.libraryName in libraryNames } + + if (toBeDownloaded.isNotEmpty()) { + MavenProjectsManager.getInstance(module.project) + .scheduleArtifactsDownloading(listOf(mavenProject), toBeDownloaded, true, false, AsyncPromise()) + } + } + + private fun configureJSOutputPaths( + mavenProject: MavenProject, + modifiableRootModel: ModifiableRootModel, + facetSettings: KotlinFacetSettings, + mavenPlugin: MavenPlugin + ) { + fun parentPath(path: String): String = + File(path).absoluteFile.parentFile.absolutePath + + val sharedOutputFile = mavenPlugin.configurationElement?.getChild("outputFile")?.text + + val compilerModuleExtension = modifiableRootModel.getModuleExtension(CompilerModuleExtension::class.java) ?: return + val buildDirectory = mavenProject.buildDirectory + + val executions = mavenPlugin.executions + + executions.forEach { + val explicitOutputFile = it.configurationElement?.getChild("outputFile")?.text ?: sharedOutputFile + if (PomFile.KotlinGoals.Js in it.goals) { + // see org.jetbrains.kotlin.maven.K2JSCompilerMojo + val outputFilePath = PathUtil.toSystemDependentName(explicitOutputFile ?: "$buildDirectory/js/${mavenProject.mavenId.artifactId}.js") + compilerModuleExtension.setCompilerOutputPath(parentPath(outputFilePath)) + facetSettings.productionOutputPath = outputFilePath + } + if (PomFile.KotlinGoals.TestJs in it.goals) { + // see org.jetbrains.kotlin.maven.KotlinTestJSCompilerMojo + val outputFilePath = PathUtil.toSystemDependentName(explicitOutputFile ?: "$buildDirectory/test-js/${mavenProject.mavenId.artifactId}-tests.js") + compilerModuleExtension.setCompilerOutputPathForTests(parentPath(outputFilePath)) + facetSettings.testOutputPath = outputFilePath + } + } + } + + private fun getCompilerArgumentsByConfigurationElement( + mavenProject: MavenProject, + configuration: Element?, + platform: IdePlatform<*, *> + ): List { + val arguments = platform.createArguments() + + arguments.apiVersion = configuration?.getChild("apiVersion")?.text ?: + mavenProject.properties["kotlin.compiler.apiVersion"]?.toString() + arguments.languageVersion = configuration?.getChild("languageVersion")?.text ?: + mavenProject.properties["kotlin.compiler.languageVersion"]?.toString() + arguments.multiPlatform = configuration?.getChild("multiPlatform")?.text?.trim()?.toBoolean() ?: false + arguments.suppressWarnings = configuration?.getChild("nowarn")?.text?.trim()?.toBoolean() ?: false + + configuration?.getChild("experimentalCoroutines")?.text?.trim()?.let { + arguments.coroutinesState = it + } + + when (arguments) { + is K2JVMCompilerArguments -> { + arguments.classpath = configuration?.getChild("classpath")?.text + arguments.jdkHome = configuration?.getChild("jdkHome")?.text + arguments.jvmTarget = configuration?.getChild("jvmTarget")?.text ?: + mavenProject.properties["kotlin.compiler.jvmTarget"]?.toString() + arguments.javaParameters = configuration?.getChild("javaParameters")?.text?.toBoolean() ?: false + } + is K2JSCompilerArguments -> { + arguments.sourceMap = configuration?.getChild("sourceMap")?.text?.trim()?.toBoolean() ?: false + arguments.sourceMapPrefix = configuration?.getChild("sourceMapPrefix")?.text?.trim() ?: "" + arguments.sourceMapEmbedSources = configuration?.getChild("sourceMapEmbedSources")?.text?.trim() ?: "inlining" + arguments.outputFile = configuration?.getChild("outputFile")?.text + arguments.metaInfo = configuration?.getChild("metaInfo")?.text?.trim()?.toBoolean() ?: false + arguments.moduleKind = configuration?.getChild("moduleKind")?.text + arguments.main = configuration?.getChild("main")?.text + } + } + + val additionalArgs = SmartList().apply { + val argsElement = configuration?.getChild("args") + + argsElement?.content?.forEach { argElement -> + when (argElement) { + is Text -> { + argElement.text?.let { addAll(splitArgumentString(it)) } + } + is Element -> { + if (argElement.name == "arg") { + addIfNotNull(argElement.text) + } + } + } + } + } + parseCommandLineArguments(additionalArgs, arguments) + + return ArgumentUtils.convertArgumentsToStringList(arguments) + } + + private val compilationGoals = listOf( + PomFile.KotlinGoals.Compile, + PomFile.KotlinGoals.TestCompile, + PomFile.KotlinGoals.Js, + PomFile.KotlinGoals.TestJs, + PomFile.KotlinGoals.MetaData + ) + + private fun configureFacet(mavenProject: MavenProject, modifiableModelsProvider: IdeModifiableModelsProvider, module: Module) { + val mavenPlugin = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID) ?: return + val compilerVersion = mavenPlugin.version ?: LanguageVersion.LATEST_STABLE.versionString + val kotlinFacet = module.getOrCreateFacet( + modifiableModelsProvider, + false, + ExternalProjectSystemRegistry.MAVEN_EXTERNAL_SOURCE_ID + ) + + // TODO There should be a way to figure out the correct platform version + val platform = detectPlatform(mavenProject)?.defaultPlatform + + kotlinFacet.configureFacet(compilerVersion, LanguageFeature.Coroutines.defaultState, platform, modifiableModelsProvider) + val facetSettings = kotlinFacet.configuration.settings + val configuredPlatform = kotlinFacet.configuration.settings.platform!! + val configuration = mavenPlugin.configurationElement + val sharedArguments = getCompilerArgumentsByConfigurationElement(mavenProject, configuration, configuredPlatform) + val executionArguments = mavenPlugin.executions + ?.firstOrNull { it.goals.any { it in compilationGoals } } + ?.configurationElement?.let { getCompilerArgumentsByConfigurationElement(mavenProject, it, configuredPlatform) } + parseCompilerArgumentsToFacet(sharedArguments, emptyList(), kotlinFacet, modifiableModelsProvider) + if (executionArguments != null) { + parseCompilerArgumentsToFacet(executionArguments, emptyList(), kotlinFacet, modifiableModelsProvider) + } + if (facetSettings.compilerArguments is K2JSCompilerArguments) { + configureJSOutputPaths(mavenProject, modifiableModelsProvider.getModifiableRootModel(module), facetSettings, mavenPlugin) + } + MavenProjectImportHandler.getInstances(module.project).forEach { it(kotlinFacet, mavenProject) } + setImplementedModuleName(kotlinFacet, mavenProject, module) + kotlinFacet.noVersionAutoAdvance() + } + + private fun detectPlatform(mavenProject: MavenProject) = + detectPlatformByExecutions(mavenProject) ?: detectPlatformByLibraries(mavenProject) + + private fun detectPlatformByExecutions(mavenProject: MavenProject): IdePlatformKind<*>? { + return mavenProject.findPlugin(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID)?.executions?.flatMap { it.goals } + ?.mapNotNull { goal -> + when (goal) { + PomFile.KotlinGoals.Compile, PomFile.KotlinGoals.TestCompile -> JvmIdePlatformKind + PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestJs -> JsIdePlatformKind + PomFile.KotlinGoals.MetaData -> CommonIdePlatformKind + else -> null + } + }?.distinct()?.singleOrNull() + } + + private fun detectPlatformByLibraries(mavenProject: MavenProject): IdePlatformKind<*>? { + for (kind in IdePlatformKind.ALL_KINDS) { + val mavenLibraryIds = kind.tooling.mavenLibraryIds + if (mavenLibraryIds.any { mavenProject.findDependencies(KOTLIN_PLUGIN_GROUP_ID, it).isNotEmpty() }) { + // TODO we could return here the correct version + return kind + } + } + + return null + } + + // TODO in theory it should work like this but it doesn't as it couldn't unmark source roots that are not roots anymore. + // I believe this is something should be done by the underlying maven importer implementation or somewhere else in the IDEA + // For now there is a contributeSourceDirectories implementation that deals with the issue + // see https://youtrack.jetbrains.com/issue/IDEA-148280 + + // override fun collectSourceRoots(mavenProject: MavenProject, result: PairConsumer>) { + // for ((type, dir) in collectSourceDirectories(mavenProject)) { + // val jpsType: JpsModuleSourceRootType<*> = when (type) { + // SourceType.PROD -> JavaSourceRootType.SOURCE + // SourceType.TEST -> JavaSourceRootType.TEST_SOURCE + // } + // + // result.consume(dir, jpsType) + // } + // } + + private fun contributeSourceDirectories(mavenProject: MavenProject, module: Module, rootModel: MavenRootModelAdapter) { + val directories = collectSourceDirectories(mavenProject) + + val toBeAdded = directories.map { it.second }.toSet() + val state = module.kotlinImporterComponent + + val isNonJvmModule = mavenProject + .plugins + .asSequence() + .filter { it.isKotlinPlugin() } + .flatMap { it.executions.asSequence() } + .flatMap { it.goals.asSequence() } + .any { it in PomFile.KotlinGoals.CompileGoals && it !in PomFile.KotlinGoals.JvmGoals } + + val prodSourceRootType: JpsModuleSourceRootType<*> = if (isNonJvmModule) KotlinSourceRootType.Source else JavaSourceRootType.SOURCE + val testSourceRootType: JpsModuleSourceRootType<*> = if (isNonJvmModule) KotlinSourceRootType.TestSource else JavaSourceRootType.TEST_SOURCE + + for ((type, dir) in directories) { + if (rootModel.getSourceFolder(File(dir)) == null) { + val jpsType: JpsModuleSourceRootType<*> = when (type) { + SourceType.TEST -> testSourceRootType + SourceType.PROD -> prodSourceRootType + } + + rootModel.addSourceFolder(dir, jpsType) + } + } + + if (isNonJvmModule) { + mavenProject.sources.forEach { rootModel.addSourceFolder(it, KotlinSourceRootType.Source) } + mavenProject.testSources.forEach { rootModel.addSourceFolder(it, KotlinSourceRootType.TestSource) } + mavenProject.resources.forEach { rootModel.addSourceFolder(it.directory, KotlinResourceRootType.Resource) } + mavenProject.testResources.forEach { rootModel.addSourceFolder(it.directory, KotlinResourceRootType.TestResource) } + } + + state.addedSources.filter { it !in toBeAdded }.forEach { + rootModel.unregisterAll(it, true, true) + state.addedSources.remove(it) + } + state.addedSources.addAll(toBeAdded) + } + + private fun collectSourceDirectories(mavenProject: MavenProject): List> = + mavenProject.plugins.filter { it.isKotlinPlugin() }.flatMap { plugin -> + plugin.configurationElement.sourceDirectories().map { SourceType.PROD to it } + + plugin.executions.flatMap { execution -> + execution.configurationElement.sourceDirectories().map { execution.sourceType() to it } + } + }.distinct() + + private fun setImplementedModuleName(kotlinFacet: KotlinFacet, mavenProject: MavenProject, module: Module) { + if (kotlinFacet.configuration.settings.platform.isCommon) { + kotlinFacet.configuration.settings.implementedModuleNames = emptyList() + } else { + val manager = MavenProjectsManager.getInstance(module.project) + val mavenDependencies = mavenProject.dependencies.mapNotNull { manager?.findProject(it) } + val implemented = mavenDependencies.filter { detectPlatformByExecutions(it).isCommon } + + kotlinFacet.configuration.settings.implementedModuleNames = implemented.map { manager.findModule(it)?.name ?: it.displayName } + } + } +} + +private fun MavenPlugin.isKotlinPlugin() = + groupId == KotlinMavenImporter.KOTLIN_PLUGIN_GROUP_ID && artifactId == KotlinMavenImporter.KOTLIN_PLUGIN_ARTIFACT_ID + +private fun Element?.sourceDirectories(): List = + this?.getChildren(KotlinMavenImporter.KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim } + ?: emptyList() + +private fun MavenPlugin.Execution.sourceType() = + goals.map { if (isTestGoalName(it)) SourceType.TEST else SourceType.PROD } + .distinct() + .singleOrNull() ?: SourceType.PROD + +private fun isTestGoalName(goalName: String) = goalName.startsWith("test-") + +private enum class SourceType { + PROD, TEST +} + +@State( + name = "AutoImportedSourceRoots", + storages = [(Storage(file = StoragePathMacros.MODULE_FILE))] +) +class KotlinImporterComponent : PersistentStateComponent { + class State(var directories: List = ArrayList()) + + val addedSources: MutableSet = Collections.synchronizedSet(HashSet()) + + override fun loadState(state: State) { + addedSources.clear() + addedSources.addAll(state.directories) + } + + override fun getState(): State { + return State(addedSources.sorted()) + } +} + +private val Module.kotlinImporterComponent: KotlinImporterComponent + get() = getComponent(KotlinImporterComponent::class.java) ?: throw IllegalStateException("No maven importer state configured") From 7da8c41f3fbfa4dfb8e2ef3631743a17dab32c95 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Tue, 15 Jan 2019 17:22:51 +0300 Subject: [PATCH 03/33] Remove build script bunches in idea/idea-maven --- idea/idea-maven/build.gradle.kts | 30 +++++++---- idea/idea-maven/build.gradle.kts.as32 | 68 ------------------------ idea/idea-maven/build.gradle.kts.as33 | 74 --------------------------- idea/idea-maven/build.gradle.kts.as34 | 74 --------------------------- 4 files changed, 21 insertions(+), 225 deletions(-) delete mode 100644 idea/idea-maven/build.gradle.kts.as32 delete mode 100644 idea/idea-maven/build.gradle.kts.as33 delete mode 100644 idea/idea-maven/build.gradle.kts.as34 diff --git a/idea/idea-maven/build.gradle.kts b/idea/idea-maven/build.gradle.kts index 3102a8f3160..eb7536a674a 100644 --- a/idea/idea-maven/build.gradle.kts +++ b/idea/idea-maven/build.gradle.kts @@ -26,7 +26,10 @@ dependencies { testCompile(projectTests(":idea:idea-test-framework")) testCompileOnly(intellijDep()) - testCompileOnly(intellijPluginDep("maven")) + if (Ide.IJ()) { + testCompileOnly(intellijPluginDep("maven")) + testRuntime(intellijPluginDep("maven")) + } testCompile(project(":idea:idea-native")) { isTransitive = false } testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false } @@ -51,14 +54,20 @@ dependencies { testRuntime(intellijPluginDep("gradle")) testRuntime(intellijPluginDep("Groovy")) testRuntime(intellijPluginDep("coverage")) - testRuntime(intellijPluginDep("maven")) testRuntime(intellijPluginDep("android")) testRuntime(intellijPluginDep("smali")) } -sourceSets { - "main" { projectDefault() } - "test" { projectDefault() } +if (Ide.IJ()) { + sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } + } +} else { + sourceSets { + "main" { } + "test" { } + } } testsJar() @@ -67,8 +76,11 @@ projectTest { workingDir = rootDir } -runtimeJar { - archiveName = "maven-ide.jar" -} -ideaPlugin() \ No newline at end of file +if (Ide.IJ()) { + runtimeJar { + archiveName = "maven-ide.jar" + } + + ideaPlugin() +} diff --git a/idea/idea-maven/build.gradle.kts.as32 b/idea/idea-maven/build.gradle.kts.as32 deleted file mode 100644 index 7d78a259b88..00000000000 --- a/idea/idea-maven/build.gradle.kts.as32 +++ /dev/null @@ -1,68 +0,0 @@ - -plugins { - kotlin("jvm") - id("jps-compatible") -} - -dependencies { - compile(project(":core:util.runtime")) - compile(project(":compiler:frontend")) - compile(project(":compiler:frontend.java")) - compile(project(":compiler:util")) - compile(project(":compiler:cli-common")) - compile(project(":kotlin-build-common")) - - compile(project(":js:js.frontend")) - - compile(project(":idea")) - compile(project(":idea:idea-jvm")) - compile(project(":idea:idea-jps-common")) - - compileOnly(intellijDep()) - excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) } - - testCompile(projectTests(":idea")) - testCompile(projectTests(":compiler:tests-common")) - testCompile(projectTests(":idea:idea-test-framework")) - - testCompileOnly(intellijDep()) - //testCompileOnly(intellijPluginDep("maven")) - - testCompile(project(":idea:idea-native")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-utils")) { isTransitive = false } - - testRuntime(project(":kotlin-reflect")) - testRuntime(project(":idea:idea-jvm")) - testRuntime(project(":idea:idea-android")) - testRuntime(project(":plugins:android-extensions-ide")) - testRuntime(project(":plugins:lint")) - testRuntime(project(":sam-with-receiver-ide-plugin")) - testRuntime(project(":allopen-ide-plugin")) - testRuntime(project(":noarg-ide-plugin")) - testRuntime(project(":kotlin-scripting-idea")) - testRuntime(project(":kotlinx-serialization-ide-plugin")) - - testRuntime(intellijDep()) - // TODO: the order of the plugins matters here, consider avoiding order-dependency - testRuntime(intellijPluginDep("junit")) - testRuntime(intellijPluginDep("testng")) - testRuntime(intellijPluginDep("properties")) - testRuntime(intellijPluginDep("gradle")) - testRuntime(intellijPluginDep("Groovy")) - testRuntime(intellijPluginDep("coverage")) - //testRuntime(intellijPluginDep("maven")) - testRuntime(intellijPluginDep("android")) - testRuntime(intellijPluginDep("smali")) -} - -sourceSets { - "main" { /*projectDefault()*/ } - "test" { /*projectDefault()*/ } -} - -testsJar() - -projectTest { - workingDir = rootDir -} diff --git a/idea/idea-maven/build.gradle.kts.as33 b/idea/idea-maven/build.gradle.kts.as33 deleted file mode 100644 index 4ecbe3f70dc..00000000000 --- a/idea/idea-maven/build.gradle.kts.as33 +++ /dev/null @@ -1,74 +0,0 @@ - -plugins { - kotlin("jvm") - id("jps-compatible") -} - -dependencies { - compile(project(":core:util.runtime")) - compile(project(":compiler:frontend")) - compile(project(":compiler:frontend.java")) - compile(project(":compiler:util")) - compile(project(":compiler:cli-common")) - compile(project(":kotlin-build-common")) - - compile(project(":js:js.frontend")) - - compile(project(":idea")) - compile(project(":idea:idea-jvm")) - compile(project(":idea:idea-jps-common")) - - compileOnly(intellijDep()) - excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) } - - testCompile(projectTests(":idea")) - testCompile(projectTests(":compiler:tests-common")) - testCompile(projectTests(":idea:idea-test-framework")) - - testCompileOnly(intellijDep()) - //testCompileOnly(intellijPluginDep("maven")) - - testCompile(project(":idea:idea-native")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-utils")) { isTransitive = false } - - testRuntime(project(":kotlin-reflect")) - testRuntime(project(":idea:idea-jvm")) - testRuntime(project(":idea:idea-android")) - testRuntime(project(":plugins:android-extensions-ide")) - testRuntime(project(":plugins:lint")) - testRuntime(project(":sam-with-receiver-ide-plugin")) - testRuntime(project(":allopen-ide-plugin")) - testRuntime(project(":noarg-ide-plugin")) - testRuntime(project(":kotlin-scripting-idea")) - testRuntime(project(":kotlinx-serialization-ide-plugin")) - - testRuntime(intellijDep()) - // TODO: the order of the plugins matters here, consider avoiding order-dependency - testRuntime(intellijPluginDep("junit")) - testRuntime(intellijPluginDep("testng")) - testRuntime(intellijPluginDep("properties")) - testRuntime(intellijPluginDep("gradle")) - testRuntime(intellijPluginDep("Groovy")) - testRuntime(intellijPluginDep("coverage")) - //testRuntime(intellijPluginDep("maven")) - testRuntime(intellijPluginDep("android")) - testRuntime(intellijPluginDep("smali")) -} - -sourceSets { - "main" { /*projectDefault()*/ } - "test" { /*projectDefault()*/ } -} - -testsJar() - -projectTest { - workingDir = rootDir -} - -runtimeJar { - archiveName = "maven-ide.jar" -} - -ideaPlugin() \ No newline at end of file diff --git a/idea/idea-maven/build.gradle.kts.as34 b/idea/idea-maven/build.gradle.kts.as34 deleted file mode 100644 index 4ecbe3f70dc..00000000000 --- a/idea/idea-maven/build.gradle.kts.as34 +++ /dev/null @@ -1,74 +0,0 @@ - -plugins { - kotlin("jvm") - id("jps-compatible") -} - -dependencies { - compile(project(":core:util.runtime")) - compile(project(":compiler:frontend")) - compile(project(":compiler:frontend.java")) - compile(project(":compiler:util")) - compile(project(":compiler:cli-common")) - compile(project(":kotlin-build-common")) - - compile(project(":js:js.frontend")) - - compile(project(":idea")) - compile(project(":idea:idea-jvm")) - compile(project(":idea:idea-jps-common")) - - compileOnly(intellijDep()) - excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) } - - testCompile(projectTests(":idea")) - testCompile(projectTests(":compiler:tests-common")) - testCompile(projectTests(":idea:idea-test-framework")) - - testCompileOnly(intellijDep()) - //testCompileOnly(intellijPluginDep("maven")) - - testCompile(project(":idea:idea-native")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false } - testRuntime(project(":kotlin-native:kotlin-native-utils")) { isTransitive = false } - - testRuntime(project(":kotlin-reflect")) - testRuntime(project(":idea:idea-jvm")) - testRuntime(project(":idea:idea-android")) - testRuntime(project(":plugins:android-extensions-ide")) - testRuntime(project(":plugins:lint")) - testRuntime(project(":sam-with-receiver-ide-plugin")) - testRuntime(project(":allopen-ide-plugin")) - testRuntime(project(":noarg-ide-plugin")) - testRuntime(project(":kotlin-scripting-idea")) - testRuntime(project(":kotlinx-serialization-ide-plugin")) - - testRuntime(intellijDep()) - // TODO: the order of the plugins matters here, consider avoiding order-dependency - testRuntime(intellijPluginDep("junit")) - testRuntime(intellijPluginDep("testng")) - testRuntime(intellijPluginDep("properties")) - testRuntime(intellijPluginDep("gradle")) - testRuntime(intellijPluginDep("Groovy")) - testRuntime(intellijPluginDep("coverage")) - //testRuntime(intellijPluginDep("maven")) - testRuntime(intellijPluginDep("android")) - testRuntime(intellijPluginDep("smali")) -} - -sourceSets { - "main" { /*projectDefault()*/ } - "test" { /*projectDefault()*/ } -} - -testsJar() - -projectTest { - workingDir = rootDir -} - -runtimeJar { - archiveName = "maven-ide.jar" -} - -ideaPlugin() \ No newline at end of file From 48d832298b77359f0bbdf9efb836f0db4b431e0d Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Tue, 15 Jan 2019 17:00:09 +0300 Subject: [PATCH 04/33] Compile Kotlin project with "-Xjvm-default=compatibility" flag #KT-29073 Fixed --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 1ded15ee2f7..fc5fed61b81 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -324,6 +324,7 @@ allprojects { val commonCompilerArgs = listOfNotNull( "-Xallow-kotlin-package", "-Xread-deserialized-contracts", + "-Xjvm-default=compatibility", "-Xprogressive".takeIf { hasProperty("test.progressive.mode") } // TODO: change to "-progressive" after bootstrap ) @@ -750,6 +751,7 @@ fun Project.configureJvmProject(javaHome: String, javaVersion: String) { tasks.withType { kotlinOptions.jdkHome = javaHome kotlinOptions.jvmTarget = javaVersion + kotlinOptions.freeCompilerArgs += "-Xjvm-default=compatibility" } tasks.withType { From 04ff2a3ee76a57c8be3d341dda845307330c1af2 Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Wed, 17 Oct 2018 15:09:05 +0300 Subject: [PATCH 05/33] Add test on isNullOrEmpty-like contract Currently, behavior is undesired, see KT-27241 --- .../smartcasts/valueOfContractedFunctionIngored.kt | 11 +++++++++++ .../smartcasts/valueOfContractedFunctionIngored.txt | 4 ++++ .../checkers/DiagnosticsTestWithStdLibGenerated.java | 5 +++++ .../DiagnosticsTestWithStdLibUsingJavacGenerated.java | 5 +++++ 4 files changed, 25 insertions(+) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt new file mode 100644 index 00000000000..892df9c1bb4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt @@ -0,0 +1,11 @@ +// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts +// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER + +import kotlin.contracts.* + +fun f3(value: String?) { + if (!value.isNullOrEmpty() is Boolean) { + value.length + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt new file mode 100644 index 00000000000..267a3e4b146 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt @@ -0,0 +1,4 @@ +package + +public fun myIf(/*0*/ cond: kotlin.Boolean): kotlin.Any +public fun test(/*0*/ x: kotlin.Any?): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index ff754894fbe..fb1464af13e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1341,6 +1341,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/unreachableBranches.kt"); } + @TestMetadata("valueOfContractedFunctionIngored.kt") + public void testValueOfContractedFunctionIngored() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt"); + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/multieffect") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index afefaf9ecf5..f5053bfadf9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -1341,6 +1341,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/unreachableBranches.kt"); } + @TestMetadata("valueOfContractedFunctionIngored.kt") + public void testValueOfContractedFunctionIngored() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt"); + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/multieffect") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) From e483f836660e83566baa9f3af68905a66ff33103 Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Tue, 15 Jan 2019 11:37:37 +0300 Subject: [PATCH 06/33] Make 'is'-operator more stupid Consider following expression: 'call() is Foo'. Suppose that we know something about the 'call()', e.g. 'returns(foo) -> ' Previously, we've tried to re-use knowledge about 'call()', constructing some smart clause, like 'returns(true) -> foo is Foo && '. The conceptual error here is that *we can't* argue that holds. Imagine that 'call()' actually has unspecified 'returns(foo2) -> ', and 'foo2 is Foo' also holds. Then we would get 'returns(true) -> foo2 is Foo && ' <=> 'returns(true) -> ' for the whole call, which is not correct. More concrete example would be something like: 'if (!x.isNullOrEmpty() is Boolean)' ^KT-27241 Fixed --- .../kotlin/contracts/model/functors/IsFunctor.kt | 15 +++++---------- .../valueOfContractedFunctionIngored.kt | 2 +- .../valueOfContractedFunctionIngored.txt | 3 +-- .../contracts/analysis/smartcasts/neg/15.kt | 7 +++---- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt index e3ff55ad804..648125c9207 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt @@ -29,22 +29,17 @@ class IsFunctor(val type: KotlinType, val isNegated: Boolean) : AbstractReducing fun invokeWithArguments(arg: Computation): List { return if (arg is ESValue) - invokeWithValue(arg, null) + invokeWithValue(arg) else - arg.effects.flatMap { - if (it !is ConditionalEffect || it.simpleEffect !is ESReturns || it.simpleEffect.value == ESConstant.WILDCARD) - listOf(it) - else - invokeWithValue(it.simpleEffect.value, it.condition) - } + emptyList() } - private fun invokeWithValue(value: ESValue, additionalCondition: ESExpression?): List { + private fun invokeWithValue(value: ESValue): List { val trueIs = ESIs(value, this) val falseIs = ESIs(value, IsFunctor(type, isNegated.not())) - val trueResult = ConditionalEffect(trueIs.and(additionalCondition), ESReturns(true.lift())) - val falseResult = ConditionalEffect(falseIs.and(additionalCondition), ESReturns(false.lift())) + val trueResult = ConditionalEffect(trueIs, ESReturns(true.lift())) + val falseResult = ConditionalEffect(falseIs, ESReturns(false.lift())) return listOf(trueResult, falseResult) } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt index 892df9c1bb4..719b21a4480 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.kt @@ -6,6 +6,6 @@ import kotlin.contracts.* fun f3(value: String?) { if (!value.isNullOrEmpty() is Boolean) { - value.length + value.length } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt index 267a3e4b146..7780a7bf0ea 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/valueOfContractedFunctionIngored.txt @@ -1,4 +1,3 @@ package -public fun myIf(/*0*/ cond: kotlin.Boolean): kotlin.Any -public fun test(/*0*/ x: kotlin.Any?): kotlin.Unit +public fun f3(/*0*/ value: kotlin.String?): kotlin.Unit diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/15.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/15.kt index 41e89f4f24f..e559b576d4d 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/15.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/15.kt @@ -7,7 +7,6 @@ * SECTIONS: contracts, analysis, smartcasts * NUMBER: 15 * DESCRIPTION: Check smartcasts working if type checking for contract function is used - * UNEXPECTED BEHAVIOUR * ISSUES: KT-27241 */ @@ -40,20 +39,20 @@ import contracts.* // TESTCASE NUMBER: 1 fun case_1(value: Any) { if (contracts.case_1_2(contracts.case_1_1(value is Char))) { - println(value.category) + println(value.category) } } // TESTCASE NUMBER: 2 fun case_2(value: Any) { if (contracts.case_2(value is Char) is Boolean) { - println(value.category) + println(value.category) } } // TESTCASE NUMBER: 3 fun case_3(value: String?) { if (!value.isNullOrEmpty() is Boolean) { - value.length + value.length } } From 5302470f6b0d37efb86ae88723964337ede2c936 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Wed, 16 Jan 2019 13:58:38 +0300 Subject: [PATCH 07/33] Fix "testUnresolvedDependency" This fix is work-around fixing incompatibility issue between gradle tooling api bundled in IDEA and gradle tooling api in gradle 4.x. When null messages were logged it resulted in the following error: "java.io.StreamCorruptedException: invalid stream header: ED000573" --- idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt | 2 +- .../src/KotlinMPPGradleModelBuilder.kt.181 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt index b184952f269..0db979abdac 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt @@ -273,7 +273,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { private fun safelyGetArguments(compileKotlinTask: Task, accessor: Method?) = try { accessor?.invoke(compileKotlinTask) as? List } catch (e: Exception) { - logger.info(e.message, e) + logger.info(e.message ?: "Unexpected exception: $e", e) null } ?: emptyList() diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt.181 b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt.181 index 909e1d9fb02..a7ff5effc27 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt.181 +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt.181 @@ -264,7 +264,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { private fun safelyGetArguments(compileKotlinTask: Task, accessor: Method?) = try { accessor?.invoke(compileKotlinTask) as? List } catch (e: Exception) { - logger.info(e.message, e) + logger.info(e.message ?: "Unexpected exception: $e", e) null } ?: emptyList() From 618a7c374749a5cedc1eba4153f49711de394aa2 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Wed, 16 Jan 2019 18:56:05 +0300 Subject: [PATCH 08/33] Improve logging in gradle import tests --- .../KotlinGradleProjectResolverExtension.kt | 6 +++++ .../gradle/GradleImportingTestCase.kt | 25 ++++++++++++++++++ .../gradle/ImportingTestWatcher.kt | 26 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt index 55b487a80cf..cca722f21aa 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt @@ -47,6 +47,9 @@ import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver import java.io.File import java.util.* import kotlin.collections.HashMap +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.diagnostic.debugOrInfoIfTestMode +import org.jetbrains.kotlin.idea.util.PsiPrecedences var DataNode.isResolved by NotNullableCopyableDataNodeUserDataProperty(Key.create("IS_RESOLVED"), false) @@ -69,6 +72,7 @@ var DataNode.dependenciesCache class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() { val isAndroidProjectKey = Key.findKeyByName("IS_ANDROID_PROJECT_KEY") + private val LOG = Logger.getInstance(PsiPrecedences::class.java) override fun getToolingExtensionsClasses(): Set> { return setOf(KotlinGradleModelBuilder::class.java, Unit::class.java) @@ -190,6 +194,7 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() ideModule: DataNode, ideProject: DataNode ) { + LOG.debugOrInfoIfTestMode { "Start populate module dependencies. Gradle module: [$gradleModule], Ide module: [$ideModule], Ide project: [$ideProject]" } val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) if (mppModel != null) { mppModel.targets.filterNot { it.name == "metadata" }.forEach { target -> @@ -227,6 +232,7 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() if (useModulePerSourceSet()) { super.populateModuleDependencies(gradleModule, ideModule, ideProject) } + LOG.debugOrInfoIfTestMode { "Finish populating module dependencies. Gradle module: [$gradleModule], Ide module: [$ideModule], Ide project: [$ideProject]" } } private fun addImplementedModuleNames( diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt index 4be3d13a29e..e2f4516178f 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt @@ -36,6 +36,7 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile import com.intellij.testFramework.IdeaTestUtil +import com.intellij.testFramework.TestLoggerFactory import com.intellij.util.PathUtil import com.intellij.util.containers.ContainerUtil import junit.framework.TestCase @@ -52,6 +53,7 @@ import org.jetbrains.plugins.gradle.settings.GradleSettings import org.jetbrains.plugins.gradle.util.GradleConstants import org.jetbrains.plugins.groovy.GroovyFileType import org.junit.Assume.assumeThat +import org.junit.BeforeClass import org.junit.Rule import org.junit.rules.TestName import org.junit.runner.RunWith @@ -61,6 +63,8 @@ import java.io.IOException import java.io.StringWriter import java.net.URISyntaxException import java.util.* +import com.intellij.openapi.diagnostic.Logger +import org.junit.AfterClass // part of org.jetbrains.plugins.gradle.importing.GradleImportingTestCase @RunWith(value = Parameterized::class) @@ -72,6 +76,10 @@ abstract class GradleImportingTestCase : ExternalSystemImportingTestCase() { @Rule var name = TestName() + @JvmField + @Rule + var testWatcher = ImportingTestWatcher() + @JvmField @Rule var versionMatcherRule = VersionMatcherRule() @@ -276,5 +284,22 @@ abstract class GradleImportingTestCase : ExternalSystemImportingTestCase() { fun wrapperJar(): File { return File(PathUtil.getJarPathForClass(GradleWrapperMain::class.java)) } + + private var persistedLoggerFactory : Logger.Factory? = null + + @JvmStatic + @BeforeClass + fun setLoggerFactory() { + persistedLoggerFactory = Logger.getFactory() + Logger.setFactory(TestLoggerFactory::class.java) + } + + @JvmStatic + @AfterClass + fun restoreLoggerFactory() { + if (persistedLoggerFactory != null) { + Logger.setFactory(persistedLoggerFactory) + } + } } } diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt new file mode 100644 index 00000000000..c05ffad7e65 --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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.idea.codeInsight.gradle + +import com.intellij.testFramework.TestLoggerFactory +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +class ImportingTestWatcher : TestWatcher() { + + override fun succeeded(description: Description) { + TestLoggerFactory.onTestFinished(true) + } + + override fun failed(e: Throwable, description: Description) { + TestLoggerFactory.onTestFinished(false) + } + + override fun starting(description: Description) { + TestLoggerFactory.onTestStarted() + } + +} \ No newline at end of file From 3c2d026128cfee79f05a6f0067d507c593c37e11 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Thu, 17 Jan 2019 17:29:24 +0700 Subject: [PATCH 09/33] CIDR: Always relax upper limit of product version in K/N plugin for non-public CIDR builds Issue #KT-29338:fixed --- buildSrc/src/main/kotlin/cidr/cidrTasks.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/buildSrc/src/main/kotlin/cidr/cidrTasks.kt b/buildSrc/src/main/kotlin/cidr/cidrTasks.kt index 57147ce35c8..9708255bc11 100644 --- a/buildSrc/src/main/kotlin/cidr/cidrTasks.kt +++ b/buildSrc/src/main/kotlin/cidr/cidrTasks.kt @@ -55,18 +55,27 @@ fun Copy.applyCidrVersionRestrictions( pluginVersion: String ) { val dotsCount = productVersion.count { it == '.' } - check(dotsCount >= 1 && dotsCount <= 2) { + check(dotsCount in 1..2) { "Wrong CIDR product version format: $productVersion" } - val sinceBuild = if (dotsCount == 1) + // private product versions don't have two dots + val privateProductVersion = dotsCount == 1 + + val applyStrictProductVersionLimitation = if (privateProductVersion && strictProductVersionLimitation) { + // it does not make sense for private versions to apply strict version limitation + logger.warn("Non-public CIDR product version [$productVersion] has been specified. The corresponding `versions..strict` property will be ignored.") + false + } else strictProductVersionLimitation + + val sinceBuild = if (privateProductVersion) productVersion else productVersion.substringBeforeLast('.') - val untilBuild = if (strictProductVersionLimitation) - // if strict then restrict plugin to the same single version of CLion or AppCode - sinceBuild + ".*" + val untilBuild = if (applyStrictProductVersionLimitation) + // if `strict` then restrict plugin to the same single version of CLion or AppCode + "$sinceBuild.*" else productVersion.substringBefore('.') + ".*" From c1de845d291da50faaef300a4ddeb92c44e7e4e4 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 16 Jan 2019 14:03:33 +0300 Subject: [PATCH 10/33] Generate switch instruction for 'when' with unsigned subject --- .../codegen/when/SwitchCodegenProvider.kt | 7 ++-- .../box/unsignedTypes/whenByUnsigned.kt | 35 +++++++++++++++++++ .../unsignedTypes/whenByUnsigned.kt | 28 +++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++ .../codegen/BytecodeTextTestGenerated.java | 5 +++ .../codegen/IrBytecodeTextTestGenerated.java | 5 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++ .../IrJsCodegenBoxTestGenerated.java | 5 +++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++ 10 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt create mode 100644 compiler/testData/codegen/bytecodeText/unsignedTypes/whenByUnsigned.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt index f05c3a26d2b..0edf2d48a8b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt @@ -22,10 +22,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.constants.ConstantValue -import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant -import org.jetbrains.kotlin.resolve.constants.NullValue -import org.jetbrains.kotlin.resolve.constants.StringValue +import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.org.objectweb.asm.Type import java.util.ArrayList @@ -102,7 +99,7 @@ private constructor( private fun isIntegralConstantsSwitch(expression: KtWhenExpression, subjectType: Type): Boolean = AsmUtil.isIntPrimitive(subjectType) && - checkAllItemsAreConstantsSatisfying(expression) { it is IntegerValueConstant<*> } + checkAllItemsAreConstantsSatisfying(expression) { it is IntegerValueConstant<*> || it is UnsignedValueConstant<*> } private fun isStringConstantsSwitch(expression: KtWhenExpression, subjectType: Type): Boolean = subjectType.className == String::class.java.name && diff --git a/compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt b/compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt new file mode 100644 index 00000000000..503349da746 --- /dev/null +++ b/compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt @@ -0,0 +1,35 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JS, JVM_IR + +const val M1: UInt = 2147483648u +const val M2: ULong = 9223372036854775808UL + +fun testUInt(x: UInt) = + when (x) { + 0u -> "none" + 1u -> "one" + 2u -> "two" + 3u -> "three" + M1 -> "M1" + else -> "many" + } + +fun testULong(x: ULong) = + when (x) { + 0UL -> "none" + 1UL -> "one" + 2UL -> "two" + 3UL -> "three" + M2 -> "M2" + else -> "many" + } + +fun box(): String { + val t1 = listOf(0u, 1u, 2u, 3u, 4u, M1).map { testUInt(it) } + if (t1 != listOf("none", "one", "two", "three", "many", "M1")) throw AssertionError("UInt: $t1") + + val t2 = listOf(0UL, 1UL, 2UL, 3UL, 4UL, M2).map { testULong(it) } + if (t2 != listOf("none", "one", "two", "three", "many", "M2")) throw AssertionError("ULong: $t2") + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/unsignedTypes/whenByUnsigned.kt b/compiler/testData/codegen/bytecodeText/unsignedTypes/whenByUnsigned.kt new file mode 100644 index 00000000000..51691fa9be3 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/unsignedTypes/whenByUnsigned.kt @@ -0,0 +1,28 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JVM_IR + +const val M1: UInt = 2147483648u + +fun testUInt1(x: UInt) = + when (x) { + 0u -> "none" + 1u -> "one" + 2u -> "two" + 3u -> "three" + else -> "many" + } + +fun testUInt2(x: UInt) = + when (x) { + 0u -> "none" + 1u -> "one" + 2u -> "two" + 3u -> "three" + M1 -> "M1" + else -> "many" + } + +// 2 SWITCH +// ^ This captures both TABLESWITCH and LOOKUPSWITCH; we don't care about nuances of *SWITCH instruction generation here. + +// 0 IF_ICMP \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index b9dd1c3e7ac..6c681793048 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -24357,6 +24357,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testVarargsOfUnsignedTypes() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/box/vararg") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 1dc515746b7..874c4355f7e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -3182,6 +3182,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { public void testUnsignedLongRemainder_jvm18() throws Exception { runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongRemainder_jvm18.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/varargs") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java index 699c4eb0528..d5215136993 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/IrBytecodeTextTestGenerated.java @@ -3182,6 +3182,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { public void testUnsignedLongRemainder_jvm18() throws Exception { runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongRemainder_jvm18.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/varargs") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 252dc7428dc..a13694535fc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -24357,6 +24357,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testVarargsOfUnsignedTypes() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/box/vararg") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index dafe58465c3..0bfb452e9d4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -24362,6 +24362,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testVarargsOfUnsignedTypes() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/box/vararg") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index eebcedaef57..e5350b0141f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -18797,6 +18797,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testVarargsOfUnsignedTypes() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/box/vararg") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 73dd72e1de6..ea96098d9b3 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -19847,6 +19847,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testVarargsOfUnsignedTypes() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/varargsOfUnsignedTypes.kt"); } + + @TestMetadata("whenByUnsigned.kt") + public void testWhenByUnsigned() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt"); + } } @TestMetadata("compiler/testData/codegen/box/vararg") From ee75b8c7e58863397d1cce1e8964229f31277afe Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 20 Dec 2018 09:57:37 +0300 Subject: [PATCH 11/33] Minor. Extract KotlinParsing::parseCommonDeclaration --- .../parsing/KotlinExpressionParsing.java | 33 ++--- .../kotlin/parsing/KotlinParsing.java | 120 ++++++++---------- 2 files changed, 68 insertions(+), 85 deletions(-) diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java index 6f8bc399898..02495ff3922 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java @@ -1068,7 +1068,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { KotlinParsing.ModifierDetector detector = new KotlinParsing.ModifierDetector(); myKotlinParsing.parseModifierList(detector, DEFAULT, TokenSet.EMPTY); - IElementType declType = parseLocalDeclarationRest(detector.isEnumDetected(), rollbackIfDefinitelyNotExpression, isScriptTopLevel); + IElementType declType = parseLocalDeclarationRest(detector, rollbackIfDefinitelyNotExpression, isScriptTopLevel); if (declType != null) { // we do not attach preceding comments (non-doc) to local variables because they are likely commenting a few statements below @@ -1348,29 +1348,19 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { * ; */ @Nullable - private IElementType parseLocalDeclarationRest(boolean isEnum, boolean failIfDefinitelyNotExpression, boolean isScriptTopLevel) { + private IElementType parseLocalDeclarationRest( + @NotNull KotlinParsing.ModifierDetector modifierDetector, + boolean failIfDefinitelyNotExpression, + boolean isScriptTopLevel + ) { IElementType keywordToken = tt(); - IElementType declType = null; - if (failIfDefinitelyNotExpression) { if (keywordToken != FUN_KEYWORD) return null; return myKotlinParsing.parseFunction(/* failIfIdentifierExists = */ true); } - if (keywordToken == CLASS_KEYWORD || keywordToken == INTERFACE_KEYWORD) { - declType = myKotlinParsing.parseClass(isEnum); - } - else if (keywordToken == FUN_KEYWORD) { - declType = myKotlinParsing.parseFunction(); - } - else if (keywordToken == VAL_KEYWORD || keywordToken == VAR_KEYWORD) { - declType = myKotlinParsing.parseLocalProperty(isScriptTopLevel); - } - else if (keywordToken == TYPE_ALIAS_KEYWORD) { - declType = myKotlinParsing.parseTypeAlias(); - } - else if (keywordToken == OBJECT_KEYWORD) { + if (keywordToken == OBJECT_KEYWORD) { // Object expression may appear at the statement position: should parse it // as expression instead of object declaration // sample: @@ -1382,11 +1372,12 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { if (lookahead == COLON || lookahead == LBRACE) { return null; } - - myKotlinParsing.parseObject(NameParsingMode.REQUIRED, true); - declType = OBJECT_DECLARATION; } - return declType; + + return myKotlinParsing.parseCommonDeclaration( + modifierDetector, NameParsingMode.REQUIRED, + isScriptTopLevel ? KotlinParsing.PropertyParsingMode.SCRIPT_TOPLEVEL : KotlinParsing.PropertyParsingMode.LOCAL + ); } /* diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index 2b9628edd9f..cb21c9ebcfd 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -416,26 +416,9 @@ public class KotlinParsing extends AbstractKotlinParsing { ModifierDetector detector = new ModifierDetector(); parseModifierList(detector, DEFAULT, TokenSet.EMPTY); - IElementType keywordToken = tt(); - IElementType declType = null; + IElementType declType = parseCommonDeclaration(detector, NameParsingMode.REQUIRED, PropertyParsingMode.MEMBER_OR_TOPLEVEL); - if (keywordToken == CLASS_KEYWORD || keywordToken == INTERFACE_KEYWORD) { - declType = parseClass(detector.isEnumDetected()); - } - else if (keywordToken == FUN_KEYWORD) { - declType = parseFunction(); - } - else if (keywordToken == VAL_KEYWORD || keywordToken == VAR_KEYWORD) { - declType = parseProperty(); - } - else if (keywordToken == TYPE_ALIAS_KEYWORD) { - declType = parseTypeAlias(); - } - else if (keywordToken == OBJECT_KEYWORD) { - parseObject(NameParsingMode.REQUIRED, true); - declType = OBJECT_DECLARATION; - } - else if (at(LBRACE)) { + if (declType == null && at(LBRACE)) { error("Expecting a top level declaration"); parseBlock(); declType = FUN; @@ -450,6 +433,33 @@ public class KotlinParsing extends AbstractKotlinParsing { } } + public IElementType parseCommonDeclaration( + @NotNull ModifierDetector detector, + @NotNull NameParsingMode nameParsingModeForObject, + @NotNull PropertyParsingMode propertyParsingMode + ) { + IElementType keywordToken = tt(); + + if (keywordToken == CLASS_KEYWORD || keywordToken == INTERFACE_KEYWORD) { + return parseClass(detector.isEnumDetected()); + } + else if (keywordToken == FUN_KEYWORD) { + return parseFunction(); + } + else if (keywordToken == VAL_KEYWORD || keywordToken == VAR_KEYWORD) { + return parseProperty(propertyParsingMode); + } + else if (keywordToken == TYPE_ALIAS_KEYWORD) { + return parseTypeAlias(); + } + else if (keywordToken == OBJECT_KEYWORD) { + parseObject(nameParsingModeForObject, true); + return OBJECT_DECLARATION; + } + + return null; + } + /* * (modifier | annotation)* */ @@ -914,7 +924,7 @@ public class KotlinParsing extends AbstractKotlinParsing { return object ? OBJECT_DECLARATION : CLASS; } - IElementType parseClass(boolean enumClass) { + private IElementType parseClass(boolean enumClass) { return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass); } @@ -1097,7 +1107,7 @@ public class KotlinParsing extends AbstractKotlinParsing { ModifierDetector detector = new ModifierDetector(); parseModifierList(detector, DEFAULT, TokenSet.EMPTY); - IElementType declType = parseMemberDeclarationRest(detector.isEnumDetected(), detector.isDefaultDetected()); + IElementType declType = parseMemberDeclarationRest(detector); if (declType == null) { errorWithRecovery("Expecting member declaration", TokenSet.EMPTY); @@ -1108,26 +1118,16 @@ public class KotlinParsing extends AbstractKotlinParsing { } } - private IElementType parseMemberDeclarationRest(boolean isEnum, boolean isDefault) { - IElementType keywordToken = tt(); - IElementType declType = null; - if (keywordToken == CLASS_KEYWORD || keywordToken == INTERFACE_KEYWORD) { - declType = parseClass(isEnum); - } - else if (keywordToken == FUN_KEYWORD) { - declType = parseFunction(); - } - else if (keywordToken == VAL_KEYWORD || keywordToken == VAR_KEYWORD) { - declType = parseProperty(); - } - else if (keywordToken == TYPE_ALIAS_KEYWORD) { - declType = parseTypeAlias(); - } - else if (keywordToken == OBJECT_KEYWORD) { - parseObject(isDefault ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, true); - declType = OBJECT_DECLARATION; - } - else if (at(INIT_KEYWORD)) { + private IElementType parseMemberDeclarationRest(@NotNull ModifierDetector modifierDetector) { + IElementType declType = parseCommonDeclaration( + modifierDetector, + modifierDetector.isDefaultDetected() ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, + PropertyParsingMode.MEMBER_OR_TOPLEVEL + ); + + if (declType != null) return declType; + + if (at(INIT_KEYWORD)) { advance(); // init if (at(LBRACE)) { parseBlock(); @@ -1225,7 +1225,7 @@ public class KotlinParsing extends AbstractKotlinParsing { * : modifiers "typealias" SimpleName typeParameters? "=" type * ; */ - IElementType parseTypeAlias() { + private IElementType parseTypeAlias() { assert _at(TYPE_ALIAS_KEYWORD); advance(); // TYPE_ALIAS_KEYWORD @@ -1249,6 +1249,20 @@ public class KotlinParsing extends AbstractKotlinParsing { return TYPEALIAS; } + enum PropertyParsingMode { + MEMBER_OR_TOPLEVEL(false, true), + LOCAL(true, false), + SCRIPT_TOPLEVEL(true, true); + + public final boolean destructuringAllowed; + public final boolean accessorsAllowed; + + PropertyParsingMode(boolean destructuringAllowed, boolean accessorsAllowed) { + this.destructuringAllowed = destructuringAllowed; + this.accessorsAllowed = accessorsAllowed; + } + } + /* * variableDeclarationEntry * : SimpleName (":" type)? @@ -1264,28 +1278,6 @@ public class KotlinParsing extends AbstractKotlinParsing { * (getter? setter? | setter? getter?) SEMI? * ; */ - private IElementType parseProperty() { - return parseProperty(PropertyParsingMode.MEMBER_OR_TOPLEVEL); - } - - public IElementType parseLocalProperty(boolean isScriptTopLevel) { - return parseProperty(isScriptTopLevel ? PropertyParsingMode.SCRIPT_TOPLEVEL : PropertyParsingMode.LOCAL); - } - - enum PropertyParsingMode { - MEMBER_OR_TOPLEVEL(false, true), - LOCAL(true, false), - SCRIPT_TOPLEVEL(true, true); - - public final boolean destructuringAllowed; - public final boolean accessorsAllowed; - - PropertyParsingMode(boolean destructuringAllowed, boolean accessorsAllowed) { - this.destructuringAllowed = destructuringAllowed; - this.accessorsAllowed = accessorsAllowed; - } - } - public IElementType parseProperty(PropertyParsingMode mode) { assert (at(VAL_KEYWORD) || at(VAR_KEYWORD)); advance(); From 8b3ffee1836db3f8ce4cb37fd7752b18fe6b0881 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 20 Dec 2018 09:57:58 +0300 Subject: [PATCH 12/33] Minor. Rename defaultDetected -> companionDetected --- .../org/jetbrains/kotlin/parsing/KotlinParsing.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index cb21c9ebcfd..8087b9d7b84 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -1121,7 +1121,7 @@ public class KotlinParsing extends AbstractKotlinParsing { private IElementType parseMemberDeclarationRest(@NotNull ModifierDetector modifierDetector) { IElementType declType = parseCommonDeclaration( modifierDetector, - modifierDetector.isDefaultDetected() ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, + modifierDetector.isCompanionDetected() ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, PropertyParsingMode.MEMBER_OR_TOPLEVEL ); @@ -2340,7 +2340,7 @@ public class KotlinParsing extends AbstractKotlinParsing { /*package*/ static class ModifierDetector implements Consumer { private boolean enumDetected = false; - private boolean defaultDetected = false; + private boolean companionDetected = false; @Override public void consume(IElementType item) { @@ -2348,7 +2348,7 @@ public class KotlinParsing extends AbstractKotlinParsing { enumDetected = true; } else if (item == KtTokens.COMPANION_KEYWORD) { - defaultDetected = true; + companionDetected = true; } } @@ -2356,8 +2356,8 @@ public class KotlinParsing extends AbstractKotlinParsing { return enumDetected; } - public boolean isDefaultDetected() { - return defaultDetected; + public boolean isCompanionDetected() { + return companionDetected; } } From 1688fed0b7588c7d54d07baaacebbd67d52c482e Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 20 Dec 2018 10:30:51 +0300 Subject: [PATCH 13/33] Minor. Rename PropertyParsingMode -> DeclarationParsingMode --- .../parsing/KotlinExpressionParsing.java | 4 ++-- .../kotlin/parsing/KotlinParsing.java | 20 +++++++------------ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java index 02495ff3922..4a870086053 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java @@ -852,7 +852,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { PsiBuilder.Marker atWhenStart = mark(); myKotlinParsing.parseAnnotationsList(DEFAULT, TokenSet.create(EQ, RPAR)); if (at(VAL_KEYWORD) || at(VAR_KEYWORD)) { - IElementType declType = myKotlinParsing.parseProperty(KotlinParsing.PropertyParsingMode.LOCAL); + IElementType declType = myKotlinParsing.parseProperty(KotlinParsing.DeclarationParsingMode.LOCAL); atWhenStart.done(declType); atWhenStart.setCustomEdgeTokenBinders(PrecedingDocCommentsBinder.INSTANCE, TrailingCommentsBinder.INSTANCE); @@ -1376,7 +1376,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { return myKotlinParsing.parseCommonDeclaration( modifierDetector, NameParsingMode.REQUIRED, - isScriptTopLevel ? KotlinParsing.PropertyParsingMode.SCRIPT_TOPLEVEL : KotlinParsing.PropertyParsingMode.LOCAL + isScriptTopLevel ? KotlinParsing.DeclarationParsingMode.SCRIPT_TOPLEVEL : KotlinParsing.DeclarationParsingMode.LOCAL ); } diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index 8087b9d7b84..ebd0630ae55 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -416,7 +416,7 @@ public class KotlinParsing extends AbstractKotlinParsing { ModifierDetector detector = new ModifierDetector(); parseModifierList(detector, DEFAULT, TokenSet.EMPTY); - IElementType declType = parseCommonDeclaration(detector, NameParsingMode.REQUIRED, PropertyParsingMode.MEMBER_OR_TOPLEVEL); + IElementType declType = parseCommonDeclaration(detector, NameParsingMode.REQUIRED, DeclarationParsingMode.MEMBER_OR_TOPLEVEL); if (declType == null && at(LBRACE)) { error("Expecting a top level declaration"); @@ -436,7 +436,7 @@ public class KotlinParsing extends AbstractKotlinParsing { public IElementType parseCommonDeclaration( @NotNull ModifierDetector detector, @NotNull NameParsingMode nameParsingModeForObject, - @NotNull PropertyParsingMode propertyParsingMode + @NotNull DeclarationParsingMode declarationParsingMode ) { IElementType keywordToken = tt(); @@ -447,7 +447,7 @@ public class KotlinParsing extends AbstractKotlinParsing { return parseFunction(); } else if (keywordToken == VAL_KEYWORD || keywordToken == VAR_KEYWORD) { - return parseProperty(propertyParsingMode); + return parseProperty(declarationParsingMode); } else if (keywordToken == TYPE_ALIAS_KEYWORD) { return parseTypeAlias(); @@ -803,12 +803,6 @@ public class KotlinParsing extends AbstractKotlinParsing { PROHIBITED } - public enum DeclarationParsingMode { - TOP_LEVEL, - CLASS_MEMBER, - LOCAL - } - /* * class * : modifiers ("class" | "interface") SimpleName @@ -1122,7 +1116,7 @@ public class KotlinParsing extends AbstractKotlinParsing { IElementType declType = parseCommonDeclaration( modifierDetector, modifierDetector.isCompanionDetected() ? NameParsingMode.ALLOWED : NameParsingMode.REQUIRED, - PropertyParsingMode.MEMBER_OR_TOPLEVEL + DeclarationParsingMode.MEMBER_OR_TOPLEVEL ); if (declType != null) return declType; @@ -1249,7 +1243,7 @@ public class KotlinParsing extends AbstractKotlinParsing { return TYPEALIAS; } - enum PropertyParsingMode { + enum DeclarationParsingMode { MEMBER_OR_TOPLEVEL(false, true), LOCAL(true, false), SCRIPT_TOPLEVEL(true, true); @@ -1257,7 +1251,7 @@ public class KotlinParsing extends AbstractKotlinParsing { public final boolean destructuringAllowed; public final boolean accessorsAllowed; - PropertyParsingMode(boolean destructuringAllowed, boolean accessorsAllowed) { + DeclarationParsingMode(boolean destructuringAllowed, boolean accessorsAllowed) { this.destructuringAllowed = destructuringAllowed; this.accessorsAllowed = accessorsAllowed; } @@ -1278,7 +1272,7 @@ public class KotlinParsing extends AbstractKotlinParsing { * (getter? setter? | setter? getter?) SEMI? * ; */ - public IElementType parseProperty(PropertyParsingMode mode) { + public IElementType parseProperty(DeclarationParsingMode mode) { assert (at(VAL_KEYWORD) || at(VAR_KEYWORD)); advance(); From 5437a0e47875146cdf5de52a49be357ea4d2a325 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 20 Dec 2018 10:50:36 +0300 Subject: [PATCH 14/33] Add recovery for enum declaration without 'class' keyword ^KT-13703 Fixed --- .../kotlin/parsing/KotlinParsing.java | 37 +++-- .../tests/modifiers/IllegalModifiers.kt | 4 +- .../tests/modifiers/IllegalModifiers.txt | 18 ++- .../psi/EnumWithAnnotationKeyword.txt | 25 ++-- .../testData/psi/recovery/enumWthoutClass.kt | 18 +++ .../testData/psi/recovery/enumWthoutClass.txt | 137 ++++++++++++++++++ .../kotlin/parsing/ParsingTestGenerated.java | 5 + 7 files changed, 215 insertions(+), 29 deletions(-) create mode 100644 compiler/testData/psi/recovery/enumWthoutClass.kt create mode 100644 compiler/testData/psi/recovery/enumWthoutClass.txt diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index ebd0630ae55..c06700c483f 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -441,7 +441,7 @@ public class KotlinParsing extends AbstractKotlinParsing { IElementType keywordToken = tt(); if (keywordToken == CLASS_KEYWORD || keywordToken == INTERFACE_KEYWORD) { - return parseClass(detector.isEnumDetected()); + return parseClass(detector.isEnumDetected(), true); } else if (keywordToken == FUN_KEYWORD) { return parseFunction(); @@ -455,6 +455,8 @@ public class KotlinParsing extends AbstractKotlinParsing { else if (keywordToken == OBJECT_KEYWORD) { parseObject(nameParsingModeForObject, true); return OBJECT_DECLARATION; + } else if (keywordToken == IDENTIFIER && detector.isEnumDetected() && declarationParsingMode.canBeEnumUsedAsSoftKeyword) { + return parseClass(true, false); } return null; @@ -825,15 +827,22 @@ public class KotlinParsing extends AbstractKotlinParsing { boolean object, NameParsingMode nameParsingMode, boolean optionalBody, - boolean enumClass + boolean enumClass, + boolean expectKindKeyword ) { - if (object) { - assert _at(OBJECT_KEYWORD); + if (expectKindKeyword) { + if (object) { + assert _at(OBJECT_KEYWORD); + } + else { + assert _atSet(CLASS_KEYWORD, INTERFACE_KEYWORD); + } + advance(); // CLASS_KEYWORD, INTERFACE_KEYWORD or OBJECT_KEYWORD } else { - assert _atSet(CLASS_KEYWORD, INTERFACE_KEYWORD); + assert enumClass : "Currently classifiers without class/interface/object are only allowed for enums"; + error("'class' keyword is expected after 'enum'"); } - advance(); // CLASS_KEYWORD, INTERFACE_KEYWORD or OBJECT_KEYWORD if (nameParsingMode == NameParsingMode.REQUIRED) { expect(IDENTIFIER, "Name expected", CLASS_NAME_RECOVERY_SET); @@ -918,12 +927,12 @@ public class KotlinParsing extends AbstractKotlinParsing { return object ? OBJECT_DECLARATION : CLASS; } - private IElementType parseClass(boolean enumClass) { - return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass); + private IElementType parseClass(boolean enumClass, boolean expectKindKeyword) { + return parseClassOrObject(false, NameParsingMode.REQUIRED, true, enumClass, expectKindKeyword); } void parseObject(NameParsingMode nameParsingMode, boolean optionalBody) { - parseClassOrObject(true, nameParsingMode, optionalBody, false); + parseClassOrObject(true, nameParsingMode, optionalBody, false, true); } /* @@ -1244,16 +1253,18 @@ public class KotlinParsing extends AbstractKotlinParsing { } enum DeclarationParsingMode { - MEMBER_OR_TOPLEVEL(false, true), - LOCAL(true, false), - SCRIPT_TOPLEVEL(true, true); + MEMBER_OR_TOPLEVEL(false, true, true), + LOCAL(true, false, false), + SCRIPT_TOPLEVEL(true, true, false); public final boolean destructuringAllowed; public final boolean accessorsAllowed; + public final boolean canBeEnumUsedAsSoftKeyword; - DeclarationParsingMode(boolean destructuringAllowed, boolean accessorsAllowed) { + DeclarationParsingMode(boolean destructuringAllowed, boolean accessorsAllowed, boolean canBeEnumUsedAsSoftKeyword) { this.destructuringAllowed = destructuringAllowed; this.accessorsAllowed = accessorsAllowed; + this.canBeEnumUsedAsSoftKeyword = canBeEnumUsedAsSoftKeyword; } } diff --git a/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.kt b/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.kt index bffac287aa9..5318cfdfede 100644 --- a/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.kt +++ b/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.kt @@ -119,7 +119,7 @@ class IllegalModifiers7() { // Secondary constructors class IllegalModifiers8 { abstract - enum + enum open inner annotation @@ -129,7 +129,7 @@ class IllegalModifiers8 { final vararg reified - const + const constructor() {} constructor(private enum abstract x: Int) {} diff --git a/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.txt b/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.txt index 2915bfd788c..7c5153ea00c 100644 --- a/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.txt +++ b/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.txt @@ -108,11 +108,27 @@ package illegal_modifiers { } public final class IllegalModifiers8 { - public constructor IllegalModifiers8() public constructor IllegalModifiers8(/*0*/ x: kotlin.Int) public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public abstract enum class constructor : kotlin.Enum { + private constructor constructor() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: illegal_modifiers.IllegalModifiers8.constructor): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): illegal_modifiers.IllegalModifiers8.constructor + public final /*synthesized*/ fun values(): kotlin.Array + } } public final class IllegalModifiers9 { diff --git a/compiler/testData/psi/EnumWithAnnotationKeyword.txt b/compiler/testData/psi/EnumWithAnnotationKeyword.txt index 84aa9116be8..577e705ca69 100644 --- a/compiler/testData/psi/EnumWithAnnotationKeyword.txt +++ b/compiler/testData/psi/EnumWithAnnotationKeyword.txt @@ -23,21 +23,20 @@ KtFile: EnumWithAnnotationKeyword.kt PsiWhiteSpace('\n') PsiElement(RBRACE)('}') PsiWhiteSpace('\n\n') - MODIFIER_LIST - PsiElement(enum)('enum') - PsiWhiteSpace(' ') - PsiElement(annotation)('annotation') - PsiWhiteSpace(' ') - PsiErrorElement:Expecting a top level declaration - PsiElement(IDENTIFIER)('E1') - PsiWhiteSpace(' ') - FUN - PsiErrorElement:Expecting a top level declaration + CLASS + MODIFIER_LIST + PsiElement(enum)('enum') + PsiWhiteSpace(' ') + PsiElement(annotation)('annotation') + PsiErrorElement:'class' keyword is expected after 'enum' - BLOCK + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('E1') + PsiWhiteSpace(' ') + CLASS_BODY PsiElement(LBRACE)('{') PsiWhiteSpace('\n ') - REFERENCE_EXPRESSION + ENUM_ENTRY PsiElement(IDENTIFIER)('D') PsiWhiteSpace('\n') - PsiElement(RBRACE)('}') \ No newline at end of file + PsiElement(RBRACE)('}') diff --git a/compiler/testData/psi/recovery/enumWthoutClass.kt b/compiler/testData/psi/recovery/enumWthoutClass.kt new file mode 100644 index 00000000000..0c4a6218139 --- /dev/null +++ b/compiler/testData/psi/recovery/enumWthoutClass.kt @@ -0,0 +1,18 @@ +enum A { X, Y } + +private enum B { + X, Y +} + +internal Q { + X, Y +} + +fun foo() { + // No recovery here + enum A { X, Y } + + private enum B { + X, Y + } +} diff --git a/compiler/testData/psi/recovery/enumWthoutClass.txt b/compiler/testData/psi/recovery/enumWthoutClass.txt new file mode 100644 index 00000000000..e256c50a81e --- /dev/null +++ b/compiler/testData/psi/recovery/enumWthoutClass.txt @@ -0,0 +1,137 @@ +KtFile: enumWthoutClass.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + CLASS + MODIFIER_LIST + PsiElement(enum)('enum') + PsiErrorElement:'class' keyword is expected after 'enum' + + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace(' ') + ENUM_ENTRY + PsiElement(IDENTIFIER)('X') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + ENUM_ENTRY + PsiElement(IDENTIFIER)('Y') + PsiWhiteSpace(' ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(private)('private') + PsiWhiteSpace(' ') + PsiElement(enum)('enum') + PsiErrorElement:'class' keyword is expected after 'enum' + + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('B') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + ENUM_ENTRY + PsiElement(IDENTIFIER)('X') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + ENUM_ENTRY + PsiElement(IDENTIFIER)('Y') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + MODIFIER_LIST + PsiElement(internal)('internal') + PsiWhiteSpace(' ') + PsiErrorElement:Expecting a top level declaration + PsiElement(IDENTIFIER)('Q') + PsiWhiteSpace(' ') + FUN + PsiErrorElement:Expecting a top level declaration + + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('X') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Y') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PsiComment(EOL_COMMENT)('// No recovery here') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('enum') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + VALUE_PARAMETER + PsiElement(IDENTIFIER)('X') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('Y') + PsiErrorElement:Expecting '->' or ',' + + PsiWhiteSpace(' ') + BLOCK + + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('private') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('enum') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('B') + PsiWhiteSpace(' ') + LAMBDA_ARGUMENT + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + VALUE_PARAMETER_LIST + VALUE_PARAMETER + PsiElement(IDENTIFIER)('X') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('Y') + PsiErrorElement:Expecting '->' or ',' + + PsiWhiteSpace('\n ') + BLOCK + + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index d7faf543dcc..a5bb676d7d8 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -1933,6 +1933,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/DoWhileWithoutLPar.kt"); } + @TestMetadata("enumWthoutClass.kt") + public void testEnumWthoutClass() throws Exception { + runTest("compiler/testData/psi/recovery/enumWthoutClass.kt"); + } + @TestMetadata("ForEmptyParentheses.kt") public void testForEmptyParentheses() throws Exception { runTest("compiler/testData/psi/recovery/ForEmptyParentheses.kt"); From e6710b6fa22a1ec81f3934c070f602177aa8fdf8 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 21 Dec 2018 09:10:04 +0300 Subject: [PATCH 15/33] Add recovery for value parameter without type or name The case for KT-7237 belongs to /NoGTInTypeArguments test It was fixed implicitly: before it recovery was working but the name for the next parameter was attached to type argument list. After that change, parameter without name gets parsed correctly (with an error of course) ^KT-13731 Fixed ^KT-7237 Fixed --- .../kotlin/parsing/KotlinParsing.java | 14 + .../psi/recovery/NoGTInTypeArguments.kt | 9 + .../psi/recovery/NoGTInTypeArguments.txt | 314 ++++++++++++++++++ .../psi/recovery/valueParameterRecovery.kt | 5 + .../psi/recovery/valueParameterRecovery.txt | 108 ++++++ .../valueParameterRecoveryWithTypes.kt | 2 + .../valueParameterRecoveryWithTypes.txt | 101 ++++++ .../kotlin/parsing/ParsingTestGenerated.java | 15 + 8 files changed, 568 insertions(+) create mode 100644 compiler/testData/psi/recovery/NoGTInTypeArguments.kt create mode 100644 compiler/testData/psi/recovery/NoGTInTypeArguments.txt create mode 100644 compiler/testData/psi/recovery/valueParameterRecovery.kt create mode 100644 compiler/testData/psi/recovery/valueParameterRecovery.txt create mode 100644 compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt create mode 100644 compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index c06700c483f..0ae41c29bd8 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -2252,6 +2252,12 @@ public class KotlinParsing extends AbstractKotlinParsing { if (at(COMMA)) { advance(); // COMMA } + else if (at(COLON)) { + // recovery for the case "fun bar(x: Array : Int)" when we've just parsed "x: Array" + // error should be reported in the `parseValueParameter` call + //noinspection UnnecessaryContinue + continue; + } else { if (!at(RPAR)) error("Expecting comma or ')'"); if (!atSet(isFunctionTypeContents ? LAMBDA_VALUE_PARAMETER_FIRST : VALUE_PARAMETER_FIRST)) break; @@ -2322,6 +2328,14 @@ public class KotlinParsing extends AbstractKotlinParsing { if (at(COLON)) { advance(); // COLON + + if (at(IDENTIFIER) && lookahead(1) == COLON) { + // recovery for the case "fun foo(x: y: Int)" when we're at "y: " it's likely that this is a name of the next parameter, + // not a type reference of the current one + error("Type reference expected"); + return false; + } + parseTypeRef(); } else if (typeRequired) { diff --git a/compiler/testData/psi/recovery/NoGTInTypeArguments.kt b/compiler/testData/psi/recovery/NoGTInTypeArguments.kt new file mode 100644 index 00000000000..bd8376401a2 --- /dev/null +++ b/compiler/testData/psi/recovery/NoGTInTypeArguments.kt @@ -0,0 +1,9 @@ +fun foo1(x: List + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo1') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('s') + PsiErrorElement:Expecting a '>' + + VALUE_PARAMETER + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('String') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo2') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('s') + PsiErrorElement:Expecting a '>' + + VALUE_PARAMETER + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('String') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo3') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo4') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo5') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo6') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo7') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('main') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/recovery/valueParameterRecovery.kt b/compiler/testData/psi/recovery/valueParameterRecovery.kt new file mode 100644 index 00000000000..fc9a23a8432 --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecovery.kt @@ -0,0 +1,5 @@ +fun foo(x: Int, y: z: Int) {} + +fun bar(x: y: Int, z: Int) {} + +fun baz(x: y: z: Int) {} diff --git a/compiler/testData/psi/recovery/valueParameterRecovery.txt b/compiler/testData/psi/recovery/valueParameterRecovery.txt new file mode 100644 index 00000000000..5c164239ae4 --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecovery.txt @@ -0,0 +1,108 @@ +KtFile: valueParameterRecovery.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('z') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('z') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('baz') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('z') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt new file mode 100644 index 00000000000..211b004ae07 --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt @@ -0,0 +1,2 @@ +fun foo(x: Array, : Int, w: Int) {} +fun bar(x: Array : Int, w: Int) {} diff --git a/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt new file mode 100644 index 00000000000..118beb8073d --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt @@ -0,0 +1,101 @@ +KtFile: valueParameterRecoveryWithTypes.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Array') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(GT)('>') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiErrorElement:Parameter name expected + + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('w') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Array') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(GT)('>') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiErrorElement:Parameter name expected + + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('w') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index a5bb676d7d8..f24b758e123 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -2148,6 +2148,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/NoArrowInWhen.kt"); } + @TestMetadata("NoGTInTypeArguments.kt") + public void testNoGTInTypeArguments() throws Exception { + runTest("compiler/testData/psi/recovery/NoGTInTypeArguments.kt"); + } + @TestMetadata("PackageNewLineRecovery.kt") public void testPackageNewLineRecovery() throws Exception { runTest("compiler/testData/psi/recovery/PackageNewLineRecovery.kt"); @@ -2183,6 +2188,16 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/ValueParameterNoTypeRecovery.kt"); } + @TestMetadata("valueParameterRecovery.kt") + public void testValueParameterRecovery() throws Exception { + runTest("compiler/testData/psi/recovery/valueParameterRecovery.kt"); + } + + @TestMetadata("valueParameterRecoveryWithTypes.kt") + public void testValueParameterRecoveryWithTypes() throws Exception { + runTest("compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt"); + } + @TestMetadata("WhenWithoutBraces.kt") public void testWhenWithoutBraces() throws Exception { runTest("compiler/testData/psi/recovery/WhenWithoutBraces.kt"); From 65e6e21d0f3017417ecb786a63d5209c546dd744 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 21 Dec 2018 13:53:10 +0300 Subject: [PATCH 16/33] Add recovery for import lists in the middle of the file Note, that it only works for top-level declarations ^KT-7185 Fixed --- .../kotlin/parsing/KotlinParsing.java | 7 +- .../src/org/jetbrains/kotlin/psi/KtFile.kt | 21 +++- .../tests/imports/twoImportLists.kt | 105 ++++++++++++++++ .../tests/imports/twoImportLists.txt | 114 ++++++++++++++++++ compiler/testData/psi/FileStart_ERR.txt | 13 +- .../psi/recovery/importsWithConflict.kt | 14 +++ .../psi/recovery/importsWithConflict.txt | 90 ++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 5 + .../DiagnosticsUsingJavacTestGenerated.java | 5 + .../kotlin/parsing/ParsingTestGenerated.java | 5 + 10 files changed, 371 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/imports/twoImportLists.kt create mode 100644 compiler/testData/diagnostics/tests/imports/twoImportLists.txt create mode 100644 compiler/testData/psi/recovery/importsWithConflict.kt create mode 100644 compiler/testData/psi/recovery/importsWithConflict.txt diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index 0ae41c29bd8..1e1a020a354 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -424,7 +424,12 @@ public class KotlinParsing extends AbstractKotlinParsing { declType = FUN; } - if (declType == null) { + if (declType == null && at(IMPORT_KEYWORD)) { + error("imports are only allowed in the beginning of file"); + parseImportDirectives(); + decl.drop(); + } + else if (declType == null) { errorAndAdvance("Expecting a top level declaration"); decl.drop(); } diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt index fde5e476148..726d4f273d5 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.fileTypes.FileType import com.intellij.psi.* import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.ArrayFactory import com.intellij.util.FileContentUtilCore import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.KtNodeTypes @@ -54,13 +55,16 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : private var pathCached: String? = null val importList: KtImportList? - get() = findChildByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList::class.java) + get() = importLists.firstOrNull() + + private val importLists: Array + get() = findChildrenByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList::class.java) val fileAnnotationList: KtFileAnnotationList? get() = findChildByTypeOrClass(KtStubElementTypes.FILE_ANNOTATION_LIST, KtFileAnnotationList::class.java) open val importDirectives: List - get() = importList?.imports ?: emptyList() + get() = importLists.flatMap { it.imports } // scripts have no package directive, all other files must have package directives val packageDirective: KtPackageDirective? @@ -154,6 +158,19 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : return findChildByClass(elementClass) } + fun >> findChildrenByTypeOrClass( + elementType: KtPlaceHolderStubElementType, + elementClass: Class + ): Array { + val stub = stub + if (stub != null) { + val arrayFactory: ArrayFactory = elementType.arrayFactory + return stub.getChildrenByType(elementType, arrayFactory) + } + return findChildrenByClass(elementClass) + } + + fun findImportByAlias(name: String): KtImportDirective? = importDirectives.firstOrNull { name == it.aliasName } diff --git a/compiler/testData/diagnostics/tests/imports/twoImportLists.kt b/compiler/testData/diagnostics/tests/imports/twoImportLists.kt new file mode 100644 index 00000000000..83f36c6a5fc --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/twoImportLists.kt @@ -0,0 +1,105 @@ +// !WITH_NEW_INFERENCE +// FILE:a.kt +package a + +<<< FOOO +import b.B //class +import b.foo //function +import b.ext //extension function +import b.value //property +import b.C.Companion.bar //function from companion object +import b.C.Companion.cValue //property from companion object +import b.constant.fff //function from val +import b.constant.dValue //property from val +import smth.illegal +import b.C.smth.illegal + +<<<HEAD +import b.bar.smth +import b.bar.* +import b.unr.unr.unr +import unr.unr.unr +import b.constant +import b.E.Companion.f //val from companion object + +fun test(arg: B) { + foo(value) + arg.ext() + + bar() + foo(cValue) + + fff(dValue) + + constant.fff(constant.dValue) + + f.f() +} + +// FILE:b.kt +package b + +class B() {} + +fun foo(i: Int) = i + +fun B.ext() {} + +val value = 0 + +class C() { + companion object { + fun bar() {} + val cValue = 1 + } +} + +class D() { + fun fff(s: String) = s + val dValue = "w" +} + +val constant = D() + +class E() { + companion object { + val f = F() + } +} + +class F() { + fun f() {} +} + +fun bar() {} + +//FILE:c.kt +package c + +import c.C.* + +object C { + fun f() { + } + val i = 348 +} + +fun foo() { + if (i == 3) f() +} + +//FILE:d.kt +package d + +import d.A.Companion.B +import d.A.Companion.C + +val b : B = B() +val c : B = C + +class A() { + companion object { + open class B() {} + object C : B() {} + } +} diff --git a/compiler/testData/diagnostics/tests/imports/twoImportLists.txt b/compiler/testData/diagnostics/tests/imports/twoImportLists.txt new file mode 100644 index 00000000000..c875a83e7e5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/twoImportLists.txt @@ -0,0 +1,114 @@ +package + +package a { + public fun test(/*0*/ arg: b.B): kotlin.Unit +} + +package b { + public val constant: b.D + public val value: kotlin.Int = 0 + public fun bar(): kotlin.Unit + public fun foo(/*0*/ i: kotlin.Int): kotlin.Int + public fun b.B.ext(): kotlin.Unit + + public final class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class C { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final val cValue: kotlin.Int = 1 + public final fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public final class D { + public constructor D() + public final val dValue: kotlin.String = "w" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun fff(/*0*/ s: kotlin.String): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class E { + public constructor E() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final val f: b.F + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public final class F { + public constructor F() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +package c { + public fun foo(): kotlin.Unit + + public object C { + private constructor C() + public final val i: kotlin.Int = 348 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun f(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +package d { + public val b: d.A.Companion.B + public val c: d.A.Companion.B + + public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public open class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public object C : d.A.Companion.B { + private constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + } +} diff --git a/compiler/testData/psi/FileStart_ERR.txt b/compiler/testData/psi/FileStart_ERR.txt index bc430fe2284..0e22e68e59b 100644 --- a/compiler/testData/psi/FileStart_ERR.txt +++ b/compiler/testData/psi/FileStart_ERR.txt @@ -14,9 +14,12 @@ KtFile: FileStart_ERR.kt PsiElement(DOT)('.') PsiErrorElement:Expecting a top level declaration PsiElement(IDENTIFIER)('bar') + PsiErrorElement:imports are only allowed in the beginning of file + PsiWhiteSpace('\n') - PsiErrorElement:Expecting a top level declaration - PsiElement(IDENTIFIER)('import') - PsiWhiteSpace(' ') - PsiErrorElement:Expecting a top level declaration - PsiElement(IDENTIFIER)('foo') \ No newline at end of file + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') diff --git a/compiler/testData/psi/recovery/importsWithConflict.kt b/compiler/testData/psi/recovery/importsWithConflict.kt new file mode 100644 index 00000000000..e0cdbf05e8a --- /dev/null +++ b/compiler/testData/psi/recovery/importsWithConflict.kt @@ -0,0 +1,14 @@ +package a + +import a1 +<<>> BAR + +fun bar() {} + +import a2 +import a4.df + +fun foo() {} diff --git a/compiler/testData/psi/recovery/importsWithConflict.txt b/compiler/testData/psi/recovery/importsWithConflict.txt new file mode 100644 index 00000000000..09438ea05f7 --- /dev/null +++ b/compiler/testData/psi/recovery/importsWithConflict.txt @@ -0,0 +1,90 @@ +KtFile: importsWithConflict.kt + PACKAGE_DIRECTIVE + PsiElement(package)('package') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace('\n\n') + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a1') + PsiWhiteSpace('\n') + PsiErrorElement:Expecting a top level declaration + PsiElement(LT)('<') + PsiErrorElement:Expecting a top level declaration + PsiElement(LT)('<') + PsiErrorElement:Expecting a top level declaration + PsiElement(LT)('<') + PsiErrorElement:Expecting a top level declaration + PsiElement(IDENTIFIER)('HEAD') + PsiErrorElement:imports are only allowed in the beginning of file + + PsiWhiteSpace('\n') + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a2') + PsiWhiteSpace('\n') + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a3') + PsiWhiteSpace('\n') + PsiErrorElement:Expecting a top level declaration + PsiElement(GT)('>') + PsiErrorElement:Expecting a top level declaration + PsiElement(GT)('>') + PsiErrorElement:Expecting a top level declaration + PsiElement(GT)('>') + PsiWhiteSpace(' ') + PsiErrorElement:Expecting a top level declaration + PsiElement(IDENTIFIER)('BAR') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiErrorElement:imports are only allowed in the beginning of file + + PsiWhiteSpace('\n\n') + IMPORT_LIST + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a2') + PsiWhiteSpace('\n') + IMPORT_DIRECTIVE + PsiElement(import)('import') + PsiWhiteSpace(' ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a4') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('df') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index ef4805ff8ad..60d319da981 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9071,6 +9071,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt"); } + @TestMetadata("twoImportLists.kt") + public void testTwoImportLists() throws Exception { + runTest("compiler/testData/diagnostics/tests/imports/twoImportLists.kt"); + } + @TestMetadata("WrongImport.kt") public void testWrongImport() throws Exception { runTest("compiler/testData/diagnostics/tests/imports/WrongImport.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 057156e64e5..d8621ff8a48 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -9071,6 +9071,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt"); } + @TestMetadata("twoImportLists.kt") + public void testTwoImportLists() throws Exception { + runTest("compiler/testData/diagnostics/tests/imports/twoImportLists.kt"); + } + @TestMetadata("WrongImport.kt") public void testWrongImport() throws Exception { runTest("compiler/testData/diagnostics/tests/imports/WrongImport.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index f24b758e123..810af25a327 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -2013,6 +2013,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/ImportRecovery.kt"); } + @TestMetadata("importsWithConflict.kt") + public void testImportsWithConflict() throws Exception { + runTest("compiler/testData/psi/recovery/importsWithConflict.kt"); + } + @TestMetadata("IncompleteAccessor1.kt") public void testIncompleteAccessor1() throws Exception { runTest("compiler/testData/psi/recovery/IncompleteAccessor1.kt"); From db53c4bea4fb8c0bb302dead89aac784aa0b87bf Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 9 Jan 2019 15:00:22 +0300 Subject: [PATCH 17/33] Add test for obsolete recovery case (semi-finished extension) ^KT-7405 Obsolete --- .../psi/recovery/UnfinishedExtension.kt | 4 +++ .../psi/recovery/UnfinishedExtension.txt | 28 +++++++++++++++++++ .../kotlin/parsing/ParsingTestGenerated.java | 5 ++++ 3 files changed, 37 insertions(+) create mode 100644 compiler/testData/psi/recovery/UnfinishedExtension.kt create mode 100644 compiler/testData/psi/recovery/UnfinishedExtension.txt diff --git a/compiler/testData/psi/recovery/UnfinishedExtension.kt b/compiler/testData/psi/recovery/UnfinishedExtension.kt new file mode 100644 index 00000000000..c7852538854 --- /dev/null +++ b/compiler/testData/psi/recovery/UnfinishedExtension.kt @@ -0,0 +1,4 @@ +fun Any. + +fun goodFunction() { +} diff --git a/compiler/testData/psi/recovery/UnfinishedExtension.txt b/compiler/testData/psi/recovery/UnfinishedExtension.txt new file mode 100644 index 00000000000..1aec4227961 --- /dev/null +++ b/compiler/testData/psi/recovery/UnfinishedExtension.txt @@ -0,0 +1,28 @@ +KtFile: UnfinishedExtension.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Any') + PsiElement(DOT)('.') + PsiErrorElement:Expecting function name + + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('goodFunction') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index 810af25a327..0d1314fdeec 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -2173,6 +2173,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/SameLineStatementRecovery.kt"); } + @TestMetadata("UnfinishedExtension.kt") + public void testUnfinishedExtension() throws Exception { + runTest("compiler/testData/psi/recovery/UnfinishedExtension.kt"); + } + @TestMetadata("ValNoName.kt") public void testValNoName() throws Exception { runTest("compiler/testData/psi/recovery/ValNoName.kt"); From 37614254d7f26a8de368289749eb2c2bc6b64f3f Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 9 Jan 2019 15:24:02 +0300 Subject: [PATCH 18/33] Fix test on unused import suppression Before the fix for KT-7185, the file looked like: package suppression @file:Suppress("UnusedImport") import java.io.* // unused And it was parsed incorrectly, because @file: annotations should come before package directive But after fix, import directives started being parsed that lead to wrong unused import (because suppression wasn't parsed still) --- idea/testData/inspections/unusedImport/suppression.kt | 3 ++- .../kotlin/idea/codeInsight/AbstractInspectionTest.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/idea/testData/inspections/unusedImport/suppression.kt b/idea/testData/inspections/unusedImport/suppression.kt index cd6684b02b0..4ccf8064b31 100644 --- a/idea/testData/inspections/unusedImport/suppression.kt +++ b/idea/testData/inspections/unusedImport/suppression.kt @@ -1,3 +1,4 @@ @file:Suppress("UnusedImport") +package suppression -import java.io.* // unused \ No newline at end of file +import java.io.* // unused diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt index 03e034eb022..ea61c50879a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInspectionTest.kt @@ -94,7 +94,7 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase() file.extension == "kt" -> { val text = FileUtil.loadFile(file, true) val fileText = - if (text.startsWith("package")) + if (text.lines().any { it.startsWith("package") }) text else "package ${file.nameWithoutExtension};$text" From 82537cdc8b1e377fbe5b1613d525fb0ef9bedb97 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 15 Jan 2019 15:23:04 +0300 Subject: [PATCH 19/33] Add recovery for missing comma between arguments ^KT-13497 Fixed --- .../parsing/KotlinExpressionParsing.java | 10 +- .../diagnostics/tests/CharacterLiterals.kt | 8 +- .../testData/psi/FunctionExpressions_ERR.txt | 89 ++++----- .../testData/psi/noCommaBetweenArguments.kt | 22 +++ .../testData/psi/noCommaBetweenArguments.txt | 182 ++++++++++++++++++ .../kotlin/parsing/ParsingTestGenerated.java | 5 + ...aStyleClassLiteralInAnnotationArguments.kt | 4 +- 7 files changed, 270 insertions(+), 50 deletions(-) create mode 100644 compiler/testData/psi/noCommaBetweenArguments.kt create mode 100644 compiler/testData/psi/noCommaBetweenArguments.txt diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java index 4a870086053..0d95eae5a3f 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java @@ -1816,7 +1816,15 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { if (at(COLON) && lookahead(1) == IDENTIFIER) { errorAndAdvance("Unexpected type specification", 2); } - if (!at(COMMA)) break; + if (!at(COMMA)) { + if (atSet(EXPRESSION_FIRST)) { + error("Expecting ','"); + continue; + } + else { + break; + } + } advance(); // COMMA if (at(RPAR)) { error("Expecting an argument"); diff --git a/compiler/testData/diagnostics/tests/CharacterLiterals.kt b/compiler/testData/diagnostics/tests/CharacterLiterals.kt index b99ca7098fa..b2e07c99188 100644 --- a/compiler/testData/diagnostics/tests/CharacterLiterals.kt +++ b/compiler/testData/diagnostics/tests/CharacterLiterals.kt @@ -4,10 +4,10 @@ fun test(c : Char) { test('aa') test('a) test(' - test(0' - test('\n') - test('\\') - test('''') + test(0' + test('\n') + test('\\') + test('''') test('\'') test('\"') } diff --git a/compiler/testData/psi/FunctionExpressions_ERR.txt b/compiler/testData/psi/FunctionExpressions_ERR.txt index a2f1b01c6b1..29f2093393e 100644 --- a/compiler/testData/psi/FunctionExpressions_ERR.txt +++ b/compiler/testData/psi/FunctionExpressions_ERR.txt @@ -575,61 +575,64 @@ KtFile: FunctionExpressions_ERR.kt PsiElement(RPAR)(')') PsiWhiteSpace('\n\n\n ') CALL_EXPRESSION - CALL_EXPRESSION - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('bar') - VALUE_ARGUMENT_LIST - PsiElement(LPAR)('(') - VALUE_ARGUMENT - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('public') - PsiWhiteSpace(' ') - PsiErrorElement:Expecting ')' - PsiElement(fun)('fun') - PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') VALUE_ARGUMENT_LIST PsiElement(LPAR)('(') + VALUE_ARGUMENT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('public') + PsiErrorElement:Expecting ',' + + PsiWhiteSpace(' ') + VALUE_ARGUMENT + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') PsiElement(RPAR)(')') - PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) - PsiElement(RPAR)(')') PsiWhiteSpace('\n ') CALL_EXPRESSION - CALL_EXPRESSION - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('bar') - VALUE_ARGUMENT_LIST - PsiElement(LPAR)('(') - VALUE_ARGUMENT - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('open') - PsiWhiteSpace(' ') - PsiErrorElement:Expecting ')' - PsiElement(fun)('fun') - PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') VALUE_ARGUMENT_LIST PsiElement(LPAR)('(') + VALUE_ARGUMENT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('open') + PsiErrorElement:Expecting ',' + + PsiWhiteSpace(' ') + VALUE_ARGUMENT + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') PsiElement(RPAR)(')') - PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) - PsiElement(RPAR)(')') PsiWhiteSpace('\n ') CALL_EXPRESSION - CALL_EXPRESSION - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('bar') - VALUE_ARGUMENT_LIST - PsiElement(LPAR)('(') - VALUE_ARGUMENT - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('final') - PsiWhiteSpace(' ') - PsiErrorElement:Expecting ')' - PsiElement(fun)('fun') - PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') VALUE_ARGUMENT_LIST PsiElement(LPAR)('(') + VALUE_ARGUMENT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('final') + PsiErrorElement:Expecting ',' + + PsiWhiteSpace(' ') + VALUE_ARGUMENT + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') PsiElement(RPAR)(')') - PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) - PsiElement(RPAR)(')') PsiWhiteSpace('\n\n ') CALL_EXPRESSION REFERENCE_EXPRESSION @@ -659,4 +662,4 @@ KtFile: FunctionExpressions_ERR.kt PsiElement(IDENTIFIER)('V') PsiElement(RPAR)(')') PsiWhiteSpace('\n') - PsiElement(RBRACE)('}') \ No newline at end of file + PsiElement(RBRACE)('}') diff --git a/compiler/testData/psi/noCommaBetweenArguments.kt b/compiler/testData/psi/noCommaBetweenArguments.kt new file mode 100644 index 00000000000..e54ef261891 --- /dev/null +++ b/compiler/testData/psi/noCommaBetweenArguments.kt @@ -0,0 +1,22 @@ +fun foo() { + bar1( + A() + A() + ) + bar2(A() A()) + + bar3(x y) + bar4(x + y + ) + + bar5("" "") + bar6("" + "" + ) + + bar7({} {}) + bar8({} + {} + ) +} diff --git a/compiler/testData/psi/noCommaBetweenArguments.txt b/compiler/testData/psi/noCommaBetweenArguments.txt new file mode 100644 index 00000000000..bbe4eeb9a49 --- /dev/null +++ b/compiler/testData/psi/noCommaBetweenArguments.txt @@ -0,0 +1,182 @@ +KtFile: noCommaBetweenArguments.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar1') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiWhiteSpace('\n ') + VALUE_ARGUMENT + BINARY_EXPRESSION + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('A') + PARENTHESIZED + PsiElement(LPAR)('(') + PsiErrorElement:Expecting an expression + + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar2') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('A') + PARENTHESIZED + PsiElement(LPAR)('(') + PsiErrorElement:Expecting an expression + + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar3') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('y') + PsiErrorElement:Expecting an element + + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar4') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace('\n ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('y') + PsiErrorElement:Expecting an element + + PsiWhiteSpace('\n ') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar5') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiErrorElement:Expecting ',' + + PsiWhiteSpace(' ') + VALUE_ARGUMENT + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar6') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiErrorElement:Expecting ',' + + PsiWhiteSpace('\n ') + VALUE_ARGUMENT + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiWhiteSpace('\n ') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar7') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + CALL_EXPRESSION + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BLOCK + + PsiElement(RBRACE)('}') + PsiWhiteSpace(' ') + LAMBDA_ARGUMENT + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BLOCK + + PsiElement(RBRACE)('}') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar8') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + CALL_EXPRESSION + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BLOCK + + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + LAMBDA_ARGUMENT + LAMBDA_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BLOCK + + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index 0d1314fdeec..29b3a2fa71f 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -521,6 +521,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/NewlinesInParentheses.kt"); } + @TestMetadata("noCommaBetweenArguments.kt") + public void testNoCommaBetweenArguments() throws Exception { + runTest("compiler/testData/psi/noCommaBetweenArguments.kt"); + } + @TestMetadata("NonTypeBeforeDotInBaseClass.kt") public void testNonTypeBeforeDotInBaseClass() throws Exception { runTest("compiler/testData/psi/NonTypeBeforeDotInBaseClass.kt"); diff --git a/idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt b/idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt index 43615b3085d..430078b8aeb 100644 --- a/idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt +++ b/idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt @@ -2,5 +2,5 @@ annotation class A class B -@A(B.class) -fun f() {} \ No newline at end of file +@A(B.class) +fun f() {} From 7191624a9287ac7c44aca6367aa06c7b3202b983 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Thu, 17 Jan 2019 17:20:43 +0300 Subject: [PATCH 20/33] Fix compilation of KotlinGradleProjectResolverExtension in bunches --- .../KotlinGradleProjectResolverExtension.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt index cca722f21aa..856ea0e2fb9 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleProjectResolverExtension.kt @@ -48,7 +48,6 @@ import java.io.File import java.util.* import kotlin.collections.HashMap import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.diagnostic.debugOrInfoIfTestMode import org.jetbrains.kotlin.idea.util.PsiPrecedences var DataNode.isResolved @@ -194,7 +193,9 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() ideModule: DataNode, ideProject: DataNode ) { - LOG.debugOrInfoIfTestMode { "Start populate module dependencies. Gradle module: [$gradleModule], Ide module: [$ideModule], Ide project: [$ideProject]" } + if (LOG.isDebugEnabled) { + LOG.debug("Start populate module dependencies. Gradle module: [$gradleModule], Ide module: [$ideModule], Ide project: [$ideProject]") + } val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) if (mppModel != null) { mppModel.targets.filterNot { it.name == "metadata" }.forEach { target -> @@ -232,7 +233,9 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() if (useModulePerSourceSet()) { super.populateModuleDependencies(gradleModule, ideModule, ideProject) } - LOG.debugOrInfoIfTestMode { "Finish populating module dependencies. Gradle module: [$gradleModule], Ide module: [$ideModule], Ide project: [$ideProject]" } + if (LOG.isDebugEnabled) { + LOG.debug("Finish populating module dependencies. Gradle module: [$gradleModule], Ide module: [$ideModule], Ide project: [$ideProject]") + } } private fun addImplementedModuleNames( From 56672c2564ed602927c961d1826295b1072955e4 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 16 Jan 2019 02:17:34 +0300 Subject: [PATCH 21/33] Ensure stable sorting in MutableList.sort/sortWith MutableList.sortWith now works correctly in JS_IR backend too #KT-12473 --- .../function/sortListOfStrings.kt | 1 - .../box/sam/constructors/comparator.kt | 1 - .../sam/constructors/nonLiteralComparator.kt | 1 - libraries/stdlib/js/src/kotlin/collections.kt | 3 +- .../stdlib/test/collections/ArraysTest.kt | 16 ++-------- .../stdlib/test/collections/CollectionTest.kt | 32 ++++++++++++++++++- .../stdlib/test/collections/IterableTests.kt | 14 ++++++++ 7 files changed, 49 insertions(+), 19 deletions(-) diff --git a/compiler/testData/codegen/box/callableReference/function/sortListOfStrings.kt b/compiler/testData/codegen/box/callableReference/function/sortListOfStrings.kt index 008ce18dd03..f37b6b89a98 100644 --- a/compiler/testData/codegen/box/callableReference/function/sortListOfStrings.kt +++ b/compiler/testData/codegen/box/callableReference/function/sortListOfStrings.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun sort(list: MutableList, comparator: (String, String) -> Int) { diff --git a/compiler/testData/codegen/box/sam/constructors/comparator.kt b/compiler/testData/codegen/box/sam/constructors/comparator.kt index 5885a026a1c..56b24616f79 100644 --- a/compiler/testData/codegen/box/sam/constructors/comparator.kt +++ b/compiler/testData/codegen/box/sam/constructors/comparator.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun box(): String { diff --git a/compiler/testData/codegen/box/sam/constructors/nonLiteralComparator.kt b/compiler/testData/codegen/box/sam/constructors/nonLiteralComparator.kt index c415e666343..0bef462b2a9 100644 --- a/compiler/testData/codegen/box/sam/constructors/nonLiteralComparator.kt +++ b/compiler/testData/codegen/box/sam/constructors/nonLiteralComparator.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun box(): String { diff --git a/libraries/stdlib/js/src/kotlin/collections.kt b/libraries/stdlib/js/src/kotlin/collections.kt index a54948cec2f..6abd57149f3 100644 --- a/libraries/stdlib/js/src/kotlin/collections.kt +++ b/libraries/stdlib/js/src/kotlin/collections.kt @@ -109,8 +109,7 @@ private fun collectionsSort(list: MutableList, comparator: Comparator Sortable(keyRange.random(), index) } - array.sortedBy { it.key }.iterator().assertStableSorted() - array.sortedByDescending { it.key }.iterator().assertStableSorted(descending = true) + array.sortedBy { it.key }.assertStableSorted() + array.sortedByDescending { it.key }.assertStableSorted(descending = true) array.sortBy { it.key } array.assertStableSorted() @@ -1488,20 +1488,10 @@ class ArraysTest { } } -private data class Sortable>(val key: K, val index: Int) : Comparable> { - override fun compareTo(other: Sortable): Int = this.key.compareTo(other.key) -} -private fun > Array>.assertStableSorted(descending: Boolean = false) = +fun > Array>.assertStableSorted(descending: Boolean = false) = iterator().assertStableSorted(descending = descending) -private fun > Iterator>.assertStableSorted(descending: Boolean = false) { - assertSorted { a, b -> - val relation = a.key.compareTo(b.key) - (if (descending) relation > 0 else relation < 0) || relation == 0 && a.index < b.index - } -} - private class ArraySortedChecker(val array: A, val comparator: Comparator) { public fun checkSorted(sorted: A.() -> R, sortedDescending: A.() -> R, iterator: R.() -> Iterator) { array.sorted().iterator().assertSorted { a, b -> comparator.compare(a, b) <= 0 } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 22fcbbf7be0..d5711fbc80f 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -9,7 +9,6 @@ import test.assertStaticAndRuntimeTypeIs import kotlin.test.* import test.collections.behaviors.* import test.comparisons.STRING_CASE_INSENSITIVE_ORDER -import kotlin.math.sin import kotlin.random.Random class CollectionTest { @@ -829,6 +828,21 @@ class CollectionTest { assertEquals(listOf("aa" to 20, "aa" to 3, "ab" to 3), data) } + @Test fun sortStable() { + val keyRange = 'A'..'D' + for (size in listOf(10, 100, 2000)) { + val list = MutableList(size) { index -> Sortable(keyRange.random(), index) } + + list.sorted().assertStableSorted() + list.sortedDescending().assertStableSorted(descending = true) + + list.sort() + list.assertStableSorted() + list.sortDescending() + list.assertStableSorted(descending = true) + } + } + @Test fun sortedBy() { assertEquals(listOf("two" to 3, "three" to 20), listOf("three" to 20, "two" to 3).sortedBy { it.second }) assertEquals(listOf("three" to 20, "two" to 3), listOf("three" to 20, "two" to 3).sortedBy { it.first }) @@ -862,6 +876,22 @@ class CollectionTest { expect(listOf("BAD", "dad", "cat")) { data.sortedWith(comparator.reversed().reversed()) } } + @Test fun sortByStable() { + val keyRange = 'A'..'D' + for (size in listOf(10, 100, 2000)) { + val list = MutableList(size) { index -> Sortable(keyRange.random(), index) } + + list.sortedBy { it.key }.assertStableSorted() + list.sortedByDescending { it.key }.assertStableSorted(descending = true) + + list.sortBy { it.key } + list.assertStableSorted() + + list.sortByDescending { it.key } + list.assertStableSorted(descending = true) + } + } + @Test fun decomposeFirst() { val (first) = listOf(1, 2) assertEquals(first, 1) diff --git a/libraries/stdlib/test/collections/IterableTests.kt b/libraries/stdlib/test/collections/IterableTests.kt index 274904b60b9..d090dff6c17 100644 --- a/libraries/stdlib/test/collections/IterableTests.kt +++ b/libraries/stdlib/test/collections/IterableTests.kt @@ -508,3 +508,17 @@ fun Iterator.assertSorted(isInOrder: (T, T) -> Boolean) { return } +data class Sortable>(val key: K, val index: Int) : Comparable> { + override fun compareTo(other: Sortable): Int = this.key.compareTo(other.key) +} + + +fun > Iterator>.assertStableSorted(descending: Boolean = false) { + assertSorted { a, b -> + val relation = a.key.compareTo(b.key) + (if (descending) relation > 0 else relation < 0) || relation == 0 && a.index < b.index + } +} + +fun > Iterable>.assertStableSorted(descending: Boolean = false) = + iterator().assertStableSorted(descending = descending) From 0ac85ad7152f7ecb1ff6b4bbb9d93d05b8fecb21 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 16 Jan 2019 02:50:34 +0300 Subject: [PATCH 22/33] Document that sorting is stable in each platform #KT-12473 Fixed --- .../stdlib/common/src/generated/_Arrays.kt | 26 ++++++++++++ .../common/src/generated/_Collections.kt | 16 ++++++++ .../stdlib/common/src/generated/_Sequences.kt | 10 +++++ .../js/irRuntime/generated/_ArraysJs.kt | 6 +++ .../stdlib/js/src/generated/_ArraysJs.kt | 6 +++ libraries/stdlib/js/src/kotlin/collections.kt | 4 ++ .../stdlib/jvm/src/generated/_ArraysJvm.kt | 10 +++++ .../collections/MutableCollectionsJVM.kt | 4 ++ .../kotlin-stdlib-gen/src/templates/Arrays.kt | 11 +++++ .../src/templates/Ordering.kt | 41 +++++++++++++++++++ 10 files changed, 134 insertions(+) diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index 59127d8e20c..cc15c5828d8 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -5040,6 +5040,8 @@ public fun CharArray.reversedArray(): CharArray { /** * Sorts elements in the array in-place according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > Array.sortBy(crossinline selector: (T) -> R?): Unit { if (size > 1) sortWith(compareBy(selector)) @@ -5047,6 +5049,8 @@ public inline fun > Array.sortBy(crossinline selecto /** * Sorts elements in the array in-place descending according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > Array.sortByDescending(crossinline selector: (T) -> R?): Unit { if (size > 1) sortWith(compareByDescending(selector)) @@ -5054,6 +5058,8 @@ public inline fun > Array.sortByDescending(crossinli /** * Sorts elements in the array in-place descending according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Array.sortDescending(): Unit { sortWith(reverseOrder()) @@ -5131,6 +5137,8 @@ public fun CharArray.sortDescending(): Unit { /** * Returns a list of all elements sorted according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Array.sorted(): List { return sortedArray().asList() @@ -5187,6 +5195,8 @@ public fun CharArray.sorted(): List { /** * Returns an array with all elements of this array sorted according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Array.sortedArray(): Array { if (isEmpty()) return this @@ -5251,6 +5261,8 @@ public fun CharArray.sortedArray(): CharArray { /** * Returns an array with all elements of this array sorted descending according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Array.sortedArrayDescending(): Array { if (isEmpty()) return this @@ -5315,6 +5327,8 @@ public fun CharArray.sortedArrayDescending(): CharArray { /** * Returns an array with all elements of this array sorted according the specified [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Array.sortedArrayWith(comparator: Comparator): Array { if (isEmpty()) return this @@ -5323,6 +5337,8 @@ public fun Array.sortedArrayWith(comparator: Comparator): Array /** * Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > Array.sortedBy(crossinline selector: (T) -> R?): List { return sortedWith(compareBy(selector)) @@ -5386,6 +5402,8 @@ public inline fun > CharArray.sortedBy(crossinline selector: ( /** * Returns a list of all elements sorted descending according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > Array.sortedByDescending(crossinline selector: (T) -> R?): List { return sortedWith(compareByDescending(selector)) @@ -5449,6 +5467,8 @@ public inline fun > CharArray.sortedByDescending(crossinline s /** * Returns a list of all elements sorted descending according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Array.sortedDescending(): List { return sortedWith(reverseOrder()) @@ -5505,6 +5525,8 @@ public fun CharArray.sortedDescending(): List { /** * Returns a list of all elements sorted according to the specified [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Array.sortedWith(comparator: Comparator): List { return sortedArrayWith(comparator).asList() @@ -6702,11 +6724,15 @@ public expect fun CharArray.sort(): Unit /** * Sorts the array in-place according to the natural order of its elements. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public expect fun > Array.sort(): Unit /** * Sorts the array in-place according to the order specified by the given [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public expect fun Array.sortWith(comparator: Comparator): Unit diff --git a/libraries/stdlib/common/src/generated/_Collections.kt b/libraries/stdlib/common/src/generated/_Collections.kt index 8b77a7f9ad1..1c045d13076 100644 --- a/libraries/stdlib/common/src/generated/_Collections.kt +++ b/libraries/stdlib/common/src/generated/_Collections.kt @@ -861,6 +861,8 @@ public fun Iterable.reversed(): List { /** * Sorts elements in the list in-place according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > MutableList.sortBy(crossinline selector: (T) -> R?): Unit { if (size > 1) sortWith(compareBy(selector)) @@ -868,6 +870,8 @@ public inline fun > MutableList.sortBy(crossinline selec /** * Sorts elements in the list in-place descending according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > MutableList.sortByDescending(crossinline selector: (T) -> R?): Unit { if (size > 1) sortWith(compareByDescending(selector)) @@ -875,6 +879,8 @@ public inline fun > MutableList.sortByDescending(crossin /** * Sorts elements in the list in-place descending according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > MutableList.sortDescending(): Unit { sortWith(reverseOrder()) @@ -882,6 +888,8 @@ public fun > MutableList.sortDescending(): Unit { /** * Returns a list of all elements sorted according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Iterable.sorted(): List { if (this is Collection) { @@ -894,6 +902,8 @@ public fun > Iterable.sorted(): List { /** * Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > Iterable.sortedBy(crossinline selector: (T) -> R?): List { return sortedWith(compareBy(selector)) @@ -901,6 +911,8 @@ public inline fun > Iterable.sortedBy(crossinline select /** * Returns a list of all elements sorted descending according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public inline fun > Iterable.sortedByDescending(crossinline selector: (T) -> R?): List { return sortedWith(compareByDescending(selector)) @@ -908,6 +920,8 @@ public inline fun > Iterable.sortedByDescending(crossinl /** * Returns a list of all elements sorted descending according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun > Iterable.sortedDescending(): List { return sortedWith(reverseOrder()) @@ -915,6 +929,8 @@ public fun > Iterable.sortedDescending(): List { /** * Returns a list of all elements sorted according to the specified [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Iterable.sortedWith(comparator: Comparator): List { if (this is Collection) { diff --git a/libraries/stdlib/common/src/generated/_Sequences.kt b/libraries/stdlib/common/src/generated/_Sequences.kt index 5ea1d117639..a22b5f70cdd 100644 --- a/libraries/stdlib/common/src/generated/_Sequences.kt +++ b/libraries/stdlib/common/src/generated/_Sequences.kt @@ -502,6 +502,8 @@ public fun Sequence.takeWhile(predicate: (T) -> Boolean): Sequence { /** * Returns a sequence that yields elements of this sequence sorted according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. * * The operation is _intermediate_ and _stateful_. */ @@ -517,6 +519,8 @@ public fun > Sequence.sorted(): Sequence { /** * Returns a sequence that yields elements of this sequence sorted according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. * * The operation is _intermediate_ and _stateful_. */ @@ -526,6 +530,8 @@ public inline fun > Sequence.sortedBy(crossinline select /** * Returns a sequence that yields elements of this sequence sorted descending according to natural sort order of the value returned by specified [selector] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. * * The operation is _intermediate_ and _stateful_. */ @@ -535,6 +541,8 @@ public inline fun > Sequence.sortedByDescending(crossinl /** * Returns a sequence that yields elements of this sequence sorted descending according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. * * The operation is _intermediate_ and _stateful_. */ @@ -544,6 +552,8 @@ public fun > Sequence.sortedDescending(): Sequence { /** * Returns a sequence that yields elements of this sequence sorted according to the specified [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. * * The operation is _intermediate_ and _stateful_. */ diff --git a/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt b/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt index 4af1303e786..f0617b7c9a4 100644 --- a/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt +++ b/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt @@ -1198,6 +1198,8 @@ public actual fun CharArray.sort(): Unit { /** * Sorts the array in-place according to the natural order of its elements. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun > Array.sort(): Unit { if (size > 1) sortArray(this) @@ -1205,6 +1207,8 @@ public actual fun > Array.sort(): Unit { /** * Sorts the array in-place according to the order specified by the given [comparison] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Array.sort(comparison: (a: T, b: T) -> Int): Unit { if (size > 1) sortArrayWith(this, comparison) @@ -1268,6 +1272,8 @@ public inline fun CharArray.sort(noinline comparison: (a: Char, b: Char) -> Int) /** * Sorts the array in-place according to the order specified by the given [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun Array.sortWith(comparator: Comparator): Unit { if (size > 1) sortArrayWith(this, comparator) diff --git a/libraries/stdlib/js/src/generated/_ArraysJs.kt b/libraries/stdlib/js/src/generated/_ArraysJs.kt index e2144d233d5..639b78f8e13 100644 --- a/libraries/stdlib/js/src/generated/_ArraysJs.kt +++ b/libraries/stdlib/js/src/generated/_ArraysJs.kt @@ -1234,6 +1234,8 @@ public actual fun CharArray.sort(): Unit { /** * Sorts the array in-place according to the natural order of its elements. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun > Array.sort(): Unit { if (size > 1) sortArray(this) @@ -1241,6 +1243,8 @@ public actual fun > Array.sort(): Unit { /** * Sorts the array in-place according to the order specified by the given [comparison] function. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Array.sort(comparison: (a: T, b: T) -> Int): Unit { if (size > 1) sortArrayWith(this, comparison) @@ -1304,6 +1308,8 @@ public inline fun CharArray.sort(noinline comparison: (a: Char, b: Char) -> Int) /** * Sorts the array in-place according to the order specified by the given [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun Array.sortWith(comparator: Comparator): Unit { if (size > 1) sortArrayWith(this, comparator) diff --git a/libraries/stdlib/js/src/kotlin/collections.kt b/libraries/stdlib/js/src/kotlin/collections.kt index 6abd57149f3..a7c52b110f8 100644 --- a/libraries/stdlib/js/src/kotlin/collections.kt +++ b/libraries/stdlib/js/src/kotlin/collections.kt @@ -93,6 +93,8 @@ public actual fun Iterable.shuffled(): List = toMutableList().apply { /** * Sorts elements in the list in-place according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun > MutableList.sort(): Unit { collectionsSort(this, naturalOrder()) @@ -100,6 +102,8 @@ public actual fun > MutableList.sort(): Unit { /** * Sorts elements in the list in-place according to the order specified with [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun MutableList.sortWith(comparator: Comparator): Unit { collectionsSort(this, comparator) diff --git a/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt b/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt index 770b6a33d80..4ef29d904bf 100644 --- a/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt +++ b/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt @@ -1685,6 +1685,8 @@ public actual fun CharArray.sort(): Unit { /** * Sorts the array in-place according to the natural order of its elements. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ @kotlin.internal.InlineOnly public actual inline fun > Array.sort(): Unit { @@ -1695,6 +1697,8 @@ public actual inline fun > Array.sort(): Unit { /** * Sorts the array in-place according to the natural order of its elements. * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. + * * @throws ClassCastException if any element of the array is not [Comparable]. */ public fun Array.sort(): Unit { @@ -1703,6 +1707,8 @@ public fun Array.sort(): Unit { /** * Sorts a range in the array in-place. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Array.sort(fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.sort(this, fromIndex, toIndex) @@ -1759,6 +1765,8 @@ public fun CharArray.sort(fromIndex: Int = 0, toIndex: Int = size): Unit { /** * Sorts the array in-place according to the order specified by the given [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun Array.sortWith(comparator: Comparator): Unit { if (size > 1) java.util.Arrays.sort(this, comparator) @@ -1766,6 +1774,8 @@ public actual fun Array.sortWith(comparator: Comparator): Unit /** * Sorts a range in the array in-place with the given [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public fun Array.sortWith(comparator: Comparator, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.sort(this, fromIndex, toIndex, comparator) diff --git a/libraries/stdlib/jvm/src/kotlin/collections/MutableCollectionsJVM.kt b/libraries/stdlib/jvm/src/kotlin/collections/MutableCollectionsJVM.kt index 5fc774ea036..a861574744c 100644 --- a/libraries/stdlib/jvm/src/kotlin/collections/MutableCollectionsJVM.kt +++ b/libraries/stdlib/jvm/src/kotlin/collections/MutableCollectionsJVM.kt @@ -22,6 +22,8 @@ public inline fun MutableList.sort(comparison: (T, T) -> Int): Unit = thr /** * Sorts elements in the list in-place according to their natural sort order. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun > MutableList.sort(): Unit { if (size > 1) java.util.Collections.sort(this) @@ -29,6 +31,8 @@ public actual fun > MutableList.sort(): Unit { /** * Sorts elements in the list in-place according to the order specified with [comparator]. + * + * The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting. */ public actual fun MutableList.sortWith(comparator: Comparator): Unit { if (size > 1) java.util.Collections.sort(this, comparator) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt index c92f7da1673..5849f683d28 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt @@ -6,6 +6,8 @@ package templates import templates.Family.* +import templates.Ordering.stableSortNote +import templates.Ordering.appendStableSortNote object ArrayOps : TemplateGroupBase() { @@ -884,6 +886,7 @@ object ArrayOps : TemplateGroupBase() { } builder { typeParam("T : Comparable") doc { "Sorts the array in-place according to the natural order of its elements." } + appendStableSortNote() specialFor(ArraysOfPrimitives) { doc { "Sorts the array in-place." } } @@ -939,6 +942,7 @@ object ArrayOps : TemplateGroupBase() { include(ArraysOfObjects) } builder { doc { "Sorts the array in-place according to the order specified by the given [comparator]." } + appendStableSortNote() returns("Unit") on(Platform.JVM) { body { @@ -968,6 +972,7 @@ object ArrayOps : TemplateGroupBase() { body { "asDynamic().sort(comparison)" } } specialFor(ArraysOfObjects) { + appendStableSortNote() body { """if (size > 1) sortArrayWith(this, comparison)""" } } } @@ -981,6 +986,8 @@ object ArrayOps : TemplateGroupBase() { """ Sorts the array in-place according to the natural order of its elements. + $stableSortNote + @throws ClassCastException if any element of the array is not [Comparable]. """ } @@ -996,6 +1003,9 @@ object ArrayOps : TemplateGroupBase() { exclude(PrimitiveType.Boolean) } builder { doc { "Sorts a range in the array in-place." } + specialFor(ArraysOfObjects) { + appendStableSortNote() + } returns("Unit") body { "java.util.Arrays.sort(this, fromIndex, toIndex)" @@ -1007,6 +1017,7 @@ object ArrayOps : TemplateGroupBase() { include(ArraysOfObjects) } builder { doc { "Sorts a range in the array in-place with the given [comparator]." } + appendStableSortNote() returns("Unit") body { "java.util.Arrays.sort(this, fromIndex, toIndex, comparator)" diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt index e441ecf4a04..ee1246e0286 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt @@ -96,6 +96,15 @@ object Ordering : TemplateGroupBase() { } } + val stableSortNote = + "The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting." + + fun MemberBuilder.appendStableSortNote() { + doc { + doc.orEmpty().trimIndent() + "\n\n" + stableSortNote + } + } + val f_sorted = fn("sorted()") { includeDefault() exclude(PrimitiveType.Boolean) @@ -106,6 +115,9 @@ object Ordering : TemplateGroupBase() { Returns a list of all elements sorted according to their natural sort order. """ } + if (f != ArraysOfPrimitives) { + appendStableSortNote() + } returns("List") typeParam("T : Comparable") body { @@ -134,6 +146,7 @@ object Ordering : TemplateGroupBase() { doc { "Returns a sequence that yields elements of this sequence sorted according to their natural sort order." } + appendStableSortNote() sequenceClassification(intermediate, stateful) } body(Sequences) { @@ -156,6 +169,9 @@ object Ordering : TemplateGroupBase() { doc { "Returns an array with all elements of this array sorted according to their natural sort order." } + specialFor(InvariantArraysOfObjects) { + appendStableSortNote() + } typeParam("T : Comparable") returns("SELF") body { @@ -171,6 +187,9 @@ object Ordering : TemplateGroupBase() { exclude(PrimitiveType.Boolean) } builder { doc { """Sorts elements in the ${f.collection} in-place descending according to their natural sort order.""" } + if (f != ArraysOfPrimitives) { + appendStableSortNote() + } returns("Unit") typeParam("T : Comparable") specialFor(Lists) { @@ -198,6 +217,9 @@ object Ordering : TemplateGroupBase() { Returns a list of all elements sorted descending according to their natural sort order. """ } + if (f != ArraysOfPrimitives) { + appendStableSortNote() + } returns("List") typeParam("T : Comparable") body { @@ -216,6 +238,7 @@ object Ordering : TemplateGroupBase() { doc { "Returns a sequence that yields elements of this sequence sorted descending according to their natural sort order." } + appendStableSortNote() sequenceClassification(intermediate, stateful) } } @@ -227,6 +250,9 @@ object Ordering : TemplateGroupBase() { doc { "Returns an array with all elements of this array sorted descending according to their natural sort order." } + specialFor(InvariantArraysOfObjects) { + appendStableSortNote() + } typeParam("T : Comparable") returns("SELF") body(InvariantArraysOfObjects) { @@ -252,6 +278,9 @@ object Ordering : TemplateGroupBase() { Returns a list of all elements sorted according to the specified [comparator]. """ } + if (f != ArraysOfPrimitives) { + appendStableSortNote() + } body { """ if (this is Collection) { @@ -278,6 +307,7 @@ object Ordering : TemplateGroupBase() { doc { "Returns a sequence that yields elements of this sequence sorted according to the specified [comparator]." } + appendStableSortNote() sequenceClassification(intermediate, stateful) } body(Sequences) { @@ -299,6 +329,7 @@ object Ordering : TemplateGroupBase() { doc { "Returns an array with all elements of this array sorted according the specified [comparator]." } + appendStableSortNote() returns("SELF") body { """ @@ -313,6 +344,7 @@ object Ordering : TemplateGroupBase() { } builder { inline() doc { """Sorts elements in the ${f.collection} in-place according to natural sort order of the value returned by specified [selector] function.""" } + appendStableSortNote() returns("Unit") typeParam("R : Comparable") specialFor(Lists) { receiver("MutableList") } @@ -332,12 +364,16 @@ object Ordering : TemplateGroupBase() { Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function. """ } + if (f != ArraysOfPrimitives) { + appendStableSortNote() + } specialFor(Sequences) { returns("SELF") doc { "Returns a sequence that yields elements of this sequence sorted according to natural sort order of the value returned by specified [selector] function." } + appendStableSortNote() sequenceClassification(intermediate, stateful) } body { @@ -350,6 +386,7 @@ object Ordering : TemplateGroupBase() { } builder { inline() doc { """Sorts elements in the ${f.collection} in-place descending according to natural sort order of the value returned by specified [selector] function.""" } + appendStableSortNote() returns("Unit") typeParam("R : Comparable") specialFor(Lists) { receiver("MutableList") } @@ -370,12 +407,16 @@ object Ordering : TemplateGroupBase() { Returns a list of all elements sorted descending according to natural sort order of the value returned by specified [selector] function. """ } + if (f != ArraysOfPrimitives) { + appendStableSortNote() + } specialFor(Sequences) { returns("SELF") doc { "Returns a sequence that yields elements of this sequence sorted descending according to natural sort order of the value returned by specified [selector] function." } + appendStableSortNote() sequenceClassification(intermediate, stateful) } From 6a3e5c4c94db90fe24d2dad6b4f293eda895152f Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Mon, 14 Jan 2019 18:20:14 +0300 Subject: [PATCH 23/33] Build: Move protobuf projects to subdirectory #KT-29202 --- buildSrc/src/main/kotlin/dependencies.kt | 5 +++-- .../{ => protobuf}/protobuf-lite/build.gradle.kts | 4 ++-- .../{ => protobuf}/protobuf-relocated/build.gradle.kts | 0 settings.gradle | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) rename custom-dependencies/{ => protobuf}/protobuf-lite/build.gradle.kts (95%) rename custom-dependencies/{ => protobuf}/protobuf-relocated/build.gradle.kts (100%) diff --git a/buildSrc/src/main/kotlin/dependencies.kt b/buildSrc/src/main/kotlin/dependencies.kt index 105c05a3be5..05a5582dc81 100644 --- a/buildSrc/src/main/kotlin/dependencies.kt +++ b/buildSrc/src/main/kotlin/dependencies.kt @@ -64,8 +64,9 @@ fun DependencyHandler.projectRuntimeJar(name: String): ProjectDependency = proje fun DependencyHandler.projectArchives(name: String): ProjectDependency = project(name, configuration = "archives") fun DependencyHandler.projectClasses(name: String): ProjectDependency = project(name, configuration = "classes-dirs") -val protobufLiteProject = ":custom-dependencies:protobuf-lite" -val protobufRelocatedProject = ":custom-dependencies:protobuf-relocated" +val protobufLiteProject = ":custom-dependencies:protobuf:protobuf-lite" +val protobufRelocatedProject = ":custom-dependencies:protobuf:protobuf-relocated" + fun DependencyHandler.protobufLite(): ProjectDependency = project(protobufLiteProject, configuration = "default").apply { isTransitive = false } val protobufLiteTask = "$protobufLiteProject:prepare" diff --git a/custom-dependencies/protobuf-lite/build.gradle.kts b/custom-dependencies/protobuf/protobuf-lite/build.gradle.kts similarity index 95% rename from custom-dependencies/protobuf-lite/build.gradle.kts rename to custom-dependencies/protobuf/protobuf-lite/build.gradle.kts index 4b539e4578d..8ed785c1368 100644 --- a/custom-dependencies/protobuf-lite/build.gradle.kts +++ b/custom-dependencies/protobuf/protobuf-lite/build.gradle.kts @@ -16,8 +16,8 @@ val protobufJarPrefix = "protobuf-$protobufVersion" val outputJarPath = "$buildDir/libs/$protobufJarPrefix-lite.jar" dependencies { - relocatedProtobuf(project(":custom-dependencies:protobuf-relocated", configuration = "default")) - relocatedProtobufSources(project(":custom-dependencies:protobuf-relocated", configuration = "sources")) + relocatedProtobuf(project(":custom-dependencies:protobuf:protobuf-relocated", configuration = "default")) + relocatedProtobufSources(project(":custom-dependencies:protobuf:protobuf-relocated", configuration = "sources")) } task("prepare") { diff --git a/custom-dependencies/protobuf-relocated/build.gradle.kts b/custom-dependencies/protobuf/protobuf-relocated/build.gradle.kts similarity index 100% rename from custom-dependencies/protobuf-relocated/build.gradle.kts rename to custom-dependencies/protobuf/protobuf-relocated/build.gradle.kts diff --git a/settings.gradle b/settings.gradle index 0ce7ebec63a..da0cf825aad 100644 --- a/settings.gradle +++ b/settings.gradle @@ -73,8 +73,8 @@ include ":kotlin-build-common", ":core:metadata.jvm", ":core:builtins", ":core:util.runtime", - ":custom-dependencies:protobuf-relocated", - ":custom-dependencies:protobuf-lite", + ":custom-dependencies:protobuf:protobuf-relocated", + ":custom-dependencies:protobuf:protobuf-lite", ":custom-dependencies:android-sdk", ":idea:fir-view", ":idea:idea-jvm", From c7ab69829ec453b8559471691074af93103b0a66 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Mon, 14 Jan 2019 20:52:43 +0300 Subject: [PATCH 24/33] Build: Convert protobuf to includable build with maven publication #KT-29202 --- .idea/dictionaries/4u7.xml | 1 + buildSrc/src/main/kotlin/dependencies.kt | 11 +-- core/metadata/build.gradle.kts | 5 -- custom-dependencies/protobuf/build.gradle.kts | 7 ++ .../protobuf/protobuf-lite/build.gradle.kts | 58 ++++++++++----- .../protobuf-relocated/build.gradle.kts | 70 ++++++++++++------- custom-dependencies/protobuf/settings.gradle | 1 + settings.gradle | 5 +- 8 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 custom-dependencies/protobuf/build.gradle.kts create mode 100644 custom-dependencies/protobuf/settings.gradle diff --git a/.idea/dictionaries/4u7.xml b/.idea/dictionaries/4u7.xml index 720bcaa440d..b9beee98b70 100644 --- a/.idea/dictionaries/4u7.xml +++ b/.idea/dictionaries/4u7.xml @@ -4,6 +4,7 @@ cidr foldable instrumentator + protobuf redirector diff --git a/buildSrc/src/main/kotlin/dependencies.kt b/buildSrc/src/main/kotlin/dependencies.kt index 05a5582dc81..af0f018c8d2 100644 --- a/buildSrc/src/main/kotlin/dependencies.kt +++ b/buildSrc/src/main/kotlin/dependencies.kt @@ -64,15 +64,8 @@ fun DependencyHandler.projectRuntimeJar(name: String): ProjectDependency = proje fun DependencyHandler.projectArchives(name: String): ProjectDependency = project(name, configuration = "archives") fun DependencyHandler.projectClasses(name: String): ProjectDependency = project(name, configuration = "classes-dirs") -val protobufLiteProject = ":custom-dependencies:protobuf:protobuf-lite" -val protobufRelocatedProject = ":custom-dependencies:protobuf:protobuf-relocated" - -fun DependencyHandler.protobufLite(): ProjectDependency = - project(protobufLiteProject, configuration = "default").apply { isTransitive = false } -val protobufLiteTask = "$protobufLiteProject:prepare" - -fun DependencyHandler.protobufFull(): ProjectDependency = - project(protobufRelocatedProject, configuration = "default").apply { isTransitive = false } +fun Project.protobufLite(): String = "org.jetbrains.kotlin:protobuf-lite:" + findProperty("versions.protobuf-java") as String +fun Project.protobufFull(): String = "org.jetbrains.kotlin:protobuf-relocated:" + findProperty("versions.protobuf-java") as String fun File.matchMaybeVersionedArtifact(baseName: String) = name.matches(baseName.toMaybeVersionedJarRegex()) diff --git a/core/metadata/build.gradle.kts b/core/metadata/build.gradle.kts index 54ce446e705..6be04082b07 100644 --- a/core/metadata/build.gradle.kts +++ b/core/metadata/build.gradle.kts @@ -20,11 +20,6 @@ sourceSets { } tasks.withType { - dependsOn(protobufLiteTask) sourceCompatibility = "1.6" targetCompatibility = "1.6" } - -tasks.withType { - dependsOn(protobufLiteTask) -} diff --git a/custom-dependencies/protobuf/build.gradle.kts b/custom-dependencies/protobuf/build.gradle.kts new file mode 100644 index 00000000000..0b171efb1fe --- /dev/null +++ b/custom-dependencies/protobuf/build.gradle.kts @@ -0,0 +1,7 @@ + +val protobufVersion by extra("2.6.1") + +allprojects { + group = "org.jetbrains.kotlin" + version = protobufVersion +} \ No newline at end of file diff --git a/custom-dependencies/protobuf/protobuf-lite/build.gradle.kts b/custom-dependencies/protobuf/protobuf-lite/build.gradle.kts index 8ed785c1368..cd8d182bbf9 100644 --- a/custom-dependencies/protobuf/protobuf-lite/build.gradle.kts +++ b/custom-dependencies/protobuf/protobuf-lite/build.gradle.kts @@ -6,21 +6,23 @@ import java.util.jar.JarEntry import java.util.jar.JarFile import java.util.zip.ZipOutputStream +plugins { + base + `maven-publish` +} + val relocatedProtobuf by configurations.creating val relocatedProtobufSources by configurations.creating -val resultsCfg = configurations.create("default") - -val protobufVersion = rootProject.extra["versions.protobuf-java"] +val protobufVersion: String by rootProject.extra val protobufJarPrefix = "protobuf-$protobufVersion" val outputJarPath = "$buildDir/libs/$protobufJarPrefix-lite.jar" dependencies { - relocatedProtobuf(project(":custom-dependencies:protobuf:protobuf-relocated", configuration = "default")) - relocatedProtobufSources(project(":custom-dependencies:protobuf:protobuf-relocated", configuration = "sources")) + relocatedProtobuf(project(":protobuf-relocated")) } -task("prepare") { +val prepare by tasks.creating { inputs.files(relocatedProtobuf) // this also adds a dependency outputs.file(outputJarPath) doFirst { @@ -41,7 +43,11 @@ task("prepare") { return result } - val allFiles = loadAllFromJar(relocatedProtobuf.singleFile) + val mainJar = relocatedProtobuf.resolvedConfiguration.resolvedArtifacts.single { + it.name == "protobuf-relocated" && it.classifier == null + }.file + + val allFiles = loadAllFromJar(mainJar) val keepClasses = arrayListOf() @@ -80,18 +86,38 @@ task("prepare") { } } } - addArtifact("archives", this, outputs.files.singleFile) { - classifier = "" - } - addArtifact(resultsCfg, this, outputs.files.singleFile) { - classifier = "" - } } -val clean by task { - delete(buildDir) +val mainArtifact = artifacts.add( + "default", + provider { + prepare.outputs.files.singleFile + } +) { + builtBy(prepare) + classifier = "" } -artifacts.add("archives", relocatedProtobufSources.files.single()) { +val sourcesArtifact = artifacts.add( + "default", + provider { + relocatedProtobuf.resolvedConfiguration.resolvedArtifacts.single { it.name == "protobuf-relocated" && it.classifier == "sources" }.file + } +) { classifier = "sources" } + +publishing { + publications { + create("maven") { + artifact(mainArtifact) + artifact(sourcesArtifact) + } + } + + repositories { + maven { + url = uri("${rootProject.buildDir}/internal/repo") + } + } +} diff --git a/custom-dependencies/protobuf/protobuf-relocated/build.gradle.kts b/custom-dependencies/protobuf/protobuf-relocated/build.gradle.kts index 4e20d76d49c..98c077ec55e 100644 --- a/custom-dependencies/protobuf/protobuf-relocated/build.gradle.kts +++ b/custom-dependencies/protobuf/protobuf-relocated/build.gradle.kts @@ -2,61 +2,79 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import java.io.File plugins { - base - id("pill-configurable") + `java-base` + `maven-publish` + id("com.github.johnrengelman.shadow") version "4.0.3" apply false +} + +repositories { + jcenter() } val baseProtobuf by configurations.creating val baseProtobufSources by configurations.creating -val resultsCfg = configurations.getByName("default") -val resultsSourcesCfg = configurations.create("sources") - -val protobufVersion = rootProject.extra["versions.protobuf-java"] as String +val protobufVersion: String by rootProject.extra val protobufJarPrefix = "protobuf-$protobufVersion" val renamedSources = "$buildDir/renamedSrc/" val outputJarsPath = "$buildDir/libs" -val artifactBaseName = "protobuf-java-relocated" - -pill { - libraryPath = File(outputJarsPath) -} - -setProperty("archivesBaseName", "$artifactBaseName-$protobufVersion") dependencies { baseProtobuf("com.google.protobuf:protobuf-java:$protobufVersion") baseProtobufSources("com.google.protobuf:protobuf-java:$protobufVersion:sources") } -val prepare by task { +val prepare = task("prepare") { destinationDir = File(outputJarsPath) - baseName = artifactBaseName version = protobufVersion classifier = "" - from(baseProtobuf.files.find { it.name.startsWith("protobuf-java") }?.canonicalPath) + from( + provider { + baseProtobuf.files.find { it.name.startsWith("protobuf-java") }?.canonicalPath + } + ) relocate("com.google.protobuf", "org.jetbrains.kotlin.protobuf" ) { exclude("META-INF/maven/com.google.protobuf/protobuf-java/pom.properties") } - addArtifact("archives", this, this) - addArtifact(resultsCfg.name, this, this) } -val relocateSources by task { - from(zipTree(baseProtobufSources.files.find { it.name.startsWith("protobuf-java") && it.name.endsWith("-sources.jar") } - ?: throw GradleException("sources jar not found among ${baseProtobufSources.files}"))) +artifacts.add("default", prepare) + +val relocateSources = task("relocateSources") { + from( + provider { + zipTree(baseProtobufSources.files.find { it.name.startsWith("protobuf-java") && it.name.endsWith("-sources.jar") } + ?: throw GradleException("sources jar not found among ${baseProtobufSources.files}")) + } + ) + into(renamedSources) + filter { it.replace("com.google.protobuf", "org.jetbrains.kotlin.protobuf") } } -val prepareSources by task { +val prepareSources = task("prepareSources") { destinationDir = File(outputJarsPath) - baseName = artifactBaseName version = protobufVersion classifier = "sources" from(relocateSources) - project.addArtifact("archives", this, this) - addArtifact(resultsSourcesCfg.name, this, this) -} \ No newline at end of file +} + +artifacts.add("default", prepareSources) + +publishing { + publications { + create("maven") { + artifact(prepare) + artifact(prepareSources) + } + } + + repositories { + maven { + url = uri("${rootProject.buildDir}/internal/repo") + } + } +} diff --git a/custom-dependencies/protobuf/settings.gradle b/custom-dependencies/protobuf/settings.gradle new file mode 100644 index 00000000000..c8dbba7a5cf --- /dev/null +++ b/custom-dependencies/protobuf/settings.gradle @@ -0,0 +1 @@ +include ":protobuf-lite", ":protobuf-relocated" \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index da0cf825aad..90affe6c207 100644 --- a/settings.gradle +++ b/settings.gradle @@ -73,8 +73,6 @@ include ":kotlin-build-common", ":core:metadata.jvm", ":core:builtins", ":core:util.runtime", - ":custom-dependencies:protobuf:protobuf-relocated", - ":custom-dependencies:protobuf:protobuf-lite", ":custom-dependencies:android-sdk", ":idea:fir-view", ":idea:idea-jvm", @@ -349,3 +347,6 @@ project(':kotlinx-serialization-ide-plugin').projectDir = file("$rootDir/plugins project(':kotlin-serialization').projectDir = file("$rootDir/libraries/tools/kotlin-serialization") project(':kotlin-serialization-unshaded').projectDir = file("$rootDir/libraries/tools/kotlin-serialization-unshaded") project(':kotlin-idl2k').projectDir = file("$rootDir/libraries/tools/idl2k") + + +includeBuild("custom-dependencies/protobuf") From 1efd859909f5d6abc99d3f8381f38b6fad467d70 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Wed, 16 Jan 2019 00:27:28 +0300 Subject: [PATCH 25/33] Exclude protobuf-relocated build directory in CodeConformanceTest #KT-29202 --- .../tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt b/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt index 4e99bebbd09..a24d0107679 100644 --- a/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt @@ -49,7 +49,8 @@ class CodeConformanceTest : TestCase() { "libraries/tools/kotlinp/src", "compiler/testData/psi/kdoc", "compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt", - "compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java" + "compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java", + "custom-dependencies/protobuf/protobuf-relocated/build" ).map(::File) private val COPYRIGHT_EXCLUDED_FILES_AND_DIRS = listOf( @@ -57,6 +58,7 @@ class CodeConformanceTest : TestCase() { "out", "dist", "custom-dependencies/android-sdk/build", + "custom-dependencies/protobuf/protobuf-relocated/build", "compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt", "idea/idea-jvm/src/org/jetbrains/kotlin/idea/copyright", "js/js.tests/.gradle", From b525146009dca0458b6ed32b69778f4f1219eb28 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Wed, 16 Jan 2019 01:43:12 +0300 Subject: [PATCH 26/33] Build: Switch to prebuilt protobuf-lite from teamcity repo #KT-29202 --- build.gradle.kts | 3 ++- buildSrc/src/main/kotlin/dependencies.kt | 9 +++++++-- settings.gradle | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fc5fed61b81..958a133d872 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -149,7 +149,7 @@ rootProject.apply { IdeVersionConfigurator.setCurrentIde(this) -extra["versions.protobuf-java"] = "2.6.1" +extra["versions.protobuf"] = "2.6.1" extra["versions.javax.inject"] = "1" extra["versions.jsr305"] = "1.3.9" extra["versions.jansi"] = "1.16" @@ -317,6 +317,7 @@ allprojects { mirrorRepo?.let(::maven) bootstrapKotlinRepo?.let(::maven) jcenter() + maven(protobufRepo) } configureJvmProject(javaHome!!, jvmTarget!!) diff --git a/buildSrc/src/main/kotlin/dependencies.kt b/buildSrc/src/main/kotlin/dependencies.kt index af0f018c8d2..c0d44099c36 100644 --- a/buildSrc/src/main/kotlin/dependencies.kt +++ b/buildSrc/src/main/kotlin/dependencies.kt @@ -64,8 +64,13 @@ fun DependencyHandler.projectRuntimeJar(name: String): ProjectDependency = proje fun DependencyHandler.projectArchives(name: String): ProjectDependency = project(name, configuration = "archives") fun DependencyHandler.projectClasses(name: String): ProjectDependency = project(name, configuration = "classes-dirs") -fun Project.protobufLite(): String = "org.jetbrains.kotlin:protobuf-lite:" + findProperty("versions.protobuf-java") as String -fun Project.protobufFull(): String = "org.jetbrains.kotlin:protobuf-relocated:" + findProperty("versions.protobuf-java") as String +val Project.protobufVersion: String get() = findProperty("versions.protobuf") as String + +val Project.protobufRepo: String get() = + "https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_Protobuf),status:SUCCESS,pinned:true,tag:$protobufVersion/artifacts/content/internal/repo/" + +fun Project.protobufLite(): String = "org.jetbrains.kotlin:protobuf-lite:$protobufVersion" +fun Project.protobufFull(): String = "org.jetbrains.kotlin:protobuf-relocated:$protobufVersion" fun File.matchMaybeVersionedArtifact(baseName: String) = name.matches(baseName.toMaybeVersionedJarRegex()) diff --git a/settings.gradle b/settings.gradle index 90affe6c207..729707c6b40 100644 --- a/settings.gradle +++ b/settings.gradle @@ -348,5 +348,5 @@ project(':kotlin-serialization').projectDir = file("$rootDir/libraries/tools/kot project(':kotlin-serialization-unshaded').projectDir = file("$rootDir/libraries/tools/kotlin-serialization-unshaded") project(':kotlin-idl2k').projectDir = file("$rootDir/libraries/tools/idl2k") - -includeBuild("custom-dependencies/protobuf") +// Uncomment to use locally built protobuf-relocated +// includeBuild("custom-dependencies/protobuf") From da0a8239928cb81028130acd196165444f82c847 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Tue, 13 Nov 2018 18:15:26 +0300 Subject: [PATCH 27/33] Remove descriptors from LocalDeclarationslowering --- .../common/lower/LocalDeclarationsLowering.kt | 12 +++++----- .../common/lower/SharedVariablesLowering.kt | 6 ++--- .../kotlin/ir/declarations/IrClass.kt | 6 +++-- .../kotlin/ir/declarations/IrDeclaration.kt | 5 +++++ .../kotlin/ir/declarations/IrEnumEntry.kt | 5 +---- .../kotlin/ir/declarations/IrField.kt | 2 -- .../kotlin/ir/declarations/IrFunction.kt | 6 ++--- .../declarations/IrLocalDelegatedProperty.kt | 4 +--- .../kotlin/ir/declarations/IrProperty.kt | 5 +---- .../kotlin/ir/declarations/IrTypeParameter.kt | 4 +--- .../ir/declarations/IrValueDeclaration.kt | 5 +---- .../closures/crossinlineLocalDeclaration.kt | 22 +++++++++++++++++++ .../crossInlineWithCapturedOuterReceiver.kt | 1 + .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++++ .../LightAnalysisModeTestGenerated.java | 5 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++++ .../IrJsCodegenBoxTestGenerated.java | 5 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++++ 18 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 3f3f7261577..804d5e158ca 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -40,8 +40,8 @@ import org.jetbrains.kotlin.name.NameUtils import java.util.* interface LocalNameProvider { - fun localName(descriptor: DeclarationDescriptor): String = - descriptor.name.asString() + fun localName(declaration: IrDeclarationWithName): String = + declaration.name.asString() companion object { val DEFAULT = object : LocalNameProvider {} @@ -465,13 +465,13 @@ class LocalDeclarationsLowering( } } - private fun suggestLocalName(declaration: IrDeclaration): String { + private fun suggestLocalName(declaration: IrDeclarationWithName): String { localFunctions[declaration]?.let { if (it.index >= 0) return "lambda-${it.index}" } - return localNameProvider.localName(declaration.descriptor) + return localNameProvider.localName(declaration) } private fun generateNameForLiftedDeclaration( @@ -481,7 +481,7 @@ class LocalDeclarationsLowering( Name.identifier( declaration.parentsWithSelf .takeWhile { it != newOwner } - .toList().reversed().joinToString(separator = "$") { suggestLocalName(it as IrDeclaration) } + .toList().reversed().joinToString(separator = "$") { suggestLocalName(it as IrDeclarationWithName) } ) private fun createLiftedDeclaration(localFunctionContext: LocalFunctionContext) { @@ -773,4 +773,4 @@ class LocalDeclarationsLowering( } } -} \ No newline at end of file +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt index 9e5883f7f1a..77ea77feb9c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt @@ -89,7 +89,7 @@ class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPas } private fun rewriteSharedVariables() { - val transformedDescriptors = HashMap() + val transformedSymbols = HashMap() irFunction.transformChildrenVoid(object : IrElementTransformerVoid() { override fun visitVariable(declaration: IrVariable): IrStatement { @@ -99,7 +99,7 @@ class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPas val newDeclaration = context.sharedVariablesManager.declareSharedVariable(declaration) newDeclaration.parent = irFunction - transformedDescriptors[declaration.symbol] = newDeclaration.symbol + transformedSymbols[declaration.symbol] = newDeclaration.symbol return context.sharedVariablesManager.defineSharedValue(declaration, newDeclaration) } @@ -123,7 +123,7 @@ class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPas } private fun getTransformedSymbol(oldSymbol: IrValueSymbol): IrVariableSymbol? = - transformedDescriptors.getOrElse(oldSymbol) { + transformedSymbols.getOrElse(oldSymbol) { assert(oldSymbol.owner !in sharedVariables) { "Shared variable is not transformed: ${oldSymbol.owner.dump()}" } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt index bbf7d75e4ef..c59fca4f864 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt @@ -24,10 +24,12 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.name.Name -interface IrClass : IrSymbolDeclaration, IrDeclarationWithVisibility, IrDeclarationContainer, IrTypeParametersContainer { +interface IrClass : + IrSymbolDeclaration, IrDeclarationWithName, IrDeclarationWithVisibility, + IrDeclarationContainer, IrTypeParametersContainer { + override val descriptor: ClassDescriptor - val name: Name val kind: ClassKind val modality: Modality val isCompanion: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt index 2f69f8bd230..9b162ea64b3 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.visitors.IrElementTransformer +import org.jetbrains.kotlin.name.Name interface IrSymbolOwner : IrElement { val symbol: IrSymbol @@ -49,3 +50,7 @@ interface IrDeclarationWithVisibility : IrDeclaration { val visibility: Visibility } +interface IrDeclarationWithName : IrDeclaration { + val name: Name +} + diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrEnumEntry.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrEnumEntry.kt index 160c0eceddf..93252f854ff 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrEnumEntry.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrEnumEntry.kt @@ -19,13 +19,10 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol -import org.jetbrains.kotlin.name.Name -interface IrEnumEntry : IrSymbolDeclaration { +interface IrEnumEntry : IrSymbolDeclaration, IrDeclarationWithName { override val descriptor: ClassDescriptor - val name: Name - var correspondingClass: IrClass? var initializerExpression: IrExpression? } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt index b5f770b9c35..8b55518304e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt @@ -9,12 +9,10 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.name.Name interface IrField : IrSymbolDeclaration, IrOverridableDeclaration, IrDeclarationWithVisibility, IrDeclarationParent { override val descriptor: PropertyDescriptor - val name: Name val type: IrType val isFinal: Boolean val isExternal: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt index d4d69e31695..3547a2b57a5 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt @@ -22,13 +22,13 @@ import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.name.Name -interface IrFunction : IrDeclarationWithVisibility, IrTypeParametersContainer, IrSymbolOwner, IrDeclarationParent, IrReturnTarget { +interface IrFunction : + IrDeclarationWithName, IrDeclarationWithVisibility, IrTypeParametersContainer, IrSymbolOwner, IrDeclarationParent, IrReturnTarget { + override val descriptor: FunctionDescriptor override val symbol: IrFunctionSymbol - val name: Name val isInline: Boolean // NB: there's an inline constructor for Array and each primitive array class val isExternal: Boolean var returnType: IrType diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrLocalDelegatedProperty.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrLocalDelegatedProperty.kt index a08662334ea..b31f45d4a0f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrLocalDelegatedProperty.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrLocalDelegatedProperty.kt @@ -18,12 +18,10 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.name.Name -interface IrLocalDelegatedProperty : IrDeclaration { +interface IrLocalDelegatedProperty : IrDeclarationWithName { override val descriptor: VariableDescriptorWithAccessors - val name: Name val type: IrType val isVar: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt index fe80b3c54b6..6c2710bcb4c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt @@ -18,13 +18,10 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.Visibility -import org.jetbrains.kotlin.name.Name -interface IrProperty : IrDeclarationWithVisibility { +interface IrProperty : IrDeclarationWithName, IrDeclarationWithVisibility { override val descriptor: PropertyDescriptor - val name: Name val modality: Modality val isVar: Boolean val isConst: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrTypeParameter.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrTypeParameter.kt index d0e9ce3323b..f13063b5d82 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrTypeParameter.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrTypeParameter.kt @@ -20,13 +20,11 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.visitors.IrElementTransformer -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance -interface IrTypeParameter : IrSymbolDeclaration { +interface IrTypeParameter : IrSymbolDeclaration, IrDeclarationWithName { override val descriptor: TypeParameterDescriptor - val name: Name val variance: Variance val index: Int val isReified: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrValueDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrValueDeclaration.kt index 8eea46c008f..362434e3b4b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrValueDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrValueDeclaration.kt @@ -8,13 +8,10 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.descriptors.ValueDescriptor import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.types.KotlinType -interface IrValueDeclaration : IrDeclaration, IrSymbolOwner { +interface IrValueDeclaration : IrDeclarationWithName, IrSymbolOwner { override val descriptor: ValueDescriptor override val symbol: IrValueSymbol - val name: Name val type: IrType } \ No newline at end of file diff --git a/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt b/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt new file mode 100644 index 00000000000..b58ffae7cc2 --- /dev/null +++ b/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt @@ -0,0 +1,22 @@ +// IGNORE_BACKEND: JVM_IR +// IGNORE_BACKEND: JS_IR +// WITH_RUNTIME + +interface Wrapper { fun runBlock() } + +inline fun crossInlineBuildWrapper(crossinline block: () -> Unit) = object : Wrapper { + override fun runBlock() { + block() + } +} + +class Container { + val wrapper = crossInlineBuildWrapper { + object { } + } +} + +fun box(): String { + Container().wrapper.runBlock() + return "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt b/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt index 96459e600c5..11336deb527 100644 --- a/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt +++ b/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt @@ -1,4 +1,5 @@ // IGNORE_BACKEND: JVM_IR +// IGNORE_BACKEND: JS_IR // WITH_RUNTIME // COMMON_COROUTINES_TEST // WITH_COROUTINES diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6c681793048..5031eb8d2fd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -3686,6 +3686,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/closures/closureWithParameterAndBoxing.kt"); } + @TestMetadata("crossinlineLocalDeclaration.kt") + public void testCrossinlineLocalDeclaration() throws Exception { + runTest("compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt"); + } + @TestMetadata("doubleEnclosedLocalVariable.kt") public void testDoubleEnclosedLocalVariable() throws Exception { runTest("compiler/testData/codegen/box/closures/doubleEnclosedLocalVariable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a13694535fc..6d42d8dc846 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -3686,6 +3686,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/closures/closureWithParameterAndBoxing.kt"); } + @TestMetadata("crossinlineLocalDeclaration.kt") + public void testCrossinlineLocalDeclaration() throws Exception { + runTest("compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt"); + } + @TestMetadata("doubleEnclosedLocalVariable.kt") public void testDoubleEnclosedLocalVariable() throws Exception { runTest("compiler/testData/codegen/box/closures/doubleEnclosedLocalVariable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 0bfb452e9d4..2e4a3fcc4ea 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -3686,6 +3686,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/closures/closureWithParameterAndBoxing.kt"); } + @TestMetadata("crossinlineLocalDeclaration.kt") + public void testCrossinlineLocalDeclaration() throws Exception { + runTest("compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt"); + } + @TestMetadata("doubleEnclosedLocalVariable.kt") public void testDoubleEnclosedLocalVariable() throws Exception { runTest("compiler/testData/codegen/box/closures/doubleEnclosedLocalVariable.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index e5350b0141f..0504e95cc66 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -3086,6 +3086,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/closures/closureWithParameterAndBoxing.kt"); } + @TestMetadata("crossinlineLocalDeclaration.kt") + public void testCrossinlineLocalDeclaration() throws Exception { + runTest("compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt"); + } + @TestMetadata("doubleEnclosedLocalVariable.kt") public void testDoubleEnclosedLocalVariable() throws Exception { runTest("compiler/testData/codegen/box/closures/doubleEnclosedLocalVariable.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index ea96098d9b3..ec98f0a906d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -3086,6 +3086,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/closures/closureWithParameterAndBoxing.kt"); } + @TestMetadata("crossinlineLocalDeclaration.kt") + public void testCrossinlineLocalDeclaration() throws Exception { + runTest("compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt"); + } + @TestMetadata("doubleEnclosedLocalVariable.kt") public void testDoubleEnclosedLocalVariable() throws Exception { runTest("compiler/testData/codegen/box/closures/doubleEnclosedLocalVariable.kt"); From 67ab8624c3131d8636da316492716eea0f33586e Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Tue, 20 Nov 2018 17:35:56 +0300 Subject: [PATCH 28/33] Add DeepCopyIrTreeWithDescriptors --- .../common/DeepCopyWithWrappedDescriptors.kt | 105 ++++++++++++++++++ .../common/lower/InitializersLowering.kt | 18 +-- 2 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyWithWrappedDescriptors.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyWithWrappedDescriptors.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyWithWrappedDescriptors.kt new file mode 100644 index 00000000000..722de16e486 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyWithWrappedDescriptors.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.backend.common + +import org.jetbrains.kotlin.backend.common.descriptors.* +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.util.DescriptorsRemapper +import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid + +/* + TODO: Does not preserve getter/setter descriptors as implementations of PropertyAccessorDescriptor. + This causes problems for KotlinTypeMapper.mapFunctionName (maybe other places as well) + */ + +inline fun T.deepCopyWithWrappedDescriptors(initialParent: IrDeclarationParent? = null): T = + deepCopyWithSymbols(initialParent, DescriptorsToIrRemapper).also { + it.acceptVoid(WrappedDescriptorPatcher) + } + +object DescriptorsToIrRemapper : DescriptorsRemapper { + override fun remapDeclaredClass(descriptor: ClassDescriptor) = + WrappedClassDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredConstructor(descriptor: ClassConstructorDescriptor) = + WrappedClassConstructorDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredEnumEntry(descriptor: ClassDescriptor) = + WrappedClassDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredField(descriptor: PropertyDescriptor) = + WrappedFieldDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) = + WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredTypeParameter(descriptor: TypeParameterDescriptor) = + WrappedTypeParameterDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredVariable(descriptor: VariableDescriptor) = + WrappedVariableDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredValueParameter(descriptor: ParameterDescriptor): ParameterDescriptor = + if (descriptor is ReceiverParameterDescriptor) + WrappedReceiverParameterDescriptor(descriptor.annotations, descriptor.source) + else + WrappedValueParameterDescriptor(descriptor.annotations, descriptor.source) +} + +object WrappedDescriptorPatcher : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitClass(declaration: IrClass) { + (declaration.descriptor as WrappedClassDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitConstructor(declaration: IrConstructor) { + (declaration.descriptor as WrappedClassConstructorDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitEnumEntry(declaration: IrEnumEntry) { + (declaration.descriptor as WrappedClassDescriptor).bind( + declaration.correspondingClass ?: declaration.parentAsClass + ) + declaration.acceptChildrenVoid(this) + } + + override fun visitField(declaration: IrField) { + (declaration.descriptor as WrappedFieldDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + (declaration.descriptor as WrappedSimpleFunctionDescriptor).bind(declaration as IrSimpleFunction) + declaration.acceptChildrenVoid(this) + } + + override fun visitValueParameter(declaration: IrValueParameter) { + (declaration.descriptor as? WrappedValueParameterDescriptor)?.bind(declaration) + (declaration.descriptor as? WrappedReceiverParameterDescriptor)?.bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitTypeParameter(declaration: IrTypeParameter) { + (declaration.descriptor as WrappedTypeParameterDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitVariable(declaration: IrVariable) { + (declaration.descriptor as WrappedVariableDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt index 23386fb9755..bf151552c13 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt @@ -7,14 +7,13 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext -import org.jetbrains.kotlin.backend.common.CompilerPhase +import org.jetbrains.kotlin.backend.common.deepCopyWithWrappedDescriptors +import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.SourceElement -import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* @@ -27,6 +26,9 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.util.DescriptorsRemapper +import org.jetbrains.kotlin.ir.util.SymbolRenamer import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -143,7 +145,7 @@ class InitializersLowering( companion object { val clinitName = Name.special("") - fun IrStatement.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithSymbols(containingDeclaration) - fun IrExpression.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithSymbols(containingDeclaration) + fun IrStatement.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithWrappedDescriptors(containingDeclaration) + fun IrExpression.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithWrappedDescriptors(containingDeclaration) } -} \ No newline at end of file +} From ec0842c0f427e44e30be0f6ef383f9e7c1e1c4fa Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Thu, 15 Nov 2018 00:20:47 +0300 Subject: [PATCH 29/33] Remove descriptors from CallableReferenceLowering --- .../kotlin/backend/common/ir/IrUtils.kt | 30 +- .../common/lower/LocalDeclarationsLowering.kt | 11 +- .../jetbrains/kotlin/ir/util/IrTypeUtils.kt | 2 +- .../kotlin/backend/jvm/JvmBackendContext.kt | 6 + .../kotlin/backend/jvm/JvmLoweringPhases.kt | 6 +- .../jvm/lower/CallableReferenceLowering.kt | 1041 +++++++---------- .../backend/jvm/lower/FileClassLowering.kt | 3 +- .../ir/declarations/IrDeclarationOrigin.kt | 3 +- .../kotlin/ir/declarations/IrField.kt | 3 +- .../ir/util/DeepCopyIrTreeWithSymbols.kt | 7 +- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 3 + 11 files changed, 494 insertions(+), 621 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index edc5bcdf428..a94408f4a58 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -16,9 +16,11 @@ package org.jetbrains.kotlin.backend.common.ir +import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedReceiverParameterDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor @@ -41,10 +43,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.IrTypeProjection -import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor @@ -354,7 +353,7 @@ fun Scope.createTemporaryVariableWithWrappedDescriptor( nameHint: String? = null, isMutable: Boolean = false, origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE): IrVariable { - + val descriptor = WrappedVariableDescriptor() return createTemporaryVariableWithGivenDescriptor( irExpression, nameHint, isMutable, origin, descriptor @@ -362,3 +361,24 @@ fun Scope.createTemporaryVariableWithWrappedDescriptor( } val IrFunction.isOverridable: Boolean get() = this is IrSimpleFunction && this.isOverridable + +fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() { + val thisReceiverDescriptor = WrappedReceiverParameterDescriptor() + thisReceiver = IrValueParameterImpl( + startOffset, endOffset, + IrDeclarationOrigin.INSTANCE_RECEIVER, + IrValueParameterSymbolImpl(thisReceiverDescriptor), + Name.identifier(""), + index = -1, + type = this.symbol.typeWith(this.typeParameters.map { it.defaultType }), + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).also { valueParameter -> + thisReceiverDescriptor.bind(valueParameter) + valueParameter.parent = this + } + + assert(typeParameters.isEmpty()) + assert(descriptor.declaredTypeParameters.isEmpty()) +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 804d5e158ca..06c7c80eed1 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -31,12 +31,8 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.NameUtils import java.util.* interface LocalNameProvider { @@ -769,6 +765,11 @@ class LocalDeclarationsLowering( val localClassContext = LocalClassContext(declaration) localClasses[declaration] = localClassContext } + + override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) { + // Getter and setter of local delegated properties are special generated functions and don't have closure. + declaration.delegate.initializer?.acceptVoid(this) + } }) } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt index 8634f8fe976..1f43f76c472 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.DFS val kotlinPackageFqn = FqName.fromSegments(listOf("kotlin")) -val kotlinReflectionPackageFqn = kotlinPackageFqn.child(Name.identifier("reflection")) +val kotlinReflectionPackageFqn = kotlinPackageFqn.child(Name.identifier("reflect")) val kotlinCoroutinesPackageFqn = kotlinPackageFqn.child(Name.identifier("coroutines")) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index fc41fd280c9..cada69f681a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -76,6 +76,10 @@ class JvmBackendContext( return find(state.module.getPackage(fqName.parent()).memberScope, fqName.shortName()) } + fun getIrClass(fqName: FqName): IrClassSymbol { + return ir.symbols.externalSymbolTable.referenceClass(getClass(fqName)) + } + override fun getInternalFunctions(name: String): List { return when (name) { "ThrowUninitializedPropertyAccessException" -> @@ -151,6 +155,8 @@ class JvmBackendContext( ) val lambdaClass = calc { symbolTable.referenceClass(context.getInternalClass("Lambda")) } + + fun getKFunction(parameterCount: Int) = symbolTable.referenceClass(reflectionTypes.getKFunction(parameterCount)) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt index 49e18ca5629..6b082563d48 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt @@ -11,8 +11,8 @@ import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.makePhase import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.jvm.lower.* -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.name.NameUtils @@ -108,8 +108,8 @@ private val SharedVariablesPhase = makeJvmPhase( private val LocalDeclarationsPhase = makeJvmPhase( { context, data -> LocalDeclarationsLowering(context, object : LocalNameProvider { - override fun localName(descriptor: DeclarationDescriptor): String = - NameUtils.sanitizeAsJavaIdentifier(super.localName(descriptor)) + override fun localName(declaration: IrDeclarationWithName): String = + NameUtils.sanitizeAsJavaIdentifier(super.localName(declaration)) }, Visibilities.PUBLIC, true).lower(data) }, name = "JvmLocalDeclarations", diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index 7536e6b56bc..4ccb08351b6 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -19,20 +19,13 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.descriptors.* -import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.* -import org.jetbrains.kotlin.backend.common.makePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.codegen.isInlineCall import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression -import org.jetbrains.kotlin.backend.jvm.descriptors.JvmPropertyDescriptorImpl import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen -import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.* -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -40,9 +33,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection @@ -51,13 +42,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.inline.InlineUtil -import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.Variance -import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type //Hack implementation to support CR java types in lower @@ -78,11 +63,11 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { override fun visitCall(expression: IrCall): IrExpression { - val descriptor = expression.descriptor - if (descriptor.isInlineCall(context.state)) { + val callee = expression.symbol.owner + if (callee.isInlineFunction(context)) { //TODO: more wise filtering - descriptor.valueParameters.forEach { valueParameter -> - if (InlineUtil.isInlineParameter(valueParameter)) { + callee.valueParameters.forEach { valueParameter -> + if (valueParameter.isInlineParameter()) { expression.getValueArgument(valueParameter.index)?.let { if (isInlineIrExpression(it)) { (it as IrBlock).statements.filterIsInstance().forEach { reference -> @@ -97,10 +82,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val argumentsCount = expression.valueArgumentsCount // Change calls to FunctionN with large N to varargs calls. val newCall = if (argumentsCount > MAX_ARGCOUNT_WITHOUT_VARARG && - descriptor.containingDeclaration in listOf( - context.builtIns.getFunction(argumentsCount), - context.reflectionTypes.getKFunction(argumentsCount) - ) + callee.parentAsClass.defaultType.isFunctionOrKFunction() ) { val vararg = IrVarargImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, @@ -108,14 +90,14 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa context.ir.symbols.any.typeWith(), (0 until argumentsCount).map { i -> expression.getValueArgument(i)!! } ) - val invokeFunDescriptor = context.getClass(FqName("kotlin.jvm.functions.FunctionN")) - .getFunction("invoke", listOf(expression.type.toKotlinType())) - val invokeFunSymbol = context.ir.symbols.externalSymbolTable.referenceSimpleFunction(invokeFunDescriptor.original) + val invokeFun = context.getIrClass(FqName("kotlin.jvm.functions.FunctionN")).owner.declarations.single { + it is IrSimpleFunction && it.name.asString() == "invoke" + } as IrSimpleFunction IrCallImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, expression.type, - invokeFunSymbol, invokeFunDescriptor, + invokeFun.symbol, invokeFun.descriptor, 1, expression.origin, expression.superQualifier?.let { context.ir.symbols.externalSymbolTable.referenceClass(it) } @@ -139,7 +121,8 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa return expression } - val loweredFunctionReference = FunctionReferenceBuilder(currentScope!!.scope.scopeOwner, expression).build() + val currentDeclarationParent = allScopes.map { it.irElement }.last { it is IrDeclarationParent } as IrDeclarationParent + val loweredFunctionReference = FunctionReferenceBuilder(currentDeclarationParent, expression).build() val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) return irBuilder.irBlock(expression) { +loweredFunctionReference.functionReferenceClass @@ -158,26 +141,28 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val functionReferenceConstructor: IrConstructor ) - private val kotlinPackageScope = context.builtIns.builtInsPackageScope - - private val continuationClassDescriptor = context.getClass(FqName("kotlin.coroutines.experimental.Continuation")) + private val continuationClass = context.getIrClass(FqName("kotlin.coroutines.experimental.Continuation")).owner //private val getContinuationSymbol = context.ir.symbols.getContinuation private inner class FunctionReferenceBuilder( - val containingDeclaration: DeclarationDescriptor, + val referenceParent: IrDeclarationParent, val irFunctionReference: IrFunctionReference ) { - private val functionDescriptor = irFunctionReference.descriptor - private val functionParameters = functionDescriptor.explicitParameters - private val boundFunctionParameters = irFunctionReference.getArguments().map { it.first } - private val unboundFunctionParameters = functionParameters - boundFunctionParameters + private val callee = irFunctionReference.symbol.owner + private val calleeParameters = callee.explicitParameters + private val boundCalleeParameters = irFunctionReference.getArgumentsWithIr().map { it.first } + private val unboundCalleeParameters = calleeParameters - boundCalleeParameters - private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl - private lateinit var functionReferenceClass: IrClassImpl + private val typeArgumentsMap = callee.typeParameters.associate { typeParam -> + typeParam to irFunctionReference.getTypeArgument(typeParam.index)!! + } + + + private lateinit var functionReferenceClass: IrClass private lateinit var functionReferenceThis: IrValueParameterSymbol - private lateinit var argumentToPropertiesMap: Map + private lateinit var argumentToFieldMap: Map private val isLambda = irFunctionReference.origin == IrStatementOrigin.LAMBDA @@ -189,600 +174,449 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val startOffset = irFunctionReference.startOffset val endOffset = irFunctionReference.endOffset - val returnType = functionDescriptor.returnType!! - val superTypes: MutableList = mutableListOf( - functionReferenceOrLambda.descriptor.defaultType + val returnType = irFunctionReference.symbol.owner.returnType + val functionReferenceClassSuperTypes: MutableList = mutableListOf( + functionReferenceOrLambda.owner.defaultType // type arguments? ) - val numberOfParameters = unboundFunctionParameters.size + val numberOfParameters = unboundCalleeParameters.size useVararg = (numberOfParameters > MAX_ARGCOUNT_WITHOUT_VARARG) - val functionClassDescriptor = if (useVararg) - context.getClass(FqName("kotlin.jvm.functions.FunctionN")) + val functionClassSymbol = if (useVararg) + context.getIrClass(FqName("kotlin.jvm.functions.FunctionN")) else - context.getClass(FqName("kotlin.jvm.functions.Function$numberOfParameters")) - val functionParameterTypes = unboundFunctionParameters.map { it.type } + context.getIrClass(FqName("kotlin.jvm.functions.Function$numberOfParameters")) + val functionClass = functionClassSymbol.owner + val functionParameterTypes = unboundCalleeParameters.map { it.type } val functionClassTypeParameters = if (useVararg) listOf(returnType) else functionParameterTypes + returnType - superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters) + functionReferenceClassSuperTypes += IrSimpleTypeImpl( + functionClassSymbol, + hasQuestionMark = false, + arguments = functionClassTypeParameters.map { makeTypeProjection(it, Variance.INVARIANT) }, + annotations = emptyList() + ) - var suspendFunctionClassDescriptor: ClassDescriptor? = null - var suspendFunctionClassTypeParameters: List? = null - val lastParameterType = unboundFunctionParameters.lastOrNull()?.type - if (lastParameterType != null && TypeUtils.getClassDescriptor(lastParameterType) == continuationClassDescriptor) { + var suspendFunctionClass: IrClass? = null + var suspendFunctionClassTypeParameters: List? = null + val lastParameterType = unboundCalleeParameters.lastOrNull()?.type + if ((lastParameterType as? IrSimpleType)?.classifier == continuationClass) { // If the last parameter is Continuation<> inherit from SuspendFunction. - suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier( - Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND - ) as ClassDescriptor - suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type - superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters) + suspendFunctionClass = context.getIrClass(FqName("kotlin.Suspendfunction${numberOfParameters - 1}")).owner + suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + + (lastParameterType.arguments.single() as IrTypeProjection).type + functionReferenceClassSuperTypes += IrSimpleTypeImpl( + suspendFunctionClass.symbol, + hasQuestionMark = false, + arguments = suspendFunctionClassTypeParameters.map { makeTypeProjection(it, Variance.INVARIANT) }, + annotations = emptyList() + ) } - functionReferenceClassDescriptor = ClassDescriptorImpl( - /* containingDeclaration = */ containingDeclaration, - /* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName, - /* modality = */ Modality.FINAL, - /* kind = */ ClassKind.CLASS, - /* superTypes = */ superTypes, - /* source = */ /*TODO*/ (containingDeclaration as? DeclarationDescriptorWithSource)?.source ?: NO_SOURCE, - /* isExternal = */ false, - LockBasedStorageManager.NO_LOCKS - ) + val functionReferenceClassDescriptor = WrappedClassDescriptor() functionReferenceClass = IrClassImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - descriptor = functionReferenceClassDescriptor + startOffset, endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrClassSymbolImpl(functionReferenceClassDescriptor), + name = "${callee.name}\$${functionReferenceCount++}".synthesizedName, + kind = ClassKind.CLASS, + visibility = Visibilities.PUBLIC, + modality = Modality.FINAL, + isCompanion = false, + isInner = false, + isData = false, + isExternal = false, + isInline = false ).apply { - createParameterDeclarations() - val typeTranslator = TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings, - enterTableScope=true) - val constantValueGenerator = ConstantValueGenerator(context.state.module, context.ir.symbols.externalSymbolTable) - typeTranslator.constantValueGenerator = constantValueGenerator - constantValueGenerator.typeTranslator = typeTranslator - functionReferenceClassDescriptor.typeConstructor.supertypes.mapTo(this.superTypes) { - typeTranslator.translateType(it) - } + functionReferenceClassDescriptor.bind(this) + parent = referenceParent + superTypes.addAll(functionReferenceClassSuperTypes) + createImplicitParameterDeclarationWithWrappedDescriptor() } - val contributedDescriptors = mutableListOf() - val constructorBuilder = createConstructorBuilder() - functionReferenceClassDescriptor.initialize( - SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null - ) - functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol - val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters) + argumentToFieldMap = boundCalleeParameters.associate { + it to buildField(it.name.safeName(), it.type) + } - val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionDescriptor) + val constructor = createConstructor() + functionReferenceClass.declarations.add(constructor) - constructorBuilder.initialize() - functionReferenceClass.declarations.add(constructorBuilder.ir) - - invokeMethodBuilder.initialize() - functionReferenceClass.declarations.add(invokeMethodBuilder.ir) + val superInvokeFunction = functionClass.functions.find { it.name.asString() == "invoke" }!! + val invokeMethod = createInvokeMethod(superInvokeFunction) + functionReferenceClass.declarations.add(invokeMethod) if (!isLambda) { - val getSignatureBuilder = - createGetSignatureMethodBuilder(functionReferenceOrLambda.owner.descriptor.getFunction("getSignature", emptyList())) - val getNameBuilder = createGetNameMethodBuilder(functionReferenceOrLambda.owner.descriptor.getProperty("name", emptyList())) - val getOwnerBuilder = - createGetOwnerMethodBuilder(functionReferenceOrLambda.owner.descriptor.getFunction("getOwner", emptyList())) + val getSignatureMethod = createGetSignatureMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getSignature"}!!) + val getNameMethod = createGetNameMethod(functionReferenceOrLambda.owner.properties.find { it.name.asString() == "name" }!!) + val getOwnerMethod = createGetOwnerMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getOwner" }!!) - val suspendInvokeMethodBuilder = - if (suspendFunctionClassDescriptor != null) { - val suspendInvokeFunctionDescriptor = - suspendFunctionClassDescriptor.getFunction("invoke", suspendFunctionClassTypeParameters!!) - createInvokeMethodBuilder(suspendInvokeFunctionDescriptor) + val suspendInvokeMethod = + if (suspendFunctionClass != null) { + val suspendInvokeFunction = + suspendFunctionClass.functions.find { it.name.asString() == "invoke" }!! + createInvokeMethod(suspendInvokeFunction) } else null - val inheritedScope = functionReferenceOrLambda.descriptor.unsubstitutedMemberScope - .getContributedDescriptors().mapNotNull { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) } - .filterNot { !isLambda && (it.name.asString() == "getSignature" || it.name.asString() == "name" || it.name.asString() == "getOwner") } - - contributedDescriptors.addAll( - ( - inheritedScope + invokeMethodBuilder.symbol.descriptor + - suspendInvokeMethodBuilder?.symbol?.descriptor + getSignatureBuilder.symbol.descriptor - ).filterNotNull() - ) - - getSignatureBuilder.initialize() - functionReferenceClass.declarations.add(getSignatureBuilder.ir) - - getNameBuilder.initialize() - functionReferenceClass.declarations.add(getNameBuilder.ir) - - getOwnerBuilder.initialize() - functionReferenceClass.declarations.add(getOwnerBuilder.ir) - - suspendInvokeMethodBuilder?.let { - it.initialize() - functionReferenceClass.declarations.add(it.ir) - } + functionReferenceClass.declarations.add(getSignatureMethod) + functionReferenceClass.declarations.add(getNameMethod) + functionReferenceClass.declarations.add(getOwnerMethod) + suspendInvokeMethod?.let { functionReferenceClass.declarations.add(it) } } - return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir) + return BuiltFunctionReference(functionReferenceClass, constructor) } - private fun createConstructorBuilder() = object : SymbolWithIrBuilder() { + private fun createConstructor(): IrConstructor { + val descriptor = WrappedClassConstructorDescriptor() + return IrConstructorImpl( + irFunctionReference.startOffset, irFunctionReference.endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrConstructorSymbolImpl(descriptor), + name = Name.special(""), + visibility = Visibilities.PUBLIC, + returnType = functionReferenceClass.defaultType, + isInline = false, + isExternal = false, + isPrimary = true + ).apply { + val constructor = this + descriptor.bind(this) + parent = functionReferenceClass - private val kFunctionRefConstructorSymbol = - functionReferenceOrLambda.constructors.filter { it.descriptor.valueParameters.size == if (isLambda) 1 else 2 }.single() - - override fun buildSymbol() = IrConstructorSymbolImpl( - ClassConstructorDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* isPrimary = */ false, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl - val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter -> - parameter.copyAsValueParameter(descriptor, index, parameter.name) - } - descriptor.initialize(constructorParameters, Visibilities.PUBLIC) - descriptor.returnType = functionReferenceClassDescriptor.defaultType - } - - override fun buildIr(): IrConstructor { - argumentToPropertiesMap = boundFunctionParameters.associate { - it to buildPropertyWithBackingField(it.name.safeName(), it.type) + val boundArgsSet = boundCalleeParameters.toSet() + for (param in callee.explicitParameters) { + if (param in boundArgsSet) { + val newParam = param.copyTo( + constructor, + index = valueParameters.size, + type = param.type.substitute(typeArgumentsMap) + ) + valueParameters.add(newParam) + } } - val startOffset = irFunctionReference.startOffset - val endOffset = irFunctionReference.endOffset - return IrConstructorImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = symbol, - returnType = symbol.descriptor.returnType.toIrType()!! - ).apply { - val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) + val kFunctionRefConstructorSymbol = + functionReferenceOrLambda.constructors.filter { it.owner.valueParameters.size == if (isLambda) 1 else 2 }.single() - createParameterDeclarations() + val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) + body = irBuilder.irBlockBody { + +IrDelegatingConstructorCallImpl( + startOffset, endOffset, context.irBuiltIns.unitType, + kFunctionRefConstructorSymbol, kFunctionRefConstructorSymbol.descriptor + ).apply { + val const = + IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, unboundCalleeParameters.size) + putValueArgument(0, const) - body = irBuilder.irBlockBody { - +IrDelegatingConstructorCallImpl( - startOffset, endOffset, context.irBuiltIns.unitType, - kFunctionRefConstructorSymbol, kFunctionRefConstructorSymbol.descriptor - ).apply { - val const = - IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, unboundFunctionParameters.size) - putValueArgument(0, const) - - if (!isLambda) { - val irReceiver = valueParameters.firstOrNull() - val receiver = boundFunctionParameters.singleOrNull() - //TODO pass proper receiver - val receiverValue = receiver?.let { - irGet(irReceiver!!.symbol.owner) - } ?: irNull() - putValueArgument(1, receiverValue) - } + if (!isLambda) { + val irReceiver = valueParameters.firstOrNull() + val receiver = boundCalleeParameters.singleOrNull() + //TODO pass proper receiver + val receiverValue = receiver?.let { + irGet(irReceiver!!.symbol.owner) + } ?: irNull() + putValueArgument(1, receiverValue) } + } - //TODO don't write receiver again: use it from base class - boundFunctionParameters.forEachIndexed { index, it -> - +irSetField( - irGet(functionReferenceThis.owner), - argumentToPropertiesMap[it]!!.owner, - irGet(valueParameters[index]) + // Save all arguments to fields. + //TODO don't write receiver again: use it from base class + boundCalleeParameters.forEachIndexed { index, it -> + +irSetField( + irGet(functionReferenceThis.owner), + argumentToFieldMap[it]!!, + irGet(valueParameters[index]) + ) + } + +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType) + } + } + } + + private fun createInvokeMethod(superFunction: IrSimpleFunction) : IrSimpleFunction { + val descriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + irFunctionReference.startOffset, irFunctionReference.endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrSimpleFunctionSymbolImpl(descriptor), + Name.identifier("invoke"), + Visibilities.PUBLIC, + Modality.FINAL, + returnType = callee.returnType, + isInline = false, // not sure + isExternal = false, + isTailrec = false, + isSuspend = superFunction.isSuspend + ).apply { + val function = this + descriptor.bind(this) + parent = functionReferenceClass + overriddenSymbols.add(superFunction.symbol) + dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function) + + val unboundArgsSet = unboundCalleeParameters.toSet() + if (useVararg) { + valueParameters.add(superFunction.valueParameters[0].copyTo(function)) + } else { + for (param in callee.explicitParameters) { + if (param in unboundArgsSet) { + val newParam = param.copyTo( + function, + index = valueParameters.size, + type = param.type.substitute(typeArgumentsMap) ) + valueParameters.add(newParam) } - +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType) - // Save all arguments to fields. - - } - } - } - } - - private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor) = - object : SymbolWithIrBuilder() { - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ Name.identifier("invoke"), - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - val valueParameters = superFunctionDescriptor.valueParameters - .map { it.copyAsValueParameter(descriptor, it.index) } - - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ valueParameters, - /* unsubstitutedReturnType = */ superFunctionDescriptor.returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PUBLIC - ).apply { - overriddenDescriptors += superFunctionDescriptor - isSuspend = superFunctionDescriptor.isSuspend } } - override fun buildIr(): IrSimpleFunction { - val startOffset = irFunctionReference.startOffset - val endOffset = irFunctionReference.endOffset - val ourSymbol = symbol - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = ourSymbol, - returnType = ourSymbol.descriptor.returnType!!.toIrType()!! - ).apply { - - val function = this - val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) - createParameterDeclarations() - - body = irBuilder.irBlockBody(startOffset, endOffset) { - val arrayGetFun = context.irBuiltIns.arrayClass.owner - .declarations.find { - (it as? IrSimpleFunction)?.name?.toString() == "get" - }!! as IrSimpleFunction - - if (useVararg) { - val varargParam = valueParameters.single() - val arraySizeProperty = context.irBuiltIns.arrayClass.owner.declarations.find { - (it as? IrProperty)?.name?.toString() == "size" - } as IrProperty - +irIfThen( - irNotEquals( - irCall(arraySizeProperty.getter!!).apply { - dispatchReceiver = irGet(varargParam) - }, - irInt(unboundFunctionParameters.size) - ), - irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply { - putValueArgument(0, irString("Expected ${unboundFunctionParameters.size} arguments")) - } - ) + val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) + body = irBuilder.irBlockBody(startOffset, endOffset) { + val arrayGetFun = context.irBuiltIns.arrayClass.owner.functions.find { it.name.asString() == "get" }!! + if (useVararg) { + val varargParam = valueParameters.single() + val arraySizeProperty = context.irBuiltIns.arrayClass.owner.properties.find { it.name.toString() == "size" }!! + +irIfThen( + irNotEquals( + irCall(arraySizeProperty.getter!!).apply { + dispatchReceiver = irGet(varargParam) + }, + irInt(unboundCalleeParameters.size) + ), + irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply { + putValueArgument(0, irString("Expected ${unboundCalleeParameters.size} arguments")) } - +irReturn( - irCall(irFunctionReference.symbol).apply { - var unboundIndex = 0 - val unboundArgsSet = unboundFunctionParameters.toSet() + ) + } + +irReturn( + irCall(irFunctionReference.symbol).apply { + var unboundIndex = 0 - functionParameters.forEach { parameter -> - val argument = when { - !unboundArgsSet.contains(parameter) -> - // Bound parameter - read from field. - irGetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter]!!.owner) - ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size -> - // For suspend functions the last argument is continuation and it is implicit. - TODO() + calleeParameters.forEach { parameter -> + val argument = when { + !unboundArgsSet.contains(parameter) -> + // Bound parameter - read from field. + irGetField(irGet(functionReferenceThis.owner), argumentToFieldMap[parameter]!!) + function.isSuspend && unboundIndex == valueParameters.size -> + // For suspend functions the last argument is continuation and it is implicit. + TODO() // irCall(getContinuationSymbol, // listOf(ourSymbol.descriptor.returnType!!)) - useVararg -> { - val type = parameter.type.toIrType()!! - val varargParam = valueParameters.single() - irBlock(resultType = type) { - val argValue = irTemporary( - irCall(arrayGetFun).apply { - dispatchReceiver = irGet(varargParam) - putValueArgument(0, irInt(unboundIndex++)) - } - ) - +irIfThen( - irNotIs(irGet(argValue), type), - irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply { - putValueArgument(0, irString("Wrong type, expected $type")) - } - ) - +irGet(argValue) + useVararg -> { + val type = parameter.type + val varargParam = valueParameters.single() + irBlock(resultType = type) { + val argValue = irTemporary( + irCall(arrayGetFun).apply { + dispatchReceiver = irGet(varargParam) + putValueArgument(0, irInt(unboundIndex++)) } - } - else -> { - irGet(valueParameters[unboundIndex++]) - } - } - when (parameter) { - functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument - functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument - else -> putValueArgument((parameter as ValueParameterDescriptor).index, argument) + ) + +irIfThen( + irNotIs(irGet(argValue), type), + irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply { + putValueArgument(0, irString("Wrong type, expected $type")) + } + ) + +irGet(argValue) } } - - if (!useVararg) assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } + else -> { + irGet(valueParameters[unboundIndex++]) + } } - ) - } - } - } - } + when (parameter) { + callee.dispatchReceiverParameter -> dispatchReceiver = argument + callee.extensionReceiverParameter -> extensionReceiver = argument + else -> putValueArgument(parameter.index, argument) + } + } - private fun buildPropertyWithBackingField(name: Name, type: KotlinType): IrFieldSymbol { - val fieldSymbol = IrFieldSymbolImpl( - JvmPropertyDescriptorImpl.createFinalField( - name, type, functionReferenceClassDescriptor, - Annotations.EMPTY, JavaVisibilities.PACKAGE_VISIBILITY, Opcodes.ACC_SYNTHETIC, SourceElement.NO_SOURCE - ) - ) + if (!useVararg) assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } + } + ) + } + + } + } + + private fun buildField(name: Name, type: IrType): IrField { + val descriptor = WrappedFieldDescriptor() + // TODO: make it synthetic val field = IrFieldImpl( irFunctionReference.startOffset, irFunctionReference.endOffset, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - fieldSymbol, - type.toIrType()!! - ) + IrFieldSymbolImpl(descriptor), + name, + type, + JavaVisibilities.PACKAGE_VISIBILITY, + isFinal = true, + isExternal = false, + isStatic = false + ).apply { + descriptor.bind(this) + } functionReferenceClass.declarations.add(field) - return fieldSymbol + return field } - private fun createGetNameMethodBuilder(superNameProperty: PropertyDescriptor) = - object : SymbolWithIrBuilder() { + private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction { + val descriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + irFunctionReference.startOffset, irFunctionReference.endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrSimpleFunctionSymbolImpl(descriptor), + Name.identifier("getSignature"), + superFunction.visibility, + superFunction.modality, + returnType = superFunction.returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + val function = this + descriptor.bind(this) + parent = functionReferenceClass + overriddenSymbols.add(superFunction.symbol) + dispatchReceiverParameter = functionReferenceClass.thisReceiver!!.copyTo(function) - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - PropertyDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - superNameProperty.modality, - superNameProperty.visibility, - false, - /* name = */ superNameProperty.name, - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE, - false, false, false, false, false, false - ).let { property -> - - property.overriddenDescriptors += superNameProperty - PropertyGetterDescriptorImpl( - property, - Annotations.EMPTY, - Modality.OPEN, - Visibilities.PUBLIC, - false, false, false, - CallableMemberDescriptor.Kind.DECLARATION, - null, - SourceElement.NO_SOURCE - ).also { - property.initialize(it, null) - property.setType( - /* outType = */ superNameProperty.type, - /* typeParameters = */ superNameProperty.typeParameters, - /* dispatchReceiverParameter = */ superNameProperty.dispatchReceiverParameter, - /* extensionReceiverParameter= */ superNameProperty.extensionReceiverParameter + val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) + body = irBuilder.irBlockBody(startOffset, endOffset) { + +irReturn( + IrConstImpl.string( + -1, -1, context.irBuiltIns.stringType, + PropertyReferenceCodegen.getSignatureString( + irFunctionReference.symbol.descriptor, this@CallableReferenceLowering.context.state ) - //overriddenDescriptors += superNameProperty.getter - } - } - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as PropertyGetterDescriptorImpl - descriptor.initialize(superNameProperty.type) - } - - override fun buildIr(): IrSimpleFunction { - val startOffset = irFunctionReference.startOffset - val endOffset = irFunctionReference.endOffset - val ourSymbol = symbol - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = ourSymbol, - returnType = ourSymbol.descriptor.returnType!!.toIrType()!! - ).apply { - - val function = this - val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) - - createParameterDeclarations() - - body = irBuilder.irBlockBody(startOffset, endOffset) { - +irReturn( - IrConstImpl.string(-1, -1, context.irBuiltIns.stringType, functionDescriptor.name.asString()) - ) - } - } - } - } - - - private fun createGetSignatureMethodBuilder(superFunctionDescriptor: FunctionDescriptor) = - object : SymbolWithIrBuilder() { - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ Name.identifier("getSignature"), - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - val valueParameters = superFunctionDescriptor.valueParameters - .map { it.copyAsValueParameter(descriptor, it.index) } - - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ valueParameters, - /* unsubstitutedReturnType = */ superFunctionDescriptor.returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PUBLIC - ).apply { - overriddenDescriptors += superFunctionDescriptor - isSuspend = superFunctionDescriptor.isSuspend - } - } - - override fun buildIr(): IrSimpleFunction { - val startOffset = irFunctionReference.startOffset - val endOffset = irFunctionReference.endOffset - val ourSymbol = symbol - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = ourSymbol, - returnType = ourSymbol.descriptor.returnType!!.toIrType()!! - ).apply { - - val function = this - val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) - - createParameterDeclarations() - - body = irBuilder.irBlockBody(startOffset, endOffset) { - +irReturn( - IrConstImpl.string( - -1, -1, context.irBuiltIns.stringType, - PropertyReferenceCodegen.getSignatureString( - irFunctionReference.symbol.descriptor, this@CallableReferenceLowering.context.state - ) - ) - ) - } - } - } - } - - private fun createGetOwnerMethodBuilder(superFunctionDescriptor: FunctionDescriptor) = - object : SymbolWithIrBuilder() { - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ Name.identifier("getOwner"), - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - val valueParameters = superFunctionDescriptor.valueParameters - .map { it.copyAsValueParameter(descriptor, it.index) } - - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ valueParameters, - /* unsubstitutedReturnType = */ superFunctionDescriptor.returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PUBLIC - ).apply { - overriddenDescriptors += superFunctionDescriptor - isSuspend = superFunctionDescriptor.isSuspend - } - } - - override fun buildIr(): IrSimpleFunction { - val startOffset = irFunctionReference.startOffset - val endOffset = irFunctionReference.endOffset - val ourSymbol = symbol - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = ourSymbol, - returnType = symbol.descriptor.returnType!!.toIrType()!! - ).apply { - val function = this - val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) - - createParameterDeclarations() - - body = irBuilder.irBlockBody(startOffset, endOffset) { - +irReturn( - generateCallableReferenceDeclarationContainer(irFunctionReference) - ) - } - } - } - - fun IrBuilderWithScope.generateCallableReferenceDeclarationContainer( - irFunctionReference: IrFunctionReference - ): IrExpression { - val descriptor = irFunctionReference.symbol.descriptor - val globalContext = this@CallableReferenceLowering.context - val state = globalContext.state - val container = descriptor.containingDeclaration - - val type = - when { - container is ClassDescriptor -> - // TODO: getDefaultType() here is wrong and won't work for arrays - state.typeMapper.mapType(container.defaultType) - container is PackageFragmentDescriptor -> - state.typeMapper.mapOwner(descriptor) - descriptor is VariableDescriptorWithAccessors -> - globalContext.state.bindingContext.get( - CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, descriptor - )!! - else -> state.typeMapper.mapOwner(descriptor) - } - - val clazzDescriptor = globalContext.getClass(FqName("java.lang.Class")) - val clazzSymbol = globalContext.ir.symbols.externalSymbolTable.referenceClass(clazzDescriptor) - val clazzRef = IrClassReferenceImpl( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - clazzDescriptor.toIrType(), - clazzSymbol, - CrIrType(type) - ) - - val isContainerPackage = if (descriptor is LocalVariableDescriptor) - DescriptorUtils.getParentOfType(descriptor, ClassDescriptor::class.java) == null - else - container is PackageFragmentDescriptor - - val reflectionClass = globalContext.getClass(FqName("kotlin.jvm.internal.Reflection")) - return if (isContainerPackage) { - // Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead, - // but there's no nice API to obtain that name here yet - // TODO: write the referenced declaration's module name and use it in reflection - val module = IrConstImpl.string( - -1, -1, globalContext.irBuiltIns.stringType, - state.moduleName ) - val functionDescriptor = reflectionClass.getStaticFunction("getOrCreateKotlinPackage", emptyList()) - val functionSymbol = globalContext.ir.symbols.externalSymbolTable.referenceSimpleFunction(functionDescriptor) - irCall(functionSymbol, functionSymbol.owner.returnType).apply { - putValueArgument(0, clazzRef) - putValueArgument(1, module) - } - } else { - val functionDescriptor = reflectionClass.staticScope - .getContributedFunctions(Name.identifier("getOrCreateKotlinClass"), NoLookupLocation.FROM_BACKEND) - .single { it.valueParameters.size == 1 } - val functionSymbol = globalContext.ir.symbols.externalSymbolTable.referenceSimpleFunction(functionDescriptor) - irCall(functionSymbol, functionSymbol.owner.returnType).apply { - putValueArgument(0, clazzRef) - } - } + ) } } + } + private fun createGetNameMethod(superNameProperty: IrProperty): IrSimpleFunction { + val superGetter = superNameProperty.getter!! + val descriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + irFunctionReference.startOffset, irFunctionReference.endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrSimpleFunctionSymbolImpl(descriptor), + Name.identifier("getName"), + superGetter.visibility, + superGetter.modality, + returnType = superGetter.returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + val function = this + descriptor.bind(this) + parent = functionReferenceClass + overriddenSymbols.add(superGetter.symbol) + dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function) + val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) + body = irBuilder.irBlockBody(startOffset, endOffset) { + +irReturn( + IrConstImpl.string(-1, -1, context.irBuiltIns.stringType, callee.name.asString()) + ) + } + } + } + + private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction { + val descriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + functionReferenceClass.startOffset, functionReferenceClass.endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrSimpleFunctionSymbolImpl(descriptor), + Name.identifier("getOwner"), + superFunction.visibility, + superFunction.modality, + returnType = superFunction.returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + val function = this + descriptor.bind(this) + parent = functionReferenceClass + overriddenSymbols.add(superFunction.symbol) + dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function) + + val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) + body = irBuilder.irBlockBody(startOffset, endOffset) { + +irReturn( + generateCallableReferenceDeclarationContainer() + ) + } + } + } + + fun IrBuilderWithScope.generateCallableReferenceDeclarationContainer(): IrExpression { + val globalContext = this@CallableReferenceLowering.context + val state = globalContext.state + val irContainer = callee.parent + + val isContainerPackage = + ((irContainer as? IrClass)?.origin == IrDeclarationOrigin.FILE_CLASS) || irContainer is IrPackageFragment + + val type = when { + irContainer is IrClass -> + // TODO: getDefaultType() here is wrong and won't work for arrays + state.typeMapper.mapType(irContainer.defaultType.toKotlinType()) + +// // TODO: this code is only needed for property references, which are not yet supported. +// descriptor is VariableDescriptorWithAccessors -> { +// assert(false) { "VariableDescriptorWithAccessors" } +// globalContext.state.bindingContext.get( +// CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, descriptor +// )!! +// } + + else -> state.typeMapper.mapOwner(callee.descriptor) + } + + val clazz = globalContext.getIrClass(FqName("java.lang.Class")).owner + val clazzRef = IrClassReferenceImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + clazz.defaultType, + clazz.symbol, + CrIrType(type) + ) + + val reflectionClass = globalContext.getIrClass(FqName("kotlin.jvm.internal.Reflection")) + return if (isContainerPackage) { + // Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead, + // but there's no nice API to obtain that name here yet + // TODO: write the referenced declaration's module name and use it in reflection + val module = IrConstImpl.string( + -1, -1, globalContext.irBuiltIns.stringType, + state.moduleName + ) + val functionSymbol = reflectionClass.functions.find { it.owner.name.asString() == "getOrCreateKotlinPackage" }!! + irCall(functionSymbol, functionSymbol.owner.returnType).apply { + putValueArgument(0, clazzRef) + putValueArgument(1, module) + } + } else { + val functionSymbol = reflectionClass.functions.filter { it.owner.name.asString() == "getOrCreateKotlinClass" } + .single { it.owner.valueParameters.size == 1 } + irCall(functionSymbol, functionSymbol.owner.returnType).apply { + putValueArgument(0, clazzRef) + } + } + } } //TODO rewrite @@ -798,38 +632,41 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa } } -// Copied from K/Native IrUtils2.kt -// TODO move IrUtils2.kt to common -private fun IrClass.createParameterDeclarations() { - thisReceiver = IrValueParameterImpl( - startOffset, endOffset, - IrDeclarationOrigin.INSTANCE_RECEIVER, - descriptor.thisAsReceiverParameter, - this.symbol.typeWith(this.typeParameters.map { it.defaultType }), - null - ).also { valueParameter -> - valueParameter.parent = this +// TODO: Move to IrUtils + +private fun IrFunction.isInlineFunction(context: JvmBackendContext) = + (!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && + (isInline || isArrayConstructorWithLambda()) + +private fun IrFunction.isArrayConstructorWithLambda() = + valueParameters.size == 2 && + this is IrConstructor && + parentAsClass.let { + it.getPackageFragment()?.fqName?.asString() == "kotlin" && + it.name.asString().endsWith("Array") + } + +private fun IrValueParameter.isInlineParameter() = + !isNoinline && !type.isNullable() && type.isFunctionOrKFunction() + +private fun IrType.substitute(substitutionMap: Map): IrType { + if (this !is IrSimpleType) return this + + substitutionMap[classifier]?.let { return it } + + val newArguments = arguments.map { + if (it is IrTypeProjection) { + makeTypeProjection(it.type.substitute(substitutionMap), it.variance) + } else { + it + } } - assert(typeParameters.isEmpty()) - assert(descriptor.declaredTypeParameters.isEmpty()) + val newAnnotations = annotations.map { it.deepCopyWithSymbols() } + return IrSimpleTypeImpl( + classifier, + hasQuestionMark, + newArguments, + newAnnotations + ) } - -private val IrTypeParameter.defaultType: IrType get() = this.symbol.defaultType - -private val IrTypeParameterSymbol.defaultType: IrType - get() = IrSimpleTypeImpl( - this, - false, - emptyList(), - emptyList() - ) - - -private fun IrClassifierSymbol.typeWith(arguments: List): IrSimpleType = - IrSimpleTypeImpl( - this, - false, - arguments.map { makeTypeProjection(it, Variance.INVARIANT) }, - emptyList() - ) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt index 4148967835d..3edd776c043 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt @@ -18,7 +18,7 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor -import org.jetbrains.kotlin.backend.common.makePhase +import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality @@ -79,6 +79,7 @@ class FileClassLowering(val context: JvmBackendContext) : FileLoweringPass { superTypes.add(context.irBuiltIns.anyType) parent = irFile declarations.addAll(fileClassMembers) + createImplicitParameterDeclarationWithWrappedDescriptor() // TODO: figure out why reparenting leads to failing tests. // fileClassMembers.forEach { it.parent = this } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index bbf0c369005..a56bbb57bbf 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -29,6 +29,7 @@ interface IrDeclarationOrigin { object DELEGATED_MEMBER : IrDeclarationOriginImpl("DELEGATED_MEMBER") object ENUM_CLASS_SPECIAL_MEMBER : IrDeclarationOriginImpl("ENUM_CLASS_SPECIAL_MEMBER") object FUNCTION_FOR_DEFAULT_PARAMETER : IrDeclarationOriginImpl("FUNCTION_FOR_DEFAULT_PARAMETER") + object FILE_CLASS : IrDeclarationOriginImpl("FILE_CLASS") object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER") object GENERATED_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_INLINE_CLASS_MEMBER") object LOCAL_FUNCTION_FOR_LAMBDA : IrDeclarationOriginImpl("LOCAL_FUNCTION_FOR_LAMBDA") @@ -48,4 +49,4 @@ interface IrDeclarationOrigin { abstract class IrDeclarationOriginImpl(val name: String) : IrDeclarationOrigin { override fun toString(): String = name -} \ No newline at end of file +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt index 8b55518304e..0fdfe1efc6d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrField.kt @@ -10,7 +10,8 @@ import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.types.IrType -interface IrField : IrSymbolDeclaration, IrOverridableDeclaration, IrDeclarationWithVisibility, IrDeclarationParent { +interface IrField : IrSymbolDeclaration, IrOverridableDeclaration, + IrDeclarationWithName, IrDeclarationWithVisibility, IrDeclarationParent { override val descriptor: PropertyDescriptor val type: IrType diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index 7c92b710080..54b4fa15ca1 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -33,8 +33,11 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import java.util.* -inline fun T.deepCopyWithSymbols(initialParent: IrDeclarationParent? = null): T { - val symbolRemapper = DeepCopySymbolRemapper() +inline fun T.deepCopyWithSymbols( + initialParent: IrDeclarationParent? = null, + descriptorRemapper: DescriptorsRemapper = DescriptorsRemapper.DEFAULT +): T { + val symbolRemapper = DeepCopySymbolRemapper(descriptorRemapper) acceptVoid(symbolRemapper) val typeRemapper = DeepCopyTypeRemapper(symbolRemapper) return transform(DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper), null).patchDeclarationParents(initialParent) as T diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index de8e1a2302b..34f86f11232 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -259,6 +259,9 @@ val IrClassSymbol.constructors: Sequence val IrClass.constructors: Sequence get() = this.declarations.asSequence().filterIsInstance() +val IrDeclarationContainer.properties: Sequence + get() = declarations.asSequence().filterIsInstance() + val IrFunction.explicitParameters: List get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters) From bccb451afd3190eaaf5c8f450807a6ed49e261c7 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Tue, 18 Dec 2018 13:15:15 +0300 Subject: [PATCH 30/33] Add isSyntheic flag to IrDeclarationOrigin --- .../org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt | 2 +- .../kotlin/backend/jvm/codegen/FunctionCodegen.kt | 4 ++-- .../kotlin/ir/declarations/IrDeclarationOrigin.kt | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index 01e16efcd73..6ed8280b0fb 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -25,7 +25,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER") object DEFAULT_IMPLS : IrDeclarationOriginImpl("DEFAULT_IMPL") object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") - object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR") + object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR", isSynthetic = true) object TO_ARRAY : IrDeclarationOriginImpl("TO_ARRAY") object JVM_STATIC_WRAPPER : IrDeclarationOriginImpl("JVM_STATIC_WRAPPER") object JVM_OVERLOADS_WRAPPER : IrDeclarationOriginImpl("JVM_OVERLOADS_WRAPPER") diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index 8c243f4e976..21f2b8b17f7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -78,7 +78,7 @@ open class FunctionCodegen(private val irFunction: IrFunction, private val class else -> if (classCodegen.irClass.isJvmInterface && irFunction.body == null) Opcodes.ACC_ABSTRACT else 0 //TODO transform interface modality on lowering to DefaultImpls } val nativeFlag = if (irFunction.isExternal) Opcodes.ACC_NATIVE else 0 - val syntheticFlag = if (irFunction.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR) Opcodes.ACC_SYNTHETIC else 0 + val syntheticFlag = if (irFunction.origin.isSynthetic) Opcodes.ACC_SYNTHETIC else 0 return visibility or modalityFlag or staticFlag or @@ -148,4 +148,4 @@ private fun createFrameMapWithReceivers( } return frameMap -} \ No newline at end of file +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index a56bbb57bbf..cbae7730ec9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -45,8 +45,13 @@ interface IrDeclarationOrigin { object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY") object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES") object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE") + + val isSynthetic: Boolean get() = false } -abstract class IrDeclarationOriginImpl(val name: String) : IrDeclarationOrigin { +abstract class IrDeclarationOriginImpl( + val name: String, + override val isSynthetic: Boolean = false +) : IrDeclarationOrigin { override fun toString(): String = name } From 7df0cffac9578115fccfee3c0149ee83b0426460 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Tue, 18 Dec 2018 14:35:13 +0300 Subject: [PATCH 31/33] Move declaration origins to IrDeclarationOrigin.kt --- .../kotlin/backend/jvm/DeclarationOrigins.kt | 1 + .../backend/jvm/codegen/FunctionCodegen.kt | 1 - .../jvm/lower/CallableReferenceLowering.kt | 17 ++++++++--------- .../jvm/lower/FunctionNVarargInvokeLowering.kt | 6 +++--- .../ir/declarations/IrDeclarationOrigin.kt | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index 6ed8280b0fb..440757354ba 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -25,6 +25,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER") object DEFAULT_IMPLS : IrDeclarationOriginImpl("DEFAULT_IMPL") object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") + object FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL") object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR", isSynthetic = true) object TO_ARRAY : IrDeclarationOriginImpl("TO_ARRAY") object JVM_STATIC_WRAPPER : IrDeclarationOriginImpl("JVM_STATIC_WRAPPER") diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index 21f2b8b17f7..6a9370f1b4e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.backend.jvm.codegen -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDescriptorWithExtraFlags import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES import org.jetbrains.kotlin.codegen.* diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index 4ccb08351b6..c4556077bc0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen import org.jetbrains.kotlin.descriptors.* @@ -53,8 +54,6 @@ class CrIrType(val type: Type) : IrType { //Originally was copied from K/Native class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPass { - object DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL") - private var functionReferenceCount = 0 private val inlineLambdaReferences = mutableSetOf() @@ -218,7 +217,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val functionReferenceClassDescriptor = WrappedClassDescriptor() functionReferenceClass = IrClassImpl( startOffset, endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrClassSymbolImpl(functionReferenceClassDescriptor), name = "${callee.name}\$${functionReferenceCount++}".synthesizedName, kind = ClassKind.CLASS, @@ -274,7 +273,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val descriptor = WrappedClassConstructorDescriptor() return IrConstructorImpl( irFunctionReference.startOffset, irFunctionReference.endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrConstructorSymbolImpl(descriptor), name = Name.special(""), visibility = Visibilities.PUBLIC, @@ -341,7 +340,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val descriptor = WrappedSimpleFunctionDescriptor() return IrFunctionImpl( irFunctionReference.startOffset, irFunctionReference.endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrSimpleFunctionSymbolImpl(descriptor), Name.identifier("invoke"), Visibilities.PUBLIC, @@ -450,7 +449,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val field = IrFieldImpl( irFunctionReference.startOffset, irFunctionReference.endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrFieldSymbolImpl(descriptor), name, type, @@ -470,7 +469,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val descriptor = WrappedSimpleFunctionDescriptor() return IrFunctionImpl( irFunctionReference.startOffset, irFunctionReference.endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrSimpleFunctionSymbolImpl(descriptor), Name.identifier("getSignature"), superFunction.visibility, @@ -506,7 +505,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val descriptor = WrappedSimpleFunctionDescriptor() return IrFunctionImpl( irFunctionReference.startOffset, irFunctionReference.endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrSimpleFunctionSymbolImpl(descriptor), Name.identifier("getName"), superGetter.visibility, @@ -536,7 +535,7 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa val descriptor = WrappedSimpleFunctionDescriptor() return IrFunctionImpl( functionReferenceClass.startOffset, functionReferenceClass.endOffset, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, IrSimpleFunctionSymbolImpl(descriptor), Name.identifier("getOwner"), superFunction.visibility, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt index 32080b5e992..21bf21b4384 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt @@ -10,8 +10,8 @@ import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDesc import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irIfThen -import org.jetbrains.kotlin.backend.common.makePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -52,7 +52,7 @@ class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : ClassLower val descriptor = WrappedSimpleFunctionDescriptor() return IrFunctionImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - origin = CallableReferenceLowering.DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, symbol = IrSimpleFunctionSymbolImpl(descriptor), name = Name.identifier("invoke"), visibility = Visibilities.PUBLIC, @@ -68,7 +68,7 @@ class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : ClassLower val varargParameterDescriptor = WrappedValueParameterDescriptor() val varargParam = IrValueParameterImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - origin = CallableReferenceLowering.DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, symbol = IrValueParameterSymbolImpl(varargParameterDescriptor), name = Name.identifier("args"), index = 0, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index cbae7730ec9..fbf81f1224f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -28,7 +28,7 @@ interface IrDeclarationOrigin { object DELEGATED_PROPERTY_ACCESSOR : IrDeclarationOriginImpl("DELEGATED_PROPERTY_ACCESSOR") object DELEGATED_MEMBER : IrDeclarationOriginImpl("DELEGATED_MEMBER") object ENUM_CLASS_SPECIAL_MEMBER : IrDeclarationOriginImpl("ENUM_CLASS_SPECIAL_MEMBER") - object FUNCTION_FOR_DEFAULT_PARAMETER : IrDeclarationOriginImpl("FUNCTION_FOR_DEFAULT_PARAMETER") + object FUNCTION_FOR_DEFAULT_PARAMETER : IrDeclarationOriginImpl("FUNCTION_FOR_DEFAULT_PARAMETER", isSynthetic = true) object FILE_CLASS : IrDeclarationOriginImpl("FILE_CLASS") object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER") object GENERATED_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_INLINE_CLASS_MEMBER") From c3352d5fdb86b6101a729ba11ecd756b96b5c8e0 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Fri, 23 Nov 2018 14:02:54 +0300 Subject: [PATCH 32/33] Unmute several tests, mute one --- .../codegen/box/closures/crossinlineLocalDeclaration.kt | 1 - .../box/collectionLiterals/collectionLiteralsWithConstants.kt | 1 - .../box/coroutines/createCoroutinesOnManualInstances_1_2.kt | 1 - .../box/coroutines/crossInlineWithCapturedOuterReceiver.kt | 1 - compiler/testData/codegen/box/enum/kt20651b.kt | 2 ++ compiler/testData/codegen/box/jvmName/annotationProperties.kt | 1 - .../testData/codegen/box/reflection/annotations/retentions.kt | 1 - .../codegen/box/reflection/annotations/simpleFunAnnotation.kt | 1 - .../codegen/box/reflection/annotations/simpleParamAnnotation.kt | 1 - .../codegen/box/reflection/call/bound/extensionFunction.kt | 1 - .../codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt | 1 - .../box/reflection/mapping/types/genericArrayElementType.kt | 1 - .../box/reflection/mapping/types/innerGenericTypeArgument.kt | 1 - .../box/reflection/mapping/types/parameterizedTypeArgument.kt | 1 - .../codegen/box/reflection/mapping/types/withNullability.kt | 1 - .../codegen/box/reflection/typeParameters/upperBounds.kt | 1 - .../testData/codegen/box/reflection/types/classifierIsClass.kt | 1 - .../codegen/box/reflection/types/classifiersOfBuiltInTypes.kt | 1 - .../testData/codegen/box/reflection/types/jvmErasureOfClass.kt | 1 - .../codegen/box/reflection/types/subtyping/platformType.kt | 1 - .../box/reflection/types/subtyping/simpleGenericTypes.kt | 1 - .../codegen/box/reflection/types/subtyping/typeProjection.kt | 1 - .../testData/codegen/box/reflection/types/useSiteVariance.kt | 1 - .../codegen/box/vararg/assigningArrayToVarargInAnnotation.kt | 1 - .../multiplatform/annotationsViaActualTypeAliasFromBinary.kt | 1 - 25 files changed, 2 insertions(+), 24 deletions(-) diff --git a/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt b/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt index b58ffae7cc2..200c3863356 100644 --- a/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt +++ b/compiler/testData/codegen/box/closures/crossinlineLocalDeclaration.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME interface Wrapper { fun runBlock() } diff --git a/compiler/testData/codegen/box/collectionLiterals/collectionLiteralsWithConstants.kt b/compiler/testData/codegen/box/collectionLiterals/collectionLiteralsWithConstants.kt index 32c8fe4d778..c565aab7244 100644 --- a/compiler/testData/codegen/box/collectionLiterals/collectionLiteralsWithConstants.kt +++ b/compiler/testData/codegen/box/collectionLiterals/collectionLiteralsWithConstants.kt @@ -1,6 +1,5 @@ // WITH_REFLECT -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM import java.util.Arrays diff --git a/compiler/testData/codegen/box/coroutines/createCoroutinesOnManualInstances_1_2.kt b/compiler/testData/codegen/box/coroutines/createCoroutinesOnManualInstances_1_2.kt index a2f540ba537..7334f3dd334 100644 --- a/compiler/testData/codegen/box/coroutines/createCoroutinesOnManualInstances_1_2.kt +++ b/compiler/testData/codegen/box/coroutines/createCoroutinesOnManualInstances_1_2.kt @@ -1,6 +1,5 @@ // !LANGUAGE: -ReleaseCoroutines // IGNORE_BACKEND: JS_IR -// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME // WITH_COROUTINES // IGNORE_BACKEND: JS diff --git a/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt b/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt index 11336deb527..96459e600c5 100644 --- a/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt +++ b/compiler/testData/codegen/box/coroutines/crossInlineWithCapturedOuterReceiver.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME // COMMON_COROUTINES_TEST // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/enum/kt20651b.kt b/compiler/testData/codegen/box/enum/kt20651b.kt index 477e3036569..348857ff448 100644 --- a/compiler/testData/codegen/box/enum/kt20651b.kt +++ b/compiler/testData/codegen/box/enum/kt20651b.kt @@ -1,3 +1,5 @@ +// IGNORE_BACKEND: JVM_IR + interface Callback { fun invoke(): String } diff --git a/compiler/testData/codegen/box/jvmName/annotationProperties.kt b/compiler/testData/codegen/box/jvmName/annotationProperties.kt index 836c81eb8f7..b3c951f952f 100644 --- a/compiler/testData/codegen/box/jvmName/annotationProperties.kt +++ b/compiler/testData/codegen/box/jvmName/annotationProperties.kt @@ -1,5 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // WITH_REFLECT import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reflection/annotations/retentions.kt b/compiler/testData/codegen/box/reflection/annotations/retentions.kt index b3c2f35445c..3d9597bd113 100644 --- a/compiler/testData/codegen/box/reflection/annotations/retentions.kt +++ b/compiler/testData/codegen/box/reflection/annotations/retentions.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/annotations/simpleFunAnnotation.kt b/compiler/testData/codegen/box/reflection/annotations/simpleFunAnnotation.kt index 7d9e0893927..9bf7297f9b3 100644 --- a/compiler/testData/codegen/box/reflection/annotations/simpleFunAnnotation.kt +++ b/compiler/testData/codegen/box/reflection/annotations/simpleFunAnnotation.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/annotations/simpleParamAnnotation.kt b/compiler/testData/codegen/box/reflection/annotations/simpleParamAnnotation.kt index 49af2f9360e..6e642f79c54 100644 --- a/compiler/testData/codegen/box/reflection/annotations/simpleParamAnnotation.kt +++ b/compiler/testData/codegen/box/reflection/annotations/simpleParamAnnotation.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt b/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt index b18ee72af00..993e4820d8d 100644 --- a/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt +++ b/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt b/compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt index 9f036301883..51a03692991 100644 --- a/compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt +++ b/compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt b/compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt index dc5789e8dbb..d8c06d8cfcd 100644 --- a/compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt +++ b/compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt b/compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt index 455461c89dd..6277c1abcfe 100644 --- a/compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt +++ b/compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/mapping/types/parameterizedTypeArgument.kt b/compiler/testData/codegen/box/reflection/mapping/types/parameterizedTypeArgument.kt index d086bef8284..e4d47a93bbf 100644 --- a/compiler/testData/codegen/box/reflection/mapping/types/parameterizedTypeArgument.kt +++ b/compiler/testData/codegen/box/reflection/mapping/types/parameterizedTypeArgument.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt b/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt index 034dca0e73b..f55c3bf041b 100644 --- a/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt +++ b/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/typeParameters/upperBounds.kt b/compiler/testData/codegen/box/reflection/typeParameters/upperBounds.kt index 68413d3a6b2..2fdc4cea305 100644 --- a/compiler/testData/codegen/box/reflection/typeParameters/upperBounds.kt +++ b/compiler/testData/codegen/box/reflection/typeParameters/upperBounds.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/types/classifierIsClass.kt b/compiler/testData/codegen/box/reflection/types/classifierIsClass.kt index 1d0b234c434..d7e5396cbd9 100644 --- a/compiler/testData/codegen/box/reflection/types/classifierIsClass.kt +++ b/compiler/testData/codegen/box/reflection/types/classifierIsClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/types/classifiersOfBuiltInTypes.kt b/compiler/testData/codegen/box/reflection/types/classifiersOfBuiltInTypes.kt index e899f3526ce..cb7a4b70b99 100644 --- a/compiler/testData/codegen/box/reflection/types/classifiersOfBuiltInTypes.kt +++ b/compiler/testData/codegen/box/reflection/types/classifiersOfBuiltInTypes.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/types/jvmErasureOfClass.kt b/compiler/testData/codegen/box/reflection/types/jvmErasureOfClass.kt index 01c927eabbc..bea77ac9c0f 100644 --- a/compiler/testData/codegen/box/reflection/types/jvmErasureOfClass.kt +++ b/compiler/testData/codegen/box/reflection/types/jvmErasureOfClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/types/subtyping/platformType.kt b/compiler/testData/codegen/box/reflection/types/subtyping/platformType.kt index e14f13a955e..f9932a50a7d 100644 --- a/compiler/testData/codegen/box/reflection/types/subtyping/platformType.kt +++ b/compiler/testData/codegen/box/reflection/types/subtyping/platformType.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/types/subtyping/simpleGenericTypes.kt b/compiler/testData/codegen/box/reflection/types/subtyping/simpleGenericTypes.kt index 019e398f7b7..56898204b25 100644 --- a/compiler/testData/codegen/box/reflection/types/subtyping/simpleGenericTypes.kt +++ b/compiler/testData/codegen/box/reflection/types/subtyping/simpleGenericTypes.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/types/subtyping/typeProjection.kt b/compiler/testData/codegen/box/reflection/types/subtyping/typeProjection.kt index f31f9bd4cdf..29863590942 100644 --- a/compiler/testData/codegen/box/reflection/types/subtyping/typeProjection.kt +++ b/compiler/testData/codegen/box/reflection/types/subtyping/typeProjection.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/types/useSiteVariance.kt b/compiler/testData/codegen/box/reflection/types/useSiteVariance.kt index b4364479cd7..d6b0fc3fc1f 100644 --- a/compiler/testData/codegen/box/reflection/types/useSiteVariance.kt +++ b/compiler/testData/codegen/box/reflection/types/useSiteVariance.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/vararg/assigningArrayToVarargInAnnotation.kt b/compiler/testData/codegen/box/vararg/assigningArrayToVarargInAnnotation.kt index 88de13999e7..d8519bbb06a 100644 --- a/compiler/testData/codegen/box/vararg/assigningArrayToVarargInAnnotation.kt +++ b/compiler/testData/codegen/box/vararg/assigningArrayToVarargInAnnotation.kt @@ -1,6 +1,5 @@ // WITH_REFLECT -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // FILE: JavaAnn.java diff --git a/compiler/testData/codegen/boxAgainstJava/multiplatform/annotationsViaActualTypeAliasFromBinary.kt b/compiler/testData/codegen/boxAgainstJava/multiplatform/annotationsViaActualTypeAliasFromBinary.kt index ff743067d66..635fb7d069a 100644 --- a/compiler/testData/codegen/boxAgainstJava/multiplatform/annotationsViaActualTypeAliasFromBinary.kt +++ b/compiler/testData/codegen/boxAgainstJava/multiplatform/annotationsViaActualTypeAliasFromBinary.kt @@ -1,6 +1,5 @@ // !LANGUAGE: +MultiPlatformProjects // WITH_REFLECT -// IGNORE_BACKEND: JVM_IR // FILE: main.kt // See compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt From 265901144039370273900ef815b41b7e2c7052f8 Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Fri, 18 Jan 2019 00:45:20 +0300 Subject: [PATCH 33/33] Fix compilation of GradleImportingTestCase in bunches --- .../gradle/GradleImportingTestCase.kt.182 | 294 ++++++++++++++++++ .../gradle/ImportingTestWatcher.kt.182 | 22 ++ 2 files changed, 316 insertions(+) create mode 100644 idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt.182 create mode 100644 idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt.182 diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt.182 b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt.182 new file mode 100644 index 00000000000..37122ddd696 --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleImportingTestCase.kt.182 @@ -0,0 +1,294 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.kotlin.idea.codeInsight.gradle + +import com.intellij.compiler.server.BuildManager +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.Result +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.externalSystem.model.ProjectSystemId +import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings +import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.impl.LoadTextUtil +import com.intellij.openapi.fileTypes.FileTypeManager +import com.intellij.openapi.projectRoots.JavaSdk +import com.intellij.openapi.projectRoots.ProjectJdkTable +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.ui.TestDialog +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.testFramework.IdeaTestUtil +import com.intellij.testFramework.TestLoggerFactory +import com.intellij.util.PathUtil +import com.intellij.util.containers.ContainerUtil +import junit.framework.TestCase +import org.gradle.util.GradleVersion +import org.gradle.wrapper.GradleWrapperMain +import org.intellij.lang.annotations.Language +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.gradle.KotlinSdkCreationChecker +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.plugins.gradle.settings.DistributionType +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings +import org.jetbrains.plugins.gradle.settings.GradleSettings +import org.jetbrains.plugins.gradle.util.GradleConstants +import org.jetbrains.plugins.groovy.GroovyFileType +import org.junit.Assume.assumeThat +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.rules.TestName +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import java.io.File +import java.io.IOException +import java.io.StringWriter +import java.net.URISyntaxException +import java.util.* +import com.intellij.openapi.diagnostic.Logger +import org.junit.AfterClass + +// part of org.jetbrains.plugins.gradle.importing.GradleImportingTestCase +@RunWith(value = Parameterized::class) +abstract class GradleImportingTestCase : ExternalSystemImportingTestCase() { + + protected var sdkCreationChecker : KotlinSdkCreationChecker? = null + + @JvmField + @Rule + var name = TestName() + + @JvmField + @Rule + var testWatcher = ImportingTestWatcher() + + @JvmField + @Rule + var versionMatcherRule = VersionMatcherRule() + + @JvmField + @Parameterized.Parameter + var gradleVersion: String = "" + + private lateinit var myProjectSettings: GradleProjectSettings + private lateinit var myJdkHome: String + + override fun setUp() { + myJdkHome = IdeaTestUtil.requireRealJdkHome() + super.setUp() + assumeThat(gradleVersion, versionMatcherRule.matcher) + runWrite { + ProjectJdkTable.getInstance().findJdk(GRADLE_JDK_NAME)?.let { + ProjectJdkTable.getInstance().removeJdk(it) + } + val jdkHomeDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(myJdkHome))!! + val jdk = SdkConfigurationUtil.setupSdk(arrayOfNulls(0), jdkHomeDir, JavaSdk.getInstance(), true, null, GRADLE_JDK_NAME) + TestCase.assertNotNull("Cannot create JDK for $myJdkHome", jdk) + ProjectJdkTable.getInstance().addJdk(jdk!!) + FileTypeManager.getInstance().associateExtension(GroovyFileType.GROOVY_FILE_TYPE, "gradle") + + } + myProjectSettings = GradleProjectSettings().apply { + this.isUseQualifiedModuleNames = false + } + GradleSettings.getInstance(myProject).gradleVmOptions = "-Xmx128m -XX:MaxPermSize=64m" + System.setProperty(ExternalSystemExecutionSettings.REMOTE_PROCESS_IDLE_TTL_IN_MS_KEY, GRADLE_DAEMON_TTL_MS.toString()) + configureWrapper() + sdkCreationChecker = KotlinSdkCreationChecker() + } + + override fun tearDown() { + try { + runWrite { + val old = ProjectJdkTable.getInstance().findJdk(GRADLE_JDK_NAME) + if (old != null) { + SdkConfigurationUtil.removeSdk(old) + } + } + + Messages.setTestDialog(TestDialog.DEFAULT) + FileUtil.delete(BuildManager.getInstance().buildSystemDirectory.toFile()) + sdkCreationChecker?.removeNewKotlinSdk() + } finally { + super.tearDown() + } + } + + override fun collectAllowedRoots(roots: MutableList) { + roots.add(myJdkHome) + roots.addAll(ExternalSystemTestCase.collectRootsInside(myJdkHome)) + roots.add(PathManager.getConfigPath()) + } + + override fun getName(): String { + return if (name.methodName == null) super.getName() else FileUtil.sanitizeFileName(name.methodName) + } + + override fun getTestsTempDir(): String = "gradleImportTests" + + override fun getExternalSystemConfigFileName(): String = "build.gradle" + + protected fun importProjectUsingSingeModulePerGradleProject() { + myProjectSettings.isResolveModulePerSourceSet = false + importProject() + } + + override fun importProject() { + ExternalSystemApiUtil.subscribe( + myProject, + GradleConstants.SYSTEM_ID, + object : ExternalSystemSettingsListenerAdapter() { + override fun onProjectsLinked(settings: Collection) { + val item = ContainerUtil.getFirstItem(settings) + if (item is GradleProjectSettings) { + item.gradleJvm = GRADLE_JDK_NAME + } + } + }) + super.importProject() + } + + override fun importProject(@NonNls @Language("Groovy") config: String) { + super.importProject( + """ + allprojects { + repositories { + maven { + url 'http://maven.labs.intellij.net/repo1' + } + } + } + + $config + """.trimIndent() + ) + } + + override fun getCurrentExternalProjectSettings(): GradleProjectSettings = myProjectSettings + + override fun getExternalSystemId(): ProjectSystemId = GradleConstants.SYSTEM_ID + + @Throws(IOException::class, URISyntaxException::class) + private fun configureWrapper() { + val distributionUri = AbstractModelBuilderTest.DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion)) + + myProjectSettings.distributionType = DistributionType.DEFAULT_WRAPPED + val wrapperJarFrom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(wrapperJar())!! + + val wrapperJarFromTo = createProjectSubFile("gradle/wrapper/gradle-wrapper.jar") + runWrite { + wrapperJarFromTo.setBinaryContent(wrapperJarFrom.contentsToByteArray()) + } + + val properties = Properties() + properties.setProperty("distributionBase", "GRADLE_USER_HOME") + properties.setProperty("distributionPath", "wrapper/dists") + properties.setProperty("zipStoreBase", "GRADLE_USER_HOME") + properties.setProperty("zipStorePath", "wrapper/dists") + properties.setProperty("distributionUrl", distributionUri.toString()) + + val writer = StringWriter() + properties.store(writer, null) + + createProjectSubFile("gradle/wrapper/gradle-wrapper.properties", writer.toString()) + } + + protected open fun testDataDirName(): String = "" + + protected fun testDataDirectory(): File { + val baseDir = "${PluginTestCaseBase.getTestDataPathBase()}/gradle/${testDataDirName()}/" + return File(baseDir, getTestName(true).substringBefore("_")) + } + + protected fun configureByFiles(): List { + val rootDir = testDataDirectory() + assert(rootDir.exists()) { "Directory ${rootDir.path} doesn't exist" } + + return rootDir.walk().mapNotNull { + when { + it.isDirectory -> null + !it.name.endsWith(SUFFIX) -> { + createProjectSubFile(it.path.substringAfter(rootDir.path + File.separator), it.readText()) + } + else -> null + } + }.toList() + } + + protected fun importProjectFromTestData(): List { + val files = configureByFiles() + importProject() + return files + } + + protected fun checkFiles(files: List) { + FileDocumentManager.getInstance().saveAllDocuments() + + files.filter { + it.name == GradleConstants.DEFAULT_SCRIPT_NAME + || it.name == GradleConstants.KOTLIN_DSL_SCRIPT_NAME + || it.name == GradleConstants.SETTINGS_FILE_NAME + } + .forEach { + if (it.name == GradleConstants.SETTINGS_FILE_NAME && !File(testDataDirectory(), it.name + SUFFIX).exists()) return@forEach + val actualText = LoadTextUtil.loadText(it).toString() + val expectedFileName = if (File(testDataDirectory(), it.name + ".$gradleVersion" + SUFFIX).exists()) { + it.name + ".$gradleVersion" + SUFFIX + } else { + it.name + SUFFIX + } + KotlinTestUtils.assertEqualsToFile(File(testDataDirectory(), expectedFileName), actualText) + } + } + + + private fun runWrite(f: () -> Unit) { + object : WriteAction() { + override fun run(result: Result) { + f() + } + }.execute() + } + + companion object { + const val GRADLE_JDK_NAME = "Gradle JDK" + private const val GRADLE_DAEMON_TTL_MS = 10000 + + @JvmStatic + protected val SUFFIX = ".after" + + @JvmStatic + @Parameterized.Parameters(name = "{index}: with Gradle-{0}") + fun data(): Collection> { + return Arrays.asList(*AbstractModelBuilderTest.SUPPORTED_GRADLE_VERSIONS) + } + + fun wrapperJar(): File { + return File(PathUtil.getJarPathForClass(GradleWrapperMain::class.java)) + } + + @JvmStatic + @BeforeClass + fun setLoggerFactory() { + Logger.setFactory(TestLoggerFactory::class.java) + } + } +} diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt.182 b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt.182 new file mode 100644 index 00000000000..4fa6d45c422 --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/ImportingTestWatcher.kt.182 @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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.idea.codeInsight.gradle + +import com.intellij.testFramework.TestLoggerFactory +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +class ImportingTestWatcher : TestWatcher() { + + override fun succeeded(description: Description) { + TestLoggerFactory.onTestFinished(true) + } + + override fun failed(e: Throwable, description: Description) { + TestLoggerFactory.onTestFinished(false) + } + +} \ No newline at end of file