All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.gradle.plugin.mpp.internal.KotlinCompilationsModuleGroups.kt Maven / Gradle / Ivy

There is a newer version: 2.0.20-RC
Show newest version
/*
 * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.gradle.plugin.mpp.internal

import org.gradle.api.Project
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation

/** This is a disjoint-set union-like approach to having a module name that is equal across associated compilations, as the compiler
 * now requires that to properly compile internal calls to friend classes. Associating a compilation with another one leads to their
 * disjoint sets being united, so their module names become equal, taken from the new leader compilation.
 *
 * TODO: once the compiler is able to correctly generate calls to internals in other modules, remove this logic.
 */
internal class KotlinCompilationsModuleGroups {
    private val moduleLeaderCompilationMap: MutableMap, KotlinCompilation<*>> =
        mutableMapOf()

    fun getModuleLeader(compilation: KotlinCompilation<*>): KotlinCompilation<*> {
        if (compilation !in moduleLeaderCompilationMap) {
            moduleLeaderCompilationMap[compilation] = compilation
        }
        val leader = moduleLeaderCompilationMap.getValue(compilation)
        return when {
            leader == compilation -> leader
            else -> getModuleLeader(leader).also { moduleLeaderCompilationMap[compilation] = it }
        }
    }

    fun unionModules(compilationA: KotlinCompilation<*>, compilationB: KotlinCompilation<*>) {
        val aLeader = getModuleLeader(compilationA)
        val bLeader = getModuleLeader(compilationB)

        if (aLeader == bLeader)
            return

        listOf(aLeader, bLeader).run {
            /** heuristically choose the new leader: choose `main` when possible, don't choose `*test*` when there's an alternative,
             * if that didn't work, choose the first name lexicographically */
            val newLeader = singleOrNull { it.name == KotlinCompilation.MAIN_COMPILATION_NAME }
                ?: singleOrNull { it.name.contains("main", true) }
                ?: singleOrNull { !it.name.contains("test", true) }
                ?: minBy { it.name }!!

            forEach { moduleLeaderCompilationMap[it] = newLeader }
        }
    }

    companion object {
        private const val EXT_NAME = "kotlin.compilations.moduleGroups"

        fun getModuleLeaderCompilation(compilation: KotlinCompilation<*>): KotlinCompilation<*> =
            getInstance(compilation.target.project).getModuleLeader(compilation)

        fun unionModules(compilationA: KotlinCompilation<*>, compilationB: KotlinCompilation<*>) {
            getInstance(compilationA.target.project).unionModules(compilationA, compilationB)
        }

        private fun getInstance(project: Project): KotlinCompilationsModuleGroups {
            val ext = project.extensions.getByType(ExtraPropertiesExtension::class.java)
            if (!ext.has(EXT_NAME)) {
                ext.set(EXT_NAME, KotlinCompilationsModuleGroups())
            }
            @Suppress("UNCHECKED_CAST")
            return ext.get(EXT_NAME) as KotlinCompilationsModuleGroups
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy