diff --git a/.travis.yml b/.travis.yml index 8e7befbe..f61b76e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,19 @@ language: scala +jdk: oraclejdk8 + scala: - - 2.11.4 +- 2.10.6 +- 2.11.8 +- 2.12.0-RC1 + script: - - "sbt clean test" -jdk: - - oraclejdk7 \ No newline at end of file +- sbt ++$TRAVIS_SCALA_VERSION test + +cache: + directories: + - $HOME/.ivy2/cache + - $HOME/.sbt + +before_cache: +- find "$HOME/.sbt/" -name '*.lock' -print0 | xargs -0 rm +- find "$HOME/.ivy2/" -name 'ivydata-*.properties' -print0 | xargs -0 rm diff --git a/project/EnvSupport.scala b/project/EnvSupport.scala deleted file mode 100644 index a0c27d54..00000000 --- a/project/EnvSupport.scala +++ /dev/null @@ -1,49 +0,0 @@ - -/** @author Stephen Samuel */ -object EnvSupport { - - // code credit: http://stackoverflow.com/a/19040660/2048448 - def setEnv(k: String, v: String): Unit = { - try { - val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment") - val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment") - theEnvironmentField.setAccessible(true) - - val variableClass = Class.forName("java.lang.ProcessEnvironment$Variable") - val convertToVariable = variableClass.getMethod("valueOf", classOf[java.lang.String]) - convertToVariable.setAccessible(true) - - val valueClass = Class.forName("java.lang.ProcessEnvironment$Value") - val convertToValue = valueClass.getMethod("valueOf", classOf[java.lang.String]) - convertToValue.setAccessible(true) - - val sampleVariable = convertToVariable.invoke(null, "") - val sampleValue = convertToValue.invoke(null, "") - val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[sampleVariable.type, sampleValue.type]] - - val variable = convertToVariable.invoke(null, k).asInstanceOf[sampleVariable.type] - val value = convertToValue.invoke(null, v).asInstanceOf[sampleValue.type] - env.put(variable, value) - - val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment") - theCaseInsensitiveEnvironmentField.setAccessible(true) - val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]] - cienv.put(k, v) - - } - catch { - case e: NoSuchFieldException => - val classes = classOf[java.util.Collections].getDeclaredClasses - val env = System.getenv() - classes foreach (cl => { - if ("java.util.Collections$UnmodifiableMap" == cl.getName) { - val field = cl.getDeclaredField("m") - field.setAccessible(true) - val map = field.get(env).asInstanceOf[java.util.Map[String, String]] - map.put(k, v) - } - }) - case e : ClassNotFoundException => - } - } -} diff --git a/project/Scoverage.scala b/project/Scoverage.scala index 998d3eb9..7b7e9464 100644 --- a/project/Scoverage.scala +++ b/project/Scoverage.scala @@ -1,7 +1,5 @@ import sbt.Keys._ import sbt._ -import sbtrelease.ReleasePlugin -import sbtrelease.ReleasePlugin.ReleaseKeys import com.typesafe.sbt.pgp.PgpKeys import org.scalajs.sbtplugin.cross.CrossProject import org.scalajs.sbtplugin.cross.CrossType @@ -11,24 +9,24 @@ import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._ object Scoverage extends Build { val Org = "org.scoverage" - val Scala = "2.11.7" - val MockitoVersion = "1.9.5" - val ScalatestVersion = "3.0.0-M15" + val MockitoVersion = "1.10.19" + val ScalatestVersion = "3.0.0" lazy val LocalTest = config("local") extend Test val appSettings = Seq( organization := Org, - scalaVersion := Scala, - crossScalaVersions := Seq("2.10.6", "2.11.7"), + scalaVersion := "2.11.8", + crossScalaVersions := Seq("2.10.6", scalaVersion.value, "2.12.0-RC1"), fork in Test := false, publishMavenStyle := true, publishArtifact in Test := false, parallelExecution in Test := false, + sbtrelease.ReleasePlugin.autoImport.releasePublishArtifactsAction := PgpKeys.publishSigned.value, + sbtrelease.ReleasePlugin.autoImport.releaseCrossBuild := true, scalacOptions := Seq("-unchecked", "-deprecation", "-feature", "-encoding", "utf8"), resolvers := ("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") +: resolvers.value, concurrentRestrictions in Global += Tags.limit(Tags.Test, 1), - javacOptions := Seq("-source", "1.6", "-target", "1.6"), publishTo <<= version { (v: String) => val nexus = "https://oss.sonatype.org/" @@ -61,16 +59,12 @@ object Scoverage extends Build { pomIncludeRepository := { _ => false } - ) ++ ReleasePlugin.releaseSettings ++ Seq( - ReleaseKeys.crossBuild := true, - ReleaseKeys.publishArtifactsAction := PgpKeys.publishSigned.value ) lazy val root = Project("scalac-scoverage", file(".")) .settings(name := "scalac-scoverage") .settings(appSettings: _*) .settings(publishArtifact := false) - .settings(javaOptions += "-XX:MaxMetaspaceSize=2048m") .aggregate(plugin, runtime.jvm, runtime.js) lazy val runtime = CrossProject("scalac-scoverage-runtime", file("scalac-scoverage-runtime"), CrossType.Full) @@ -78,10 +72,9 @@ object Scoverage extends Build { .settings(appSettings: _*) .jvmSettings( libraryDependencies ++= Seq( - "org.mockito" % "mockito-all" % MockitoVersion % "test", - "org.scalatest" %% "scalatest" % ScalatestVersion % "test" - ), - javaOptions += "-XX:MaxMetaspaceSize=2048m" + "org.mockito" % "mockito-all" % MockitoVersion % Test, + "org.scalatest" %% "scalatest" % ScalatestVersion % Test + ) ) .jsSettings( libraryDependencies += "org.scalatest" %%% "scalatest" % ScalatestVersion, @@ -92,26 +85,36 @@ object Scoverage extends Build { lazy val `scalac-scoverage-runtimeJS` = runtime.js lazy val plugin = Project("scalac-scoverage-plugin", file("scalac-scoverage-plugin")) - .dependsOn(`scalac-scoverage-runtimeJVM` % "test") + .dependsOn(`scalac-scoverage-runtimeJVM` % Test) .settings(name := "scalac-scoverage-plugin") .settings(appSettings: _*) - .settings(javaOptions += "-XX:MaxMetaspaceSize=2048m") + .settings(crossVersionSharedSources) .settings(libraryDependencies ++= Seq( - "org.mockito" % "mockito-all" % MockitoVersion % "test", - "org.scalatest" %% "scalatest" % ScalatestVersion % "test", - "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided", - "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", - "org.joda" % "joda-convert" % "1.6" % "test", - "joda-time" % "joda-time" % "2.3" % "test", - "com.typesafe.scala-logging" %% "scala-logging-slf4j" % "2.1.2" % "test" - )).settings(libraryDependencies ++= { + "org.mockito" % "mockito-all" % MockitoVersion % Test, + "org.scalatest" %% "scalatest" % ScalatestVersion % Test, + "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided", + "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", + "org.joda" % "joda-convert" % "1.8.1" % Test, + "joda-time" % "joda-time" % "2.9.4" % Test + )).settings(libraryDependencies ++= { CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, scalaMajor)) if scalaMajor == 11 => - EnvSupport.setEnv("CrossBuildScalaVersion", "2.11.7") - Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.4") + case Some((2, scalaMajor)) if scalaMajor > 10 => + Seq("org.scala-lang.modules" %% "scala-xml" % "1.0.5") case _ => - EnvSupport.setEnv("CrossBuildScalaVersion", "2.10.6") - Nil + Seq() } }) + + lazy val crossVersionSharedSources: Seq[Setting[_]] = + Seq(Compile, Test).map { sc => + (unmanagedSourceDirectories in sc) ++= { + (unmanagedSourceDirectories in sc ).value.map { dir: File => + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, y)) if y == 10 => new File(dir.getPath + "_2.10") + case Some((2, y)) if y >= 11 => new File(dir.getPath + "_2.11+") + } + } + } + } + } diff --git a/project/build.properties b/project/build.properties index 43b8278c..10eeb5b8 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.11 +sbt.version=0.13.13-M1 diff --git a/project/plugins.sbt b/project/plugins.sbt index c8c17aa4..11fc9ed9 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,9 +1,6 @@ resolvers += Classpaths.sbtPluginReleases -addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.3.2") - -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") - -addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.8.5") - -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.9") +addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0") +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") +addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.12") diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala index 098c5f4a..86b7c535 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala @@ -100,9 +100,9 @@ class CoberturaXmlWriterTest extends FunSuite with BeforeAndAfter with OneInstan writer.write(coverage) val xml = XML.loadFile(fileIn(dir)) + import XmlCompat._ - assert(xml \\ "coverage" \@ "line-rate" === "0.33", "line-rate") - assert(xml \\ "coverage" \@ "branch-rate" === "0.50", "branch-rate") - + assert((xml \\ "coverage" \@ "line-rate") === "0.33", "line-rate") + assert((xml \\ "coverage" \@ "branch-rate") === "0.50", "branch-rate") } } diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala index ae0013c3..f653b835 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala @@ -3,7 +3,7 @@ package scoverage import java.io.{File, FileWriter} import java.util.UUID -import org.scalatest.mock.MockitoSugar +import org.scalatest.mockito.MockitoSugar import org.scalatest.{FreeSpec, Matchers, OneInstancePerTest} /** @author Stephen Samuel */ diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala index 57af802b..795d5769 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala @@ -28,8 +28,9 @@ class LocationCompiler(settings: scala.tools.nsc.Settings, reporter: scala.tools class LocationSetter(val global: Global) extends PluginComponent with TypingTransformers with Transform { override val phaseName: String = "location-setter" - override val runsAfter: List[String] = List("typer") - override val runsBefore = List[String]("patmat") + override val runsRightAfter = Some("typer") + override val runsAfter = List("typer") + override val runsBefore = List[String]("patmat") override protected def newTransformer(unit: global.CompilationUnit): global.Transformer = new Transformer(unit) class Transformer(unit: global.CompilationUnit) extends TypingTransformer(unit) { @@ -44,35 +45,7 @@ class LocationCompiler(settings: scala.tools.nsc.Settings, reporter: scala.tools } override def computeInternalPhases() { - val phs = List( - syntaxAnalyzer -> "parse source into ASTs, perform simple desugaring", - analyzer.namerFactory -> "resolve names, attach symbols to named trees", - analyzer.packageObjects -> "load package objects", - analyzer.typerFactory -> "the meat and potatoes: type the trees", - locationSetter -> "sets locations", - patmat -> "translate match expressions", - superAccessors -> "add super accessors in traits and nested classes", - extensionMethods -> "add extension methods for inline classes", - pickler -> "serialize symbol tables", - refChecks -> "reference/override checking, translate nested objects", - uncurry -> "uncurry, translate function values to anonymous classes", - tailCalls -> "replace tail calls by jumps", - specializeTypes -> "@specialized-driven class and method specialization", - explicitOuter -> "this refs to outer pointers, translate patterns", - erasure -> "erase types, add interfaces for traits", - postErasure -> "clean up erased inline classes", - lazyVals -> "allocate bitmaps, translate lazy vals into lazified defs", - lambdaLift -> "move nested functions to top level", - constructors -> "move field definitions into constructors", - mixer -> "mixin composition", - cleanup -> "platform-specific cleanups, generate reflective calls", - genicode -> "generate portable intermediate code", - inliner -> "optimization: do inlining", - inlineExceptionHandlers -> "optimization: inline exception handlers", - closureElimination -> "optimization: eliminate uncalled closures", - deadCode -> "optimization: eliminate dead code", - terminal -> "The last phase in the compiler chain" - ) - phs foreach (addToPhasesSet _).tupled + super.computeInternalPhases() + addToPhasesSet(locationSetter, "sets locations") } -} \ No newline at end of file +} diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginASTSupportTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/PluginASTSupportTest.scala index d3a62d40..cac56fa9 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginASTSupportTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/PluginASTSupportTest.scala @@ -1,6 +1,6 @@ package scoverage -import org.scalatest.mock.MockitoSugar +import org.scalatest.mockito.MockitoSugar import org.scalatest._ /** @author Stephen Samuel */ @@ -76,29 +76,13 @@ class PluginASTSupportTest assert(!compiler.reporter.hasWarnings) } - // https://github.com/skinny-framework/skinny-framework/issues/97 - test("macro range positions should not break plugin") { - val compiler = ScoverageCompiler.default - compiler.addToClassPath("org.slf4j", "slf4j-api", "1.7.7") - compiler.addToClassPath("com.typesafe.scala-logging", "scala-logging-api_" + ScoverageCompiler.ShortScalaVersion, "2.1.2") - compiler.addToClassPath("com.typesafe.scala-logging", "scala-logging-slf4j_" + ScoverageCompiler.ShortScalaVersion, "2.1.2") - compiler.compileCodeSnippet( """import com.typesafe.scalalogging.slf4j.StrictLogging - | - |object MacroTest extends StrictLogging { - | println("Hello") - | logger.info("will break") - |} """.stripMargin) - assert(!compiler.reporter.hasErrors) - assert(!compiler.reporter.hasWarnings) - } - // https://github.com/scoverage/scalac-scoverage-plugin/issues/45 test("compile final vals in annotations") { val compiler = ScoverageCompiler.default compiler.compileCodeSnippet( """object Foo { | final val foo = 1L |} - |@SerialVersionUID(value = Foo.foo) + |@SerialVersionUID(Foo.foo) |class Bar |""".stripMargin) assert(!compiler.reporter.hasErrors) diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageTest.scala index 86876115..e9e77e37 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageTest.scala @@ -1,6 +1,6 @@ package scoverage -import org.scalatest.mock.MockitoSugar +import org.scalatest.mockito.MockitoSugar import org.scalatest.{BeforeAndAfterEachTestData, FunSuite, OneInstancePerTest} /** @author Stephen Samuel */ @@ -25,23 +25,6 @@ class PluginCoverageTest compiler.assertNMeasuredStatements(2) } - test("scoverage should skip macros") { - val compiler = ScoverageCompiler.default - val code = """ - import scala.language.experimental.macros - import scala.reflect.macros.Context - class Impl(val c: Context) { - import c.universe._ - def poly[T: c.WeakTypeTag] = c.literal(c.weakTypeOf[T].toString) - } - object Macros { - def poly[T] = macro Impl.poly[T] - }""" - compiler.compileCodeSnippet(code) - assert(!compiler.reporter.hasErrors) - compiler.assertNMeasuredStatements(0) - } - test("scoverage should instrument final vals") { val compiler = ScoverageCompiler.default compiler.compileCodeSnippet( """ object FinalVals { @@ -255,44 +238,6 @@ class PluginCoverageTest compiler.assertNMeasuredStatements(11) } - test("plugin should not instrument local macro implementation") { - val compiler = ScoverageCompiler.default - compiler.compileCodeSnippet( """ - | object MyMacro { - | import scala.language.experimental.macros - | import scala.reflect.macros.Context - | def test = macro testImpl - | def testImpl(c: Context): c.Expr[Unit] = { - | import c.universe._ - | reify { - | println("macro test") - | } - | } - |} """.stripMargin) - assert(!compiler.reporter.hasErrors) - compiler.assertNoCoverage() - } - - test("plugin should not instrument expanded macro code github.com/skinny-framework/skinny-framework/issues/97") { - val compiler = ScoverageCompiler.default - compiler.addToClassPath("org.slf4j", "slf4j-api", "1.7.7") - compiler - .addToClassPath("com.typesafe.scala-logging", - "scala-logging-api_" + ScoverageCompiler.ShortScalaVersion, - "2.1.2") - compiler - .addToClassPath("com.typesafe.scala-logging", - "scala-logging-slf4j_" + ScoverageCompiler.ShortScalaVersion, - "2.1.2") - compiler.compileCodeSnippet( """import com.typesafe.scalalogging.slf4j.StrictLogging - |class MacroTest extends StrictLogging { - | logger.info("will break") - |} """.stripMargin) - assert(!compiler.reporter.hasErrors) - assert(!compiler.reporter.hasWarnings) - compiler.assertNoCoverage() - } - ignore("plugin should handle return inside catch github.com/scoverage/scalac-scoverage-plugin/issues/93") { val compiler = ScoverageCompiler.default compiler.compileCodeSnippet( diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala index f7911187..ea935082 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala @@ -1,7 +1,7 @@ package scoverage import org.mockito.Mockito -import org.scalatest.mock.MockitoSugar +import org.scalatest.mockito.MockitoSugar import org.scalatest.{FreeSpec, Matchers} import scala.reflect.internal.util._ diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala index 4addc306..354451a8 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala @@ -11,8 +11,11 @@ import scala.tools.nsc.transform.{Transform, TypingTransformers} /** @author Stephen Samuel */ object ScoverageCompiler { - val ScalaVersion = "2.11.7" - val ShortScalaVersion = ScalaVersion.dropRight(2) + val ScalaVersion = scala.util.Properties.versionNumberString + val ShortScalaVersion = (ScalaVersion split "[.]").toList match { + case init :+ last if last forall (_.isDigit) => init mkString "." + case _ => ScalaVersion + } def classPath = getScalaJars.map(_.getAbsolutePath) :+ sbtCompileDir.getAbsolutePath :+ runtimeClasses.getAbsolutePath @@ -51,31 +54,41 @@ object ScoverageCompiler { dir } - private def runtimeClasses: File = new File("./scalac-scoverage-runtime/jvm/target/scala-2.11/classes") + private def runtimeClasses: File = new File(s"./scalac-scoverage-runtime/jvm/target/scala-$ShortScalaVersion/classes") private def findScalaJar(artifactId: String): File = findIvyJar("org.scala-lang", artifactId, ScalaVersion) + private def findCrossedIvyJar(groupId: String, artifactId: String, version: String): File = + findIvyJar(groupId, artifactId + "_" + ShortScalaVersion, version) + + /* This is the wrong way to go about this. + */ private def findIvyJar(groupId: String, artifactId: String, version: String): File = { - val userHome = System.getProperty("user.home") - val sbtHome = userHome + "/.ivy2" - val jarPath = sbtHome + "/cache/" + groupId + "/" + artifactId + "/jars/" + artifactId + "-" + version + ".jar" - val file = new File(jarPath) - if (!file.exists) - throw new FileNotFoundException(s"Could not locate [$jarPath].") - file + val userHome = System.getProperty("user.home") + val localPath = new File(s"$userHome/.ivy2/local/$groupId/$artifactId/$version/jars/$artifactId.jar") + val cachePath = new File(s"$userHome/.ivy2/cache/$groupId/$artifactId/jars/${artifactId}-${version}.jar") + + Seq(localPath, cachePath) find (_.exists) getOrElse { + throw new FileNotFoundException(s"Could not locate $artifactId at standard location.") + } } } class ScoverageCompiler(settings: scala.tools.nsc.Settings, reporter: scala.tools.nsc.reporters.Reporter) extends scala.tools.nsc.Global(settings, reporter) { - def addToClassPath(groupId: String, artifactId: String, version: String): Unit = { - settings.classpath.value = settings.classpath.value + File.pathSeparator + ScoverageCompiler - .findIvyJar(groupId, artifactId, version) - .getAbsolutePath + def addLogging(): Unit = { + addToClassPath(ScoverageCompiler.findIvyJar("org.slf4j", "slf4j-api", "1.7.7")) + addToClassPath(ScoverageCompiler.findCrossedIvyJar("com.typesafe.scala-logging", "scala-logging", "3.5.0-SNAPSHOT")) + } + def addToClassPath(file: File): Unit = { + settings.classpath.value = settings.classpath.value + File.pathSeparator + file.getAbsolutePath + } + + val instrumentationComponent = new ScoverageInstrumentationComponent(this, None, None) { + override val runsRightAfter = Some("scoverage-validator") } - val instrumentationComponent = new ScoverageInstrumentationComponent(this, None, None) instrumentationComponent.setOptions(new ScoverageOptions()) val testStore = new ScoverageTestStoreComponent(this) val validator = new PositionValidator(this) @@ -112,8 +125,9 @@ class ScoverageCompiler(settings: scala.tools.nsc.Settings, reporter: scala.tool class PositionValidator(val global: Global) extends PluginComponent with TypingTransformers with Transform { override val phaseName: String = "scoverage-validator" - override val runsAfter: List[String] = List("typer") - override val runsBefore = List[String]("scoverage-instrumentation") + override val runsRightAfter = Some("typer") + override val runsAfter = List("typer") + override val runsBefore = List("scoverage-instrumentation") override protected def newTransformer(unit: global.CompilationUnit): global.Transformer = new Transformer(unit) class Transformer(unit: global.CompilationUnit) extends TypingTransformer(unit) { @@ -130,9 +144,8 @@ class ScoverageCompiler(settings: scala.tools.nsc.Settings, reporter: scala.tool val sources = new ListBuffer[String] override val phaseName: String = "scoverage-teststore" - override val runsAfter: List[String] = List("dce") - // deadcode - override val runsBefore = List[String]("terminal") + override val runsAfter = List("jvm") + override val runsBefore = List("terminal") override protected def newTransformer(unit: global.CompilationUnit): global.Transformer = new Transformer(unit) class Transformer(unit: global.CompilationUnit) extends TypingTransformer(unit) { @@ -145,39 +158,9 @@ class ScoverageCompiler(settings: scala.tools.nsc.Settings, reporter: scala.tool } override def computeInternalPhases() { - val phs = List( - syntaxAnalyzer -> "parse source into ASTs, perform simple desugaring", - analyzer.namerFactory -> "resolve names, attach symbols to named trees", - analyzer.packageObjects -> "load package objects", - analyzer.typerFactory -> "the meat and potatoes: type the trees", - validator -> "scoverage validator", - instrumentationComponent -> "scoverage instrumentationComponent", - patmat -> "translate match expressions", - superAccessors -> "add super accessors in traits and nested classes", - extensionMethods -> "add extension methods for inline classes", - pickler -> "serialize symbol tables", - refChecks -> "reference/override checking, translate nested objects", - uncurry -> "uncurry, translate function values to anonymous classes", - tailCalls -> "replace tail calls by jumps", - specializeTypes -> "@specialized-driven class and method specialization", - explicitOuter -> "this refs to outer pointers, translate patterns", - erasure -> "erase types, add interfaces for traits", - postErasure -> "clean up erased inline classes", - lazyVals -> "allocate bitmaps, translate lazy vals into lazified defs", - lambdaLift -> "move nested functions to top level", - constructors -> "move field definitions into constructors", - mixer -> "mixin composition", - cleanup -> "platform-specific cleanups, generate reflective calls", - genicode -> "generate portable intermediate code", - inliner -> "optimization: do inlining", - inlineExceptionHandlers -> "optimization: inline exception handlers", - closureElimination -> "optimization: eliminate uncalled closures", - deadCode -> "optimization: eliminate dead code", - testStore -> "scoverage teststore", - terminal -> "The last phase in the compiler chain" - ) - phs foreach (addToPhasesSet _).tupled + super.computeInternalPhases() + addToPhasesSet(validator, "scoverage validator") + addToPhasesSet(instrumentationComponent, "scoverage instrumentationComponent") + addToPhasesSet(testStore, "scoverage teststore") } } - - diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala index 9982945e..14e1abaf 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala @@ -3,7 +3,7 @@ package scoverage import java.io.StringWriter import org.scalatest.{OneInstancePerTest, FunSuite} -import org.scalatest.mock.MockitoSugar +import org.scalatest.mockito.MockitoSugar import scala.xml.Utility diff --git a/scalac-scoverage-plugin/src/test/scala_2.10/scoverage/PluginCoverageMacrosTest.scala b/scalac-scoverage-plugin/src/test/scala_2.10/scoverage/PluginCoverageMacrosTest.scala new file mode 100644 index 00000000..7b090940 --- /dev/null +++ b/scalac-scoverage-plugin/src/test/scala_2.10/scoverage/PluginCoverageMacrosTest.scala @@ -0,0 +1,51 @@ +package scoverage + +import org.scalatest.mockito.MockitoSugar +import org.scalatest.{BeforeAndAfterEachTestData, FunSuite, OneInstancePerTest} + +/** @author Stephen Samuel */ +class PluginCoverageMacrosTest + extends FunSuite + with MockitoSugar + with OneInstancePerTest + with BeforeAndAfterEachTestData { + + test("scoverage should skip macros") { + val compiler = ScoverageCompiler.default + val code = """ + import scala.language.experimental.macros + import scala.reflect.macros.Context + object Impl { + def poly[T: c.WeakTypeTag](c: Context) = c.literal(c.weakTypeOf[T].toString) + } + + object Macros { + def poly[T] = macro Impl.poly[T] + }""" + compiler.compileCodeSnippet(code) + assert(!compiler.reporter.hasErrors) + compiler.assertNMeasuredStatements(0) + compiler.assertNoCoverage() + } + + test("plugin should not instrument local macro implementation") { + val compiler = ScoverageCompiler.default + compiler.compileCodeSnippet( """ + | object MyMacro { + | import scala.language.experimental.macros + | import scala.reflect.macros.Context + | def test = macro testImpl + | def testImpl(c: Context): c.Expr[Unit] = { + | import c.universe._ + | reify { + | println("macro test") + | } + | } + |} """.stripMargin) + assert(!compiler.reporter.hasErrors) + compiler.assertNoCoverage() + } +} + + + diff --git a/scalac-scoverage-plugin/src/test/scala_2.10/scoverage/XmlCompat.scala b/scalac-scoverage-plugin/src/test/scala_2.10/scoverage/XmlCompat.scala new file mode 100644 index 00000000..b0a1c1fe --- /dev/null +++ b/scalac-scoverage-plugin/src/test/scala_2.10/scoverage/XmlCompat.scala @@ -0,0 +1,7 @@ +package scoverage + +object XmlCompat { +implicit class NodeSeqOps(nodeSeq: scala.xml.NodeSeq) { + def \@(attributeName: String): String = (nodeSeq \ ("@" + attributeName)).text + } +} diff --git a/scalac-scoverage-plugin/src/test/scala_2.11+/scoverage/PluginCoverageMacrosTest.scala b/scalac-scoverage-plugin/src/test/scala_2.11+/scoverage/PluginCoverageMacrosTest.scala new file mode 100644 index 00000000..ff590b42 --- /dev/null +++ b/scalac-scoverage-plugin/src/test/scala_2.11+/scoverage/PluginCoverageMacrosTest.scala @@ -0,0 +1,48 @@ +package scoverage + +import org.scalatest.mockito.MockitoSugar +import org.scalatest.{BeforeAndAfterEachTestData, FunSuite, OneInstancePerTest} + +/** @author Stephen Samuel */ +class PluginCoverageMacrosTest + extends FunSuite + with MockitoSugar + with OneInstancePerTest + with BeforeAndAfterEachTestData { + + test("scoverage should skip macros") { + val compiler = ScoverageCompiler.default + val code = """ + import scala.language.experimental.macros + import scala.reflect.macros.whitebox.Context + class Impl(val c: Context) { + import c.universe._ + def poly[T: c.WeakTypeTag] = c.literal(c.weakTypeOf[T].toString) + } + object Macros { + def poly[T] = macro Impl.poly[T] + }""" + compiler.compileCodeSnippet(code) + assert(!compiler.reporter.hasErrors) + compiler.assertNMeasuredStatements(0) + compiler.assertNoCoverage() + } + + test("plugin should not instrument local macro implementation") { + val compiler = ScoverageCompiler.default + compiler.compileCodeSnippet( """ + | object MyMacro { + | import scala.language.experimental.macros + | import scala.reflect.macros.whitebox.Context + | def test = macro testImpl + | def testImpl(c: Context): c.Expr[Unit] = { + | import c.universe._ + | reify { + | println("macro test") + | } + | } + |} """.stripMargin) + assert(!compiler.reporter.hasErrors) + compiler.assertNoCoverage() + } +} diff --git a/scalac-scoverage-plugin/src/test/scala_2.11+/scoverage/XmlCompat.scala b/scalac-scoverage-plugin/src/test/scala_2.11+/scoverage/XmlCompat.scala new file mode 100644 index 00000000..0b964f1f --- /dev/null +++ b/scalac-scoverage-plugin/src/test/scala_2.11+/scoverage/XmlCompat.scala @@ -0,0 +1,5 @@ +package scoverage + +object XmlCompat { + +}