mirror of https://github.com/sbt/sbt.git
Don't use runtime universe to discover autoImport
The previous implementation was using the Scala runtime universe to check whether a plugin had or not an `autoImport` member. This is a bad idea for the following reasons: * The first time you use it, you class load the whole Scalac compiler universe. Not efficient. Measurements say this is about a second. * There is a small overhead of going through the reflection API. There exists a better approach that consists in checking if `autoImport` exists with pure Java reflection. Since the class is already class loaded, we check for: * A class file named after the plugin FQN that includes `autoImport$` at the end, which means that an object named `autoImport` exists. * A field in the plugin class that is named `autoImport`. This complies with the plugin sbt specification: http://www.scala-sbt.org/1.0/docs/Plugins.html#Controlling+the+import+with+autoImport
This commit is contained in:
parent
27b4faebed
commit
a36d8401e1
|
|
@ -349,18 +349,34 @@ ${listConflicts(conflicting)}""")
|
|||
case ap: AutoPlugin => model(ap)
|
||||
}
|
||||
|
||||
private val autoImport = "autoImport"
|
||||
|
||||
/** Determines whether a plugin has a stable autoImport member by:
|
||||
*
|
||||
* 1. Checking whether there exists a public field.
|
||||
* 2. Checking whether there exists a public object.
|
||||
*
|
||||
* The above checks work for inherited members too.
|
||||
*
|
||||
* @param ap The found plugin.
|
||||
* @param loader The plugin loader.
|
||||
* @return True if plugin has a stable member `autoImport`, otherwise false.
|
||||
*/
|
||||
private[sbt] def hasAutoImportGetter(ap: AutoPlugin, loader: ClassLoader): Boolean = {
|
||||
import reflect.runtime.{ universe => ru }
|
||||
import java.lang.reflect.Field
|
||||
import scala.util.control.Exception.catching
|
||||
val m = ru.runtimeMirror(loader)
|
||||
val im = m.reflect(ap)
|
||||
val hasGetterOpt = catching(classOf[ScalaReflectionException]) opt {
|
||||
im.symbol.asType.toType.decl(ru.TermName("autoImport")) match {
|
||||
case ru.NoSymbol => false
|
||||
case sym => sym.asTerm.isGetter || sym.asTerm.isModule
|
||||
}
|
||||
// Make sure that we don't detect user-defined methods called autoImport
|
||||
def existsAutoImportVal(clazz: Class[_]): Option[Field] = {
|
||||
catching(classOf[NoSuchFieldException])
|
||||
.opt(clazz.getDeclaredField(autoImport))
|
||||
.orElse(Option(clazz.getSuperclass).flatMap(existsAutoImportVal))
|
||||
}
|
||||
hasGetterOpt getOrElse false
|
||||
|
||||
val pluginClazz = ap.getClass
|
||||
existsAutoImportVal(pluginClazz)
|
||||
.orElse(catching(classOf[ClassNotFoundException]).opt(
|
||||
Class.forName(s"${pluginClazz.getName}$autoImport$$", false, loader)))
|
||||
.isDefined
|
||||
}
|
||||
|
||||
/** Debugging method to time how long it takes to run various compilation tasks. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue