summaryrefslogtreecommitdiff
path: root/plugins/kotlin/gradle/gradle-tooling/src/org/jetbrains/kotlin/idea/gradleTooling/MultiplatformModelImportingContext.kt
blob: ca25bdcd8905ee82c441e4a9abf6571c4c3643c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.

package org.jetbrains.kotlin.idea.gradleTooling

import org.gradle.api.Project
import org.jetbrains.kotlin.idea.projectModel.*

internal interface MultiplatformModelImportingContext: KotlinSourceSetContainer {
    val project: Project
    val compilerArgumentsCacheMapper: CompilerArgumentsCacheMapper

    val targets: Collection<KotlinTarget>
    val compilations: Collection<KotlinCompilation>

    /**
     * All source sets in a project, including those that are created but not included into any compilations
     * (so-called "orphan" source sets). Use [isOrphanSourceSet] to get only compiled source sets
     */
    val sourceSets: Collection<KotlinSourceSetImpl> get() = sourceSetsByName.values
    override val sourceSetsByName: Map<String, KotlinSourceSetImpl>

    /**
     * Platforms, which are actually used in this project (i.e. platforms, for which targets has been created)
     */
    val projectPlatforms: Collection<KotlinPlatform>

    fun sourceSetByName(name: String): KotlinSourceSet?
    fun compilationsBySourceSet(sourceSet: KotlinSourceSet): Collection<KotlinCompilation>?

    /**
     * "Orphan" is a source set which is not actually compiled by the compiler, i.e. the one
     * which doesn't belong to any [KotlinCompilation].
     *
     * Orphan source sets might appear if one creates a source-set manually and doesn't link
     * it anywhere (essentially this is a misconfiguration)
     */
    fun isOrphanSourceSet(sourceSet: KotlinSourceSet): Boolean = compilationsBySourceSet(sourceSet) == null

    /**
     * "Declared" source-set is a source-set which is included into compilation directly, rather
     * through closure over dependsOn-relation.
     *
     * See also KDoc for [KotlinCompilation.declaredSourceSets]
     */
    fun isDeclaredSourceSet(sourceSet: KotlinSourceSet): Boolean
}

internal fun MultiplatformModelImportingContext.getProperty(property: GradleImportProperties): Boolean = project.getProperty(property)

internal fun Project.getProperty(property: GradleImportProperties): Boolean {
    val explicitValueIfAny = try {
        (findProperty(property.id) as? String)?.toBoolean()
    } catch (e: Exception) {
        logger.error("Error while trying to read property $property from project $project", e)
        null
    }

    return explicitValueIfAny ?: property.defaultValue
}

internal enum class GradleImportProperties(val id: String, val defaultValue: Boolean) {
    IS_HMPP_ENABLED("kotlin.mpp.enableGranularSourceSetsMetadata", false),
    COERCE_ROOT_SOURCE_SETS_TO_COMMON("kotlin.mpp.coerceRootSourceSetsToCommon", true),
    ENABLE_NATIVE_DEPENDENCY_PROPAGATION("kotlin.native.enableDependencyPropagation", true),
    BUILD_METADATA_DEPENDENCIES("build_metadata_dependencies_for_actualised_source_sets", true),
    IMPORT_ORPHAN_SOURCE_SETS("import_orphan_source_sets", true),
    INCLUDE_ANDROID_DEPENDENCIES("kotlin.include.android.dependencies", false)
    ;
}


internal class MultiplatformModelImportingContextImpl(
    override val project: Project,
    override val compilerArgumentsCacheMapper: CompilerArgumentsCacheMapper
) : MultiplatformModelImportingContext {
    /** see [initializeSourceSets] */
    override lateinit var sourceSetsByName: Map<String, KotlinSourceSetImpl>
        private set

    /** see [initializeCompilations] */
    override lateinit var compilations: Collection<KotlinCompilation>
        private set
    private lateinit var sourceSetToParticipatedCompilations: Map<KotlinSourceSet, Set<KotlinCompilation>>
    private lateinit var allDeclaredSourceSets: Set<KotlinSourceSet>


    /** see [initializeTargets] */
    override lateinit var targets: Collection<KotlinTarget>
        private set

    override lateinit var projectPlatforms: Collection<KotlinPlatform>
        private set

    internal fun initializeSourceSets(sourceSetsByNames: Map<String, KotlinSourceSetImpl>) {
        require(!this::sourceSetsByName.isInitialized) {
            "Attempt to re-initialize source sets for $this. Previous value: ${this.sourceSetsByName}"
        }
        this.sourceSetsByName = sourceSetsByNames
    }

    @OptIn(ExperimentalGradleToolingApi::class)
    internal fun initializeCompilations(compilations: Collection<KotlinCompilation>) {
        require(!this::compilations.isInitialized) { "Attempt to re-initialize compilations for $this. Previous value: ${this.compilations}" }
        this.compilations = compilations

        val sourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>()

        for (target in targets) {
            for (compilation in target.compilations) {
                for (sourceSet in compilation.allSourceSets) {
                    sourceSetToCompilations.getOrPut(sourceSet) { LinkedHashSet() } += compilation
                    resolveAllDependsOnSourceSets(sourceSet).forEach {
                        sourceSetToCompilations.getOrPut(it) { LinkedHashSet() } += compilation
                    }
                }
            }
        }

        this.sourceSetToParticipatedCompilations = sourceSetToCompilations

        this.allDeclaredSourceSets = compilations.flatMapTo(mutableSetOf()) { it.declaredSourceSets }
    }

    internal fun initializeTargets(targets: Collection<KotlinTarget>) {
        require(!this::targets.isInitialized) { "Attempt to re-initialize targets for $this. Previous value: ${this.targets}" }
        this.targets = targets
        this.projectPlatforms = targets.map { it.platform }
    }

    // overload for small optimization
    override fun isOrphanSourceSet(sourceSet: KotlinSourceSet): Boolean = sourceSet !in sourceSetToParticipatedCompilations.keys

    override fun isDeclaredSourceSet(sourceSet: KotlinSourceSet): Boolean = sourceSet in allDeclaredSourceSets

    override fun compilationsBySourceSet(sourceSet: KotlinSourceSet): Collection<KotlinCompilation>? =
        sourceSetToParticipatedCompilations[sourceSet]

    override fun sourceSetByName(name: String): KotlinSourceSet? = sourceSetsByName[name]
}