-
Notifications
You must be signed in to change notification settings - Fork 47
/
KotlinMultiplatformPluginAdapter.kt
80 lines (64 loc) · 3.18 KB
/
KotlinMultiplatformPluginAdapter.kt
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
/*
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.kover.lookup.adapters
import groovy.lang.*
import kotlinx.kover.api.*
import kotlinx.kover.lookup.LookupAdapter
import org.gradle.api.*
import org.gradle.api.file.*
import org.gradle.internal.metaobject.*
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.gradle.kotlin.dsl.*
/**
* Adapter to get sources and outputs of Kotlin Multi-Platform Gradle plugin.
* Required to support kotlin sources for multiplatform projects.
*/
internal class KotlinMultiplatformPluginAdapter : LookupAdapter() {
override fun lookup(project: Project, sourceSetFilters: KoverSourceSetFilter): Dirs {
project.plugins.findPlugin("kotlin-multiplatform") ?: return Dirs()
val extension = try {
project.extensions.findByType<KotlinMultiplatformExtension>() ?: return Dirs()
} catch (e: ClassNotFoundException) {
return findByReflection(project)
} catch (e: NoClassDefFoundError) {
return findByReflection(project)
}
val targets =
extension.targets.filter { it.platformType == KotlinPlatformType.jvm || it.platformType == KotlinPlatformType.androidJvm }
val compilations = targets.flatMap { it.compilations.filter { c -> c.name != "test" } }
val sourceDirs =
compilations.asSequence().flatMap { it.allKotlinSourceSets }.map { it.kotlin }.flatMap { it.srcDirs }
.toList()
val outputDirs =
compilations.asSequence().flatMap { it.output.classesDirs }.toList()
return Dirs(sourceDirs, outputDirs)
}
/*
* If Kotlin Multiplatform plugin if the plugin applied not in the same project where Kover is applied,
* then its classes are in another class loader, and they are not available to kover.
* Therefore, the only way to work with such an object is to use reflection.
*/
@Suppress("UNCHECKED_CAST")
fun findByReflection(project: Project): Dirs {
val extension =
project.extensions.findByName("kotlin-multiplatform")?.let { BeanDynamicObject(it) } ?: return Dirs()
val targets = (extension.getProperty("targets") as NamedDomainObjectCollection<GroovyObject>).filter {
val platformTypeName = (it.getProperty("platformType") as Named).name
platformTypeName == "jvm" || platformTypeName == "androidJvm"
}
val compilations = targets.flatMap {
(it.getProperty("compilations") as NamedDomainObjectCollection<Named>)
.filter { c -> c.name != "test" }
}.map { BeanDynamicObject(it) }
val sourceDirs = compilations.asSequence()
.flatMap { it.getProperty("allKotlinSourceSets") as Collection<*> }
.map { BeanDynamicObject(it).getProperty("kotlin") as SourceDirectorySet }.flatMap { it.srcDirs }
.toList()
val outputDirs =
compilations.asSequence().map { BeanDynamicObject(it.getProperty("output")) }
.flatMap { it.getProperty("classesDirs") as FileCollection }.toList()
return Dirs(sourceDirs, outputDirs)
}
}