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
|
/* NSC -- new Scala compiler
* Copyright 2007-2013 LAMP/EPFL
* @author Lex Spoon
* Updated by Anders Bach Nielsen
*/
package scala.tools.nsc
package plugins
import scala.reflect.io.{ File, Path }
import scala.tools.util.PathResolver.Defaults
/** Support for run-time loading of compiler plugins.
*
* @author Lex Spoon
* @version 1.1, 2009/1/2
* Updated 2009/1/2 by Anders Bach Nielsen: Added features to implement SIP 00002
*/
trait Plugins {
self: Global =>
/** Load a rough list of the plugins. For speed, it
* does not instantiate a compiler run. Therefore it cannot
* test for same-named phases or other problems that are
* filtered from the final list of plugins.
*/
protected def loadRoughPluginsList(): List[Plugin] = {
val jars = settings.plugin.value map Path.apply
def injectDefault(s: String) = if (s.isEmpty) Defaults.scalaPluginPath else s
val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map injectDefault map Path.apply
val maybes = Plugin.loadAllFrom(jars, dirs, settings.disable.value)
val (goods, errors) = maybes partition (_.isSuccess)
// Explicit parameterization of recover to suppress -Xlint warning about inferred Any
errors foreach (_.recover[Any] { case e: Exception => inform(e.getMessage) })
val classes = goods map (_.get) // flatten
// Each plugin must only be instantiated once. A common pattern
// is to register annotation checkers during object construction, so
// creating multiple plugin instances will leave behind stale checkers.
classes map (Plugin.instantiate(_, this))
}
protected lazy val roughPluginsList: List[Plugin] = loadRoughPluginsList()
/** Load all available plugins. Skips plugins that
* either have the same name as another one, or which
* define a phase name that another one does.
*/
protected def loadPlugins(): List[Plugin] = {
// remove any with conflicting names or subcomponent names
def pick(
plugins: List[Plugin],
plugNames: Set[String],
phaseNames: Set[String]): List[Plugin] =
{
if (plugins.isEmpty) return Nil // early return
val plug :: tail = plugins
val plugPhaseNames = Set(plug.components map (_.phaseName): _*)
def withoutPlug = pick(tail, plugNames, plugPhaseNames)
def withPlug = plug :: pick(tail, plugNames + plug.name, phaseNames ++ plugPhaseNames)
lazy val commonPhases = phaseNames intersect plugPhaseNames
def note(msg: String): Unit = if (settings.verbose) inform(msg format plug.name)
def fail(msg: String) = { note(msg) ; withoutPlug }
if (plugNames contains plug.name)
fail("[skipping a repeated plugin: %s]")
else if (settings.disable.value contains plug.name)
fail("[disabling plugin: %s]")
else if (!commonPhases.isEmpty)
fail("[skipping plugin %s because it repeats phase names: " + (commonPhases mkString ", ") + "]")
else {
note("[loaded plugin %s]")
withPlug
}
}
val plugs = pick(roughPluginsList, Set(), (phasesSet map (_.phaseName)).toSet)
/* Verify requirements are present. */
for (req <- settings.require.value ; if !(plugs exists (_.name == req)))
globalError("Missing required plugin: " + req)
/* Process plugin options. */
def namec(plug: Plugin) = plug.name + ":"
def optList(xs: List[String], p: Plugin) = xs filter (_ startsWith namec(p))
def doOpts(p: Plugin): List[String] =
optList(settings.pluginOptions.value, p) map (_ stripPrefix namec(p))
for (p <- plugs) {
val opts = doOpts(p)
if (!opts.isEmpty)
p.processOptions(opts, globalError)
}
/* Verify no non-existent plugin given with -P */
for (opt <- settings.pluginOptions.value ; if plugs forall (p => optList(List(opt), p).isEmpty))
globalError("bad option: -P:" + opt)
plugs
}
lazy val plugins: List[Plugin] = loadPlugins()
/** A description of all the plugins that are loaded */
def pluginDescriptions: String =
roughPluginsList map (x => "%s - %s".format(x.name, x.description)) mkString "\n"
/**
* Extract all phases supplied by plugins and add them to the phasesSet.
* @see phasesSet
*/
protected def computePluginPhases(): Unit =
for (p <- plugins; c <- p.components) addToPhasesSet(c, c.description)
/** Summary of the options for all loaded plugins */
def pluginOptionsHelp: String =
(for (plug <- roughPluginsList ; help <- plug.optionsHelp) yield {
"\nOptions for plugin '%s':\n%s\n".format(plug.name, help)
}).mkString
}
|