diff options
author | Som Snytt <som.snytt@gmail.com> | 2015-06-08 11:09:42 -0700 |
---|---|---|
committer | Som Snytt <som.snytt@gmail.com> | 2015-06-29 10:26:44 -0700 |
commit | 7a076931491ee2467e76f480386ea05e319ec3a2 (patch) | |
tree | d5335f61005653b5a02b86133161de208773d6b9 /src/reflect | |
parent | ffcf07347925cabdfc205aec1e4ff42de840ba5e (diff) | |
download | scala-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.scala | 17 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala | 32 |
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() |