forked from scala/scala
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CompilerBridge.scala
209 lines (180 loc) · 7.07 KB
/
CompilerBridge.scala
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
* Zinc - The incremental compiler for Scala.
* Copyright Scala Center, Lightbend, and Mark Harrah
*
* Scala (https://www.scala-lang.org)
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools
package xsbt
import xsbti.{ AnalysisCallback, Logger, Problem, Reporter, VirtualFile }
import xsbti.compile._
import scala.tools.nsc.Settings
import scala.collection.mutable
import scala.reflect.io.AbstractFile
import scala.tools.nsc.CompilerCommand
import Log.debug
import java.io.File
/**
* This is the entry point for the compiler bridge (implementation of CompilerInterface)
*/
final class CompilerBridge extends xsbti.compile.CompilerInterface2 {
override def run(
sources: Array[VirtualFile],
changes: DependencyChanges,
options: Array[String],
output: Output,
callback: AnalysisCallback,
delegate: Reporter,
progress: CompileProgress,
log: Logger
): Unit = {
val cached = new CachedCompiler0(options, output, new WeakLog(log, delegate))
try {
cached.run(sources.toList, changes, callback, log, delegate, progress)
} finally {
cached.close()
}
}
}
class InterfaceCompileFailed(
val arguments: Array[String],
val problems: Array[Problem],
override val toString: String
) extends xsbti.CompileFailed
class InterfaceCompileCancelled(val arguments: Array[String], override val toString: String)
extends xsbti.CompileCancelled
private final class WeakLog(private[this] var log: Logger, private[this] var delegate: Reporter) {
def apply(message: String): Unit = {
assert(log ne null, "Stale reference to logger")
log.error(Message(message))
}
def logger: Logger = log
def reporter: Reporter = delegate
def clear(): Unit = {
log = null
delegate = null
}
}
private final class CachedCompiler0(
args: Array[String],
output: Output,
initialLog: WeakLog
) extends CachedCompilerCompat
with java.io.Closeable {
/////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// INITIALIZATION CODE ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
val settings = new Settings(s => initialLog(s))
output match {
case multi: MultipleOutput =>
for (out <- multi.getOutputGroups)
settings.outputDirs
.add(
out.getSourceDirectoryAsPath.toAbsolutePath.toString,
out.getOutputDirectoryAsPath.toAbsolutePath.toString
)
case single: SingleOutput =>
val outputFilepath = single.getOutputDirectoryAsPath.toAbsolutePath
settings.outputDirs.setSingleOutput(outputFilepath.toString)
}
val command = new CompilerCommand(args.toList, settings)
private[this] val dreporter = DelegatingReporter(settings, initialLog.reporter)
try {
if (!noErrors(dreporter)) {
dreporter.printSummary()
handleErrors(dreporter, initialLog.logger)
}
} finally initialLog.clear()
/** Instance of the underlying Zinc compiler. */
val compiler: ZincCompiler = newCompiler(command.settings, dreporter, output)
/////////////////////////////////////////////////////////////////////////////////////////////////
def close(): Unit = {
compiler match {
case c: java.io.Closeable => c.close()
case _ =>
}
}
def noErrors(dreporter: DelegatingReporter) = !dreporter.hasErrors && command.ok
def commandArguments(sources: Array[File]): Array[String] =
(command.settings.recreateArgs ++ sources.map(_.getAbsolutePath)).toArray[String]
import scala.tools.nsc.Properties.versionString
def infoOnCachedCompiler(compilerId: String): String =
s"[zinc] Running cached compiler $compilerId for Scala compiler $versionString"
def run(
sources: List[VirtualFile],
changes: DependencyChanges,
callback: AnalysisCallback,
log: Logger,
delegate: Reporter,
progress: CompileProgress
): Unit = synchronized {
debug(log, infoOnCachedCompiler(hashCode().toLong.toHexString))
val dreporter = DelegatingReporter(settings, delegate)
try {
run(sources.sortBy(_.id).map(AbstractZincFile(_)), callback, log, dreporter, progress)
} finally {
dreporter.dropDelegate()
}
}
private def prettyPrintCompilationArguments(args: Array[String]) =
args.mkString("[zinc] The Scala compiler is invoked with:\n\t", "\n\t", "")
private val StopInfoError = "Compiler option supplied that disabled Zinc compilation."
private[this] def run(
sources: List[AbstractFile],
callback: AnalysisCallback,
log: Logger,
underlyingReporter: DelegatingReporter,
compileProgress: CompileProgress
): Unit = {
if (command.shouldStopWithInfo) {
underlyingReporter.info(null, command.getInfoMessage(compiler), true)
throw new InterfaceCompileFailed(args, Array(), StopInfoError)
}
if (noErrors(underlyingReporter)) {
debug(log, prettyPrintCompilationArguments(args))
compiler.set(callback, underlyingReporter)
val run = new compiler.ZincRun(compileProgress)
run.compileFiles(sources)
processUnreportedWarnings(run)
underlyingReporter.problems.foreach(p =>
callback.problem(p.category, p.position, p.message, p.severity, true)
)
}
underlyingReporter.printSummary()
if (!noErrors(underlyingReporter))
handleErrors(underlyingReporter, log)
// the case where we cancelled compilation _after_ some compilation errors got reported
// will be handled by line above so errors still will be reported properly just potentially not
// all of them (because we cancelled the compilation)
if (underlyingReporter.cancelled)
handleCompilationCancellation(underlyingReporter, log)
}
def handleErrors(dreporter: DelegatingReporter, log: Logger): Nothing = {
debug(log, "Compilation failed (CompilerInterface)")
throw new InterfaceCompileFailed(args, dreporter.problems, "Compilation failed")
}
def handleCompilationCancellation(dreporter: DelegatingReporter, log: Logger): Nothing = {
assert(dreporter.cancelled, "We should get here only if when compilation got cancelled")
debug(log, "Compilation cancelled (CompilerInterface)")
throw new InterfaceCompileCancelled(args, "Compilation has been cancelled")
}
def processUnreportedWarnings(run: compiler.Run): Unit = {
// allConditionalWarnings and the ConditionalWarning class are only in 2.10+
final class CondWarnCompat(
val what: String,
val warnings: mutable.ListBuffer[(compiler.Position, String)]
)
implicit def compat(run: AnyRef): Compat = new Compat
final class Compat { def allConditionalWarnings = List[CondWarnCompat]() }
val warnings = run.allConditionalWarnings
if (warnings.nonEmpty)
compiler.logUnreportedWarnings(warnings.map(cw => ("" /*cw.what*/, cw.warnings.toList)))
}
}