diff --git a/bridge/src/main/scala/xsbt/CompilerInterface.scala b/bridge/src/main/scala/xsbt/CompilerInterface.scala index ee272b8b127f..bf1488dad93b 100644 --- a/bridge/src/main/scala/xsbt/CompilerInterface.scala +++ b/bridge/src/main/scala/xsbt/CompilerInterface.scala @@ -50,12 +50,14 @@ class CachedCompilerImpl(args: Array[String], output: Output, resident: Boolean) (outputArgs ++ args.toList ++ sources.map(_.getAbsolutePath).sortWith(_ < _)).toArray[String] def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, progress: CompileProgress): Unit = synchronized { - run(sources.toList, changes, callback, log, progress) + run(sources.toList, changes, callback, log, delegate, progress) } - private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, compileProgress: CompileProgress): Unit = { + private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, compileProgress: CompileProgress): Unit = { debug(log, args.mkString("Calling Dotty compiler with arguments (CompilerInterface):\n\t", "\n\t", "")) val ctx = (new ContextBase).initialCtx.fresh .setSbtCallback(callback) + .setReporter(new DelegatingReporter(delegate)) + val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader] val reporter = DottyMain.process(commandArguments(sources.toArray), ctx) diff --git a/bridge/src/main/scala/xsbt/DelegatingReporter.scala b/bridge/src/main/scala/xsbt/DelegatingReporter.scala new file mode 100644 index 000000000000..726570d71d91 --- /dev/null +++ b/bridge/src/main/scala/xsbt/DelegatingReporter.scala @@ -0,0 +1,58 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import dotty.tools._ +import dotc._ +import reporting._ +import core.Contexts._ + +import xsbti.{Maybe, Position} + +final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter + with UniqueMessagePositions + with HideNonSensicalMessages { + + override def printSummary(implicit ctx: Context): Unit = delegate.printSummary() + + def doReport(d: Diagnostic)(implicit ctx: Context): Unit = { + val severity = + d match { + case _: Reporter.Error => xsbti.Severity.Error + case _: Reporter.Warning => xsbti.Severity.Warn + case _ => xsbti.Severity.Info + } + val pos = + if (d.pos.exists) Some(d.pos) + else None + + val file = + if (d.pos.source.file.exists) Option(d.pos.source.file.file) + else None + + val offset0 = pos.map(_.point) + + val position = new Position { + def line: Maybe[Integer] = maybe(pos.map(_.line)) + def lineContent: String = pos.map(_.lineContent).getOrElse("") + def offset: Maybe[Integer] = maybeInt(offset0) + def pointer: Maybe[Integer] = offset + def pointerSpace: Maybe[String] = maybe(offset0.map(" " * _)) + def sourceFile: Maybe[java.io.File] = maybe(file) + def sourcePath: Maybe[String] = maybe(file.map(_.getPath)) + } + + delegate.log(position, d.message, severity) + } + + private[this] def maybe[T](opt: Option[T]): Maybe[T] = opt match { + case None => Maybe.nothing[T] + case Some(s) => Maybe.just[T](s) + } + import java.lang.{ Integer => I } + private[this] def maybeInt(opt: Option[Int]): Maybe[I] = opt match { + case None => Maybe.nothing[I] + case Some(s) => Maybe.just[I](s) + } +} \ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/Source.scala b/bridge/src/sbt-test/compilerReporter/simple/Source.scala new file mode 100644 index 000000000000..6f06785990c3 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/Source.scala @@ -0,0 +1,10 @@ +trait A +trait B + +trait Wr { + val z: A with B +} + +object Er { + val a = er1 +} \ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/build.sbt b/bridge/src/sbt-test/compilerReporter/simple/build.sbt new file mode 100644 index 000000000000..017846f5ed23 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/build.sbt @@ -0,0 +1 @@ +Reporter.checkSettings \ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/project/DottyInjectedPlugin.scala b/bridge/src/sbt-test/compilerReporter/simple/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..3433779b6c66 --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/project/DottyInjectedPlugin.scala @@ -0,0 +1,17 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := "0.1-SNAPSHOT", + scalaOrganization := "ch.epfl.lamp", + scalacOptions += "-language:Scala2", + scalaBinaryVersion := "2.11", + autoScalaLibrary := false, + libraryDependencies ++= Seq("org.scala-lang" % "scala-library" % "2.11.5"), + scalaCompilerBridgeSource := ("ch.epfl.lamp" % "dotty-bridge" % "0.1.1-SNAPSHOT" % "component").sources() + ) +} diff --git a/bridge/src/sbt-test/compilerReporter/simple/project/Reporter.scala b/bridge/src/sbt-test/compilerReporter/simple/project/Reporter.scala new file mode 100644 index 000000000000..c0a56ec82c8c --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/project/Reporter.scala @@ -0,0 +1,44 @@ +import sbt._ +import Keys._ +import KeyRanks.DTask + +object Reporter { + import xsbti.{Reporter, Problem, Position, Severity, Maybe} + + lazy val check = TaskKey[Unit]("check", "make sure compilation info are forwared to sbt") + + // compilerReporter is marked private in sbt + lazy val compilerReporter = TaskKey[Option[xsbti.Reporter]]("compilerReporter", "Experimental hook to listen (or send) compilation failure messages.", DTask) + + lazy val reporter = + Some(new xsbti.Reporter { + private val buffer = collection.mutable.ArrayBuffer.empty[Problem] + def reset(): Unit = buffer.clear() + def hasErrors: Boolean = buffer.exists(_.severity == Severity.Error) + def hasWarnings: Boolean = buffer.exists(_.severity == Severity.Warn) + def printSummary(): Unit = println(problems.mkString(System.lineSeparator)) + def problems: Array[Problem] = buffer.toArray + def log(pos: Position, msg: String, sev: Severity): Unit = { + object MyProblem extends Problem { + def category: String = null + def severity: Severity = sev + def message: String = msg + def position: Position = pos + override def toString = s"custom: $position:$severity: $message" + } + buffer.append(MyProblem) + } + def comment(pos: xsbti.Position, msg: String): Unit = () + }) + + lazy val checkSettings = Seq( + compilerReporter in (Compile, compile) := reporter, + check <<= (compile in Compile).mapFailure( _ => { + val problems = reporter.get.problems + println(problems.toList) + assert(problems.size == 2) + assert(problems.count(_.severity == Severity.Error) == 1) // not found: er1, + assert(problems.count(_.severity == Severity.Warn) == 1) // `with' as a type operator has been deprecated; use `&' instead, + }) + ) +} \ No newline at end of file diff --git a/bridge/src/sbt-test/compilerReporter/simple/test b/bridge/src/sbt-test/compilerReporter/simple/test new file mode 100644 index 000000000000..a5912a391a4d --- /dev/null +++ b/bridge/src/sbt-test/compilerReporter/simple/test @@ -0,0 +1 @@ +> check \ No newline at end of file diff --git a/project/Build.scala b/project/Build.scala index 1412556a9732..ec2db8339e88 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -207,11 +207,31 @@ object DottyBuild extends Build { ). settings(publishing) + // until sbt/sbt#2402 is fixed (https://github.com/sbt/sbt/issues/2402) + lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") + lazy val `dotty-bridge` = project.in(file("bridge")). dependsOn(dotty). settings( overrideScalaVersionSetting, + cleanSbtBridge := { + val dottyBridgeVersion = version.value + val dottyVersion = (version in dotty).value + val classVersion = System.getProperty("java.class.version") + + val sbtV = sbtVersion.value + val sbtOrg = "org.scala-sbt" + val sbtScalaVersion = "2.10.6" + + val home = System.getProperty("user.home") + val org = organization.value + val artifact = moduleName.value + + IO.delete(file(home) / ".ivy2" / "cache" / sbtOrg / s"$org-$artifact-$dottyBridgeVersion-bin_${dottyVersion}__$classVersion") + IO.delete(file(home) / ".sbt" / "boot" / s"scala-$sbtScalaVersion" / sbtOrg / "sbt" / sbtV / s"$org-$artifact-$dottyBridgeVersion-bin_${dottyVersion}__$classVersion") + }, + publishLocal := (publishLocal.dependsOn(cleanSbtBridge)).value, description := "sbt compiler bridge for Dotty", resolvers += Resolver.typesafeIvyRepo("releases"), libraryDependencies ++= Seq(