summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2015-06-08 11:09:42 -0700
committerSom Snytt <som.snytt@gmail.com>2015-06-29 10:26:44 -0700
commit7a076931491ee2467e76f480386ea05e319ec3a2 (patch)
treed5335f61005653b5a02b86133161de208773d6b9 /src/reflect
parentffcf07347925cabdfc205aec1e4ff42de840ba5e (diff)
downloadscala-7a076931491ee2467e76f480386ea05e319ec3a2.tar.gz
scala-7a076931491ee2467e76f480386ea05e319ec3a2.tar.bz2
scala-7a076931491ee2467e76f480386ea05e319ec3a2.zip
SI-9350 Command option -Xreporter
Add a setting to take a custom Reporter. Example of reporter that discounts deprecations for purposes of (not) failing the build: ``` import scala.tools.nsc.Settings import scala.tools.nsc.reporters.ConsoleReporter import scala.reflect.internal.util._ class MyReporter(ss: Settings) extends ConsoleReporter(ss) { var deprecationCount = 0 override def warning(pos: Position, msg: String): Unit = { if (msg contains "is deprecated") deprecationCount += 1 super.warning(pos, msg) } override def hasWarnings: Boolean = count(WARNING) - deprecationCount > 0 override def reset() = { deprecationCount = 0 ; super.reset() } } ``` Invoked as: ``` $ scalac -toolcp . -Xreporter myrep.MyReporter -Xfatal-warnings -deprecation test.scala test.scala:8: warning: class C in package tester is deprecated: Don't use me Console println s"${new C}" ^ one warning found ``` where the reporter class is in the current directory, placed on the tool class path. Also flush on early-reported errors.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Reporting.scala17
-rw-r--r--src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala32
2 files changed, 41 insertions, 8 deletions
diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala
index f2de83bc5d..2534f59c97 100644
--- a/src/reflect/scala/reflect/internal/Reporting.scala
+++ b/src/reflect/scala/reflect/internal/Reporting.scala
@@ -8,11 +8,11 @@ package reflect
package internal
/** Provides delegates to the reporter doing the actual work.
- * All forwarding methods should be marked final,
- * but some subclasses out of our reach stil override them.
+ * All forwarding methods should be marked final,
+ * but some subclasses out of our reach stil override them.
*
- * Eventually, this interface should be reduced to one method: `reporter`,
- * and clients should indirect themselves (reduce duplication of forwarders).
+ * Eventually, this interface should be reduced to one method: `reporter`,
+ * and clients should indirect themselves (reduce duplication of forwarders).
*/
trait Reporting { self : Positions =>
def reporter: Reporter
@@ -71,8 +71,8 @@ import util.Position
/** Report information, warnings and errors.
*
- * This describes the (future) external interface for issuing information, warnings and errors.
- * Currently, scala.tools.nsc.Reporter is used by sbt/ide/partest.
+ * This describes the (future) external interface for issuing information, warnings and errors.
+ * Currently, scala.tools.nsc.Reporter is used by sbt/ide/partest.
*/
abstract class Reporter {
protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit
@@ -101,7 +101,10 @@ abstract class Reporter {
resetCount(ERROR)
}
- def flush(): Unit = { }
+ def flush(): Unit = ()
+
+ /** Finish reporting: print summaries, release resources. */
+ def finish(): Unit = ()
}
// TODO: move into superclass once partest cuts tie on Severity
diff --git a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
index 41011f6c6b..04bc2dd7e8 100644
--- a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
+++ b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
@@ -11,7 +11,8 @@ import java.lang.reflect.{ Constructor, Modifier, Method }
import java.io.{ File => JFile }
import java.net.{ URLClassLoader => JURLClassLoader }
import java.net.URL
-import scala.reflect.runtime.ReflectionUtils.unwrapHandler
+import scala.reflect.internal.FatalError
+import scala.reflect.runtime.ReflectionUtils.{ show, unwrapHandler }
import ScalaClassLoader._
import scala.util.control.Exception.{ catching }
import scala.language.implicitConversions
@@ -46,6 +47,35 @@ trait ScalaClassLoader extends JClassLoader {
def create(path: String): AnyRef =
tryToInitializeClass[AnyRef](path).map(_.newInstance()).orNull
+ /** Create an instance with ctor args, or invoke errorFn before throwing FatalError. */
+ def create[T <: AnyRef : ClassTag](path: String, errorFn: String => Unit)(args: AnyRef*): T = {
+ def fail(msg: String) = {
+ errorFn(msg)
+ throw FatalError(msg)
+ }
+ try {
+ val clazz = Class.forName(path, /*initialize =*/ true, /*loader =*/ this)
+ if (classTag[T].runtimeClass isAssignableFrom clazz) {
+ val ctor = {
+ val maybes = clazz.getConstructors filter (c => c.getParameterCount == args.size &&
+ (c.getParameterTypes zip args).forall { case (k, a) => k isAssignableFrom a.getClass })
+ if (maybes.size == 1) maybes.head
+ else fail(s"Constructor must accept arg list (${args map (_.getClass.getName) mkString ", "}): ${path}")
+ }
+ (ctor.newInstance(args: _*)).asInstanceOf[T]
+ } else {
+ errorFn(s"""Loader for ${classTag[T]}: [${show(classTag[T].runtimeClass.getClassLoader)}]
+ |Loader for ${clazz.getName}: [${show(clazz.getClassLoader)}]""".stripMargin)
+ fail(s"Not a ${classTag[T]}: ${path}")
+ }
+ } catch {
+ case _: ClassNotFoundException =>
+ fail(s"Class not found: ${path}")
+ case e @ (_: LinkageError | _: ReflectiveOperationException) =>
+ fail(s"Unable to create instance: ${path}: ${e.toString}")
+ }
+ }
+
/** The actual bytes for a class file, or an empty array if it can't be found. */
def classBytes(className: String): Array[Byte] = classAsStream(className) match {
case null => Array()