aboutsummaryrefslogtreecommitdiff
path: root/src/Analysis/AnalysisEnvironment.kt
blob: 1813a4b013a8986e8a9b32436e1eb142c5545f7f (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
package org.jetbrains.dokka

import org.jetbrains.kotlin.cli.common.messages.*
import com.intellij.openapi.*
import org.jetbrains.kotlin.cli.jvm.compiler.*
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.psi.*
import java.io.File
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.cli.common.*
import org.jetbrains.kotlin.cli.jvm.*
import com.intellij.openapi.util.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.resolve.lazy.ResolveSession

/**
 * Kotlin as a service entry point
 *
 * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode
 *
 * $messageCollector: required by compiler infrastructure and will receive all compiler messages
 * $body: optional and can be used to configure environment without creating local variable
 */
public class AnalysisEnvironment(val messageCollector: MessageCollector, body: AnalysisEnvironment.() -> Unit = {}) : Disposable {
    val configuration = CompilerConfiguration();

    init {
        configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
        body()
    }

    /**
     * Executes [processor] when analysis is complete.
     * $processor: function to receive compiler environment, module and context for symbol resolution
     */
    public fun withContext<T>(processor: (JetCoreEnvironment, ResolveSession) -> T): T {
        val environment = JetCoreEnvironment.createForProduction(this, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
        val resolveSession = environment.analyze()
        if (environment.getSourceFiles().isNotEmpty()) {
            resolveSession.forceResolveAll()
        }
        return processor(environment, resolveSession)
    }

    /**
     * Executes [processor] when analysis is complete.
     * $processor: function to receive compiler module and context for symbol resolution
     */
    public fun withContext<T>(processor: (ResolveSession) -> T): T {
        return withContext { environment, session -> processor(session) }
    }

    /**
     * Streams files into [processor] and returns a stream of its results
     * $processor: function to receive context for symbol resolution and file for processing
     */
    public fun streamFiles<T>(processor: (ResolveSession, JetFile) -> T): Stream<T> {
        return withContext { environment, session ->
            environment.getSourceFiles().stream().map { file -> processor(session, file) }
        }
    }

    /**
     * Runs [processor] for each file and collects its results into single list
     * $processor: function to receive context for symbol resolution and file for processing
     */
    public fun processFiles<T>(processor: (ResolveSession, JetFile) -> T): List<T> {
        return withContext { environment, session ->
            environment.getSourceFiles().map { file -> processor(session, file) }
        }
    }

    /**
     * Runs [processor] for each file and collects its results into single list
     * $processor: is a function to receive context for symbol resolution and file for processing
     */
    public fun processFilesFlat<T>(processor: (ResolveSession, JetFile) -> List<T>): List<T> {
        return withContext { environment, session ->
            environment.getSourceFiles().flatMap { file -> processor(session, file) }
        }
    }

    /**
     * Classpath for this environment.
     */
    public val classpath: List<File>
        get() = configuration.get(JVMConfigurationKeys.CLASSPATH_KEY) ?: listOf()

    /**
     * Adds list of paths to classpath.
     * $paths: collection of files to add
     */
    public fun addClasspath(paths: List<File>) {
        configuration.addAll(JVMConfigurationKeys.CLASSPATH_KEY, paths)
    }

    /**
     * Adds path to classpath.
     * $path: path to add
     */
    public fun addClasspath(path: File) {
        configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, path)
    }

    /**
     * List of source roots for this environment.
     */
    public val sources: List<String>
        get() = configuration.get(CommonConfigurationKeys.SOURCE_ROOTS_KEY) ?: listOf()

    /**
     * Adds list of paths to source roots.
     * $list: collection of files to add
     */
    public fun addSources(list: List<String>) {
        configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, list)
    }

    /**
     * Disposes the environment and frees all associated resources.
     */
    public override fun dispose() {
        Disposer.dispose(this)
    }
}