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

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

/**
 * Kotlin as a service entry point
 * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode
 * $messageCollector is required by compiler infrastructure and will receive all compiler messages
 * $body is 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();

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

    /**
     * Executes [processor] when analysis is complete.
     * $processor is a function to receive compiler environment, module and context for symbol resolution
     */
    public fun withContext<T>(processor: (JetCoreEnvironment, ModuleDescriptor, BindingContext) -> T): T {
        val environment = JetCoreEnvironment.createForProduction(this, configuration)
        val exhaust = environment.analyze2(messageCollector)
        return processor(environment, exhaust.getModuleDescriptor(), exhaust.getBindingContext())
    }

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

    /**
     * Streams files into [processor] and returns a stream of its results
     * $processor is a function to receive context for symbol resolution and file for processing
     */
    public fun streamFiles<T>(processor: (BindingContext, JetFile) -> T): Stream<T> {
        return withContext { environment, module, context ->
            environment.getSourceFiles().stream().map { file -> processor(context, 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 processFiles<T>(processor: (BindingContext, JetFile) -> T): List<T> {
        return withContext { environment, module, context ->
            environment.getSourceFiles().map { file -> processor(context, file) }
        }
    }

    /**
     * Runs [processor] for each file and collects its results into single list
     * $processor is a function to receive context for symbol resolution, module and file for processing
     */
    public fun processFiles<T>(processor: (BindingContext, ModuleDescriptor, JetFile) -> T): List<T> {
        return withContext { environment, module, context ->
            environment.getSourceFiles().map { file -> processor(context, module, 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: (BindingContext, JetFile) -> List<T>): List<T> {
        return withContext { environment, module, context ->
            environment.getSourceFiles().flatMap { file -> processor(context, 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 paths 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)
    }
}