diff --git a/main/src/main/scala/sbt/Plugins.scala b/main/src/main/scala/sbt/Plugins.scala index 5b6cf57fe..6f4341ce9 100644 --- a/main/src/main/scala/sbt/Plugins.scala +++ b/main/src/main/scala/sbt/Plugins.scala @@ -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. */