summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-05-16 16:04:17 +1000
committerLukas Rytz <lukas.rytz@typesafe.com>2016-05-16 08:04:17 +0200
commiteac1af364e99a6712c5e54e257216027b2ab127e (patch)
tree7913340cff137466511c3d6ca4066fdd55d4aeb9
parent9e30bee0c9363f6cf36a7b65ddbaaa225b57d6a9 (diff)
downloadscala-eac1af364e99a6712c5e54e257216027b2ab127e.tar.gz
scala-eac1af364e99a6712c5e54e257216027b2ab127e.tar.bz2
scala-eac1af364e99a6712c5e54e257216027b2ab127e.zip
Reduce boilerplate in compiler JUnit tests (#5158)
Many JUnit tests share a compiler instance between all test cases in a class to reduce overhead. This commit refactors the mechanism to reduce the boilerplate. In the new scheme: - Using the `@ClassRule` hook in JUnit, we create a per-class map for each test class. - Per-class values are registered from the test class itself by calling `cached("someKey", () => mkExpensiveThing)` - At the end of the test, the entries in this map are `close()`-ed (if they implement `Closable`), and are released for garbage collection.)
-rw-r--r--test/junit/scala/issues/BytecodeTest.scala8
-rw-r--r--test/junit/scala/issues/OptimizedBytecodeTest.scala15
-rw-r--r--test/junit/scala/issues/RunTest.scala11
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala15
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala9
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala11
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala14
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala11
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala11
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala26
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala9
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala14
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala22
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala20
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala9
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala32
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala9
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala24
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala9
-rw-r--r--test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala12
-rw-r--r--test/junit/scala/tools/testing/ClearAfterClass.java47
25 files changed, 112 insertions, 258 deletions
diff --git a/test/junit/scala/issues/BytecodeTest.scala b/test/junit/scala/issues/BytecodeTest.scala
index cf5c7f9ec3..a720f20718 100644
--- a/test/junit/scala/issues/BytecodeTest.scala
+++ b/test/junit/scala/issues/BytecodeTest.scala
@@ -15,15 +15,9 @@ import scala.tools.asm.tree.ClassNode
import scala.tools.partest.ASMConverters._
import scala.tools.testing.ClearAfterClass
-object BytecodeTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class BytecodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = BytecodeTest
- val compiler = BytecodeTest.compiler
+ val compiler = cached("compiler", () => newCompiler())
@Test
def t8731(): Unit = {
diff --git a/test/junit/scala/issues/OptimizedBytecodeTest.scala b/test/junit/scala/issues/OptimizedBytecodeTest.scala
index 1555e8945a..c69229ae22 100644
--- a/test/junit/scala/issues/OptimizedBytecodeTest.scala
+++ b/test/junit/scala/issues/OptimizedBytecodeTest.scala
@@ -15,17 +15,10 @@ import AsmUtils._
import scala.tools.testing.ClearAfterClass
-object OptimizedBytecodeTest extends ClearAfterClass.Clearable {
- val args = "-Yopt:l:classpath -Yopt-warnings"
- var compiler = newCompiler(extraArgs = args)
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class OptimizedBytecodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = OptimizedBytecodeTest
-
- val compiler = OptimizedBytecodeTest.compiler
+ val args = "-Yopt:l:classpath -Yopt-warnings"
+ val compiler = cached("compiler", () => newCompiler(extraArgs = args))
@Test
def t2171(): Unit = {
@@ -127,7 +120,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
|object Warmup { def filter[A](p: Any => Boolean): Any = filter[Any](p) }
""".stripMargin
val c2 = "class C { def t = warmup.Warmup.filter[Any](x => false) }"
- val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args)
+ val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = args)
assertInvoke(getSingleMethod(c, "t"), "warmup/Warmup$", "filter")
}
@@ -268,7 +261,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
|}
""".stripMargin
- val cls = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args)
+ val cls = compileClassesSeparately(List(c1, c2), extraArgs = args)
val c = cls.find(_.name == "C").get
assertSameSummary(getSingleMethod(c, "t"), List(
GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW, // module load and null checks not yet eliminated
diff --git a/test/junit/scala/issues/RunTest.scala b/test/junit/scala/issues/RunTest.scala
index 0605947e63..148009c912 100644
--- a/test/junit/scala/issues/RunTest.scala
+++ b/test/junit/scala/issues/RunTest.scala
@@ -9,22 +9,17 @@ import scala.reflect.runtime._
import scala.tools.reflect.ToolBox
import scala.tools.testing.ClearAfterClass
-object RunTest extends ClearAfterClass.Clearable {
- var toolBox = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
- override def clear(): Unit = { toolBox = null }
-
- // definitions for individual tests
+object RunTest {
class VC(val x: Any) extends AnyVal
}
@RunWith(classOf[JUnit4])
class RunTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = RunTest
+ val toolBox = cached("toolbox", () => universe.runtimeMirror(getClass.getClassLoader).mkToolBox())
def run[T](code: String): T = {
- val tb = RunTest.toolBox
- tb.eval(tb.parse(code)).asInstanceOf[T]
+ toolBox.eval(toolBox.parse(code)).asInstanceOf[T]
}
@Test
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
index 8b8e2b36de..e7bbbb9a4f 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -10,22 +10,15 @@ import org.junit.Assert._
import scala.tools.nsc.backend.jvm.CodeGenTools._
import scala.tools.testing.ClearAfterClass
-object BTypesTest extends ClearAfterClass.Clearable {
- var compiler = {
+@RunWith(classOf[JUnit4])
+class BTypesTest extends ClearAfterClass {
+ val compiler = cached("compiler", () => {
val comp = newCompiler(extraArgs = "-Yopt:l:none")
new comp.Run() // initializes some of the compiler
comp.exitingDelambdafy(comp.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler
comp.exitingDelambdafy(comp.genBCode.bTypes.initializeCoreBTypes())
comp
- }
- def clear(): Unit = { compiler = null }
-}
-
-@RunWith(classOf[JUnit4])
-class BTypesTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = BTypesTest
-
- val compiler = BTypesTest.compiler
+ })
import compiler.genBCode.bTypes._
def classBTFS(sym: compiler.Symbol) = compiler.exitingDelambdafy(classBTypeFromSymbol(sym))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala
index 2ce9d21331..7d4ae866fc 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala
@@ -10,14 +10,8 @@ import scala.tools.nsc.backend.jvm.CodeGenTools._
import JavaConverters._
import scala.tools.testing.ClearAfterClass
-object DefaultMethodTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
-
class DefaultMethodTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = DefaultMethodTest
- val compiler = DefaultMethodTest.compiler
+ val compiler = cached("compiler", () => newCompiler())
@Test
def defaultMethodsViaGenBCode(): Unit = {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
index 0cdc6ead10..e984b75518 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
@@ -9,16 +9,9 @@ import scala.tools.asm.Opcodes._
import scala.tools.partest.ASMConverters._
import scala.tools.testing.ClearAfterClass
-object DirectCompileTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:method")
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class DirectCompileTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = DirectCompileTest
-
- val compiler = DirectCompileTest.compiler
+ val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:method"))
@Test
def testCompile(): Unit = {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
index d29f6b0a13..b906942ffa 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
@@ -10,17 +10,8 @@ import scala.tools.nsc.backend.jvm.CodeGenTools._
import scala.tools.testing.ClearAfterClass
import scala.collection.JavaConverters._
-object IndyLambdaTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
-
- def clear(): Unit = {
- compiler = null
- }
-}
-
class IndyLambdaTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = IndyLambdaTest
- val compiler = IndyLambdaTest.compiler
+ val compiler = cached("compiler", () => newCompiler())
@Test def boxingBridgeMethodUsedSelectively(): Unit = {
def implMethodDescriptorFor(code: String): String = {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
index b9e45a7dc9..5c2ab6a2c7 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
@@ -15,21 +15,13 @@ import ASMConverters._
import scala.tools.testing.ClearAfterClass
-object IndySammyTest extends ClearAfterClass.Clearable {
- var _compiler = newCompiler()
-
- def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] =
- compileClasses(_compiler)(scalaCode, javaCode, allowMessage)
-
- def clear(): Unit = { _compiler = null }
-}
@RunWith(classOf[JUnit4])
class IndySammyTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = IndySammyTest
- import IndySammyTest._
- val compiler = _compiler
+ val compiler = cached("compiler", () => newCompiler())
+ def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] =
+ compileClasses(compiler)(scalaCode, javaCode, allowMessage)
def funClassName(from: String, to: String) = s"Fun$from$to"
def classPrologue(from: String, to: String) =
diff --git a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
index 2a9b8f7198..fc0c96e71a 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
@@ -14,15 +14,9 @@ import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass
-object StringConcatTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class StringConcatTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = StringConcatTest
- val compiler = StringConcatTest.compiler
+ val compiler = cached("compiler", () => newCompiler())
@Test
def appendOverloadNoBoxing(): Unit = {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
index 571d84c872..075f42d18f 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
@@ -19,18 +19,9 @@ import AsmUtils._
import scala.collection.JavaConverters._
-object NullnessAnalyzerTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
-
- def clear(): Unit = {
- noOptCompiler = null
- }
-}
-
@RunWith(classOf[JUnit4])
class NullnessAnalyzerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = NullnessAnalyzerTest
- val noOptCompiler = NullnessAnalyzerTest.noOptCompiler
+ val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
import noOptCompiler.genBCode.bTypes.backendUtils._
def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(noOptCompiler.genBCode.bTypes))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala
index d54b8ac563..8d4bc19ec3 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala
@@ -14,18 +14,9 @@ import scala.tools.testing.ClearAfterClass
import CodeGenTools._
import AsmUtils._
-object ProdConsAnalyzerTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
-
- def clear(): Unit = {
- noOptCompiler = null
- }
-}
-
@RunWith(classOf[JUnit4])
class ProdConsAnalyzerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ProdConsAnalyzerTest
- val noOptCompiler = ProdConsAnalyzerTest.noOptCompiler
+ val noOptCompiler =cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
import noOptCompiler.genBCode.bTypes.backendUtils._
def prodToString(producer: AbstractInsnNode) = producer match {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala
index 930f7f2f10..09675870f0 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala
@@ -21,15 +21,9 @@ import BytecodeUtils._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object AnalyzerTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
- def clear(): Unit = { noOptCompiler = null }
-}
-
@RunWith(classOf[JUnit4])
class AnalyzerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = AnalyzerTest
- val noOptCompiler = AnalyzerTest.noOptCompiler
+ val noOptCompiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
@Test
def aliasingOfPrimitives(): Unit = {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
index 1d30e42e3c..9a27c42cac 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
@@ -24,29 +24,23 @@ import BackendReporting._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object CallGraphTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:inline-global -Yopt-warnings")
- def clear(): Unit = { compiler = null }
-
- // allows inspecting the caches after a compilation run
- val notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses,
- compiler.genBCode.bTypes.callGraph.callsites)
- notPerRun foreach compiler.perRunCaches.unrecordCache
-}
-
@RunWith(classOf[JUnit4])
class CallGraphTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = CallGraphTest
+ val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:inline-global -Yopt-warnings")
+ )
+ import compiler.genBCode.bTypes
+ val notPerRun: List[Clearable] = List(
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses,
+ bTypes.callGraph.callsites)
+ notPerRun foreach compiler.perRunCaches.unrecordCache
- val compiler = CallGraphTest.compiler
import compiler.genBCode.bTypes._
import callGraph._
def compile(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
- CallGraphTest.notPerRun.foreach(_.clear())
+ notPerRun.foreach(_.clear())
compileClasses(compiler)(code, allowMessage = allowMessage).map(c => byteCodeRepository.classNode(c.name).get)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
index 12bfba71a8..e8530af4e0 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
@@ -27,16 +27,9 @@ import BackendReporting._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object ClosureOptimizerTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:classpath -Yopt-warnings:_")
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class ClosureOptimizerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ClosureOptimizerTest
-
- val compiler = ClosureOptimizerTest.compiler
+ val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:classpath -Yopt-warnings:_"))
@Test
def nothingTypedClosureBody(): Unit = {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
index 22aed4207f..6d566c722f 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
@@ -13,21 +13,11 @@ import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass
-object EmptyExceptionHandlersTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
- var dceCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
- def clear(): Unit = {
- noOptCompiler = null
- dceCompiler = null
- }
-}
@RunWith(classOf[JUnit4])
class EmptyExceptionHandlersTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = EmptyExceptionHandlersTest
-
- val noOptCompiler = EmptyExceptionHandlersTest.noOptCompiler
- val dceCompiler = EmptyExceptionHandlersTest.dceCompiler
+ val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
+ val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code"))
val exceptionDescriptor = "java/lang/Exception"
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
index 23386bb5ae..5cb1aab4a9 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
@@ -18,25 +18,19 @@ import BackendReporting._
import scala.collection.JavaConverters._
-object InlineInfoTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:classpath")
- def clear(): Unit = { compiler = null }
-
- def notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses)
- notPerRun foreach compiler.perRunCaches.unrecordCache
-}
-
@RunWith(classOf[JUnit4])
class InlineInfoTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlineInfoTest
+ val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:classpath"))
- val compiler = InlineInfoTest.compiler
+ import compiler.genBCode.bTypes
+ def notPerRun: List[Clearable] = List(
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses)
+ notPerRun foreach compiler.perRunCaches.unrecordCache
def compile(code: String) = {
- InlineInfoTest.notPerRun.foreach(_.clear())
+ notPerRun.foreach(_.clear())
compileClasses(compiler)(code)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
index 1597c75a7e..6dd0a33289 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
@@ -27,20 +27,12 @@ import BackendReporting._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object InlineWarningTest extends ClearAfterClass.Clearable {
- val argsNoWarn = "-Yopt:l:classpath"
- val args = argsNoWarn + " -Yopt-warnings"
- var compiler = newCompiler(extraArgs = args)
- var compilerWarnAll = newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:_")
- def clear(): Unit = { compiler = null; compilerWarnAll = null }
-}
-
@RunWith(classOf[JUnit4])
class InlineWarningTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlineWarningTest
-
- val compiler = InlineWarningTest.compiler
- val compilerWarnAll = InlineWarningTest.compilerWarnAll
+ val argsNoWarn = "-Yopt:l:classpath"
+ val args = argsNoWarn + " -Yopt-warnings"
+ val compiler = cached("compiler", () => newCompiler(extraArgs = args))
+ val compilerWarnAll = cached("compilerWarnAll", () => newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:_"))
def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false, compiler: Global = compiler): List[ClassNode] = {
compileClasses(compiler)(scalaCode, javaCode, allowMessage)
@@ -115,10 +107,10 @@ class InlineWarningTest extends ClearAfterClass {
assert(c == 1, c)
// no warnings here
- compileClasses(newCompiler(extraArgs = InlineWarningTest.argsNoWarn + " -Yopt-warnings:none"))(scalaCode, List((javaCode, "A.java")))
+ compileClasses(newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:none"))(scalaCode, List((javaCode, "A.java")))
c = 0
- compileClasses(newCompiler(extraArgs = InlineWarningTest.argsNoWarn + " -Yopt-warnings:no-inline-mixed"))(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)})
+ compileClasses(newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:no-inline-mixed"))(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)})
assert(c == 2, c)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
index 6460158e71..ab1aef47cd 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
@@ -19,16 +19,9 @@ import AsmUtils._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object InlinerIllegalAccessTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:none")
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class InlinerIllegalAccessTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlinerIllegalAccessTest
-
- val compiler = InlinerIllegalAccessTest.compiler
+ val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
import compiler.genBCode.bTypes._
def addToRepo(cls: List[ClassNode]): Unit = for (c <- cls) byteCodeRepository.add(c, ByteCodeRepository.Classfile)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index e2a495fb2b..b7641b5ec7 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -22,35 +22,27 @@ import BackendReporting._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object InlinerTest extends ClearAfterClass.Clearable {
+@RunWith(classOf[JUnit4])
+class InlinerTest extends ClearAfterClass {
val args = "-Yopt:l:classpath -Yopt-warnings"
- var compiler = newCompiler(extraArgs = args)
- var inlineOnlyCompiler = newCompiler(extraArgs = "-Yopt:inline-project")
-
+ val compiler = cached("compiler", () => newCompiler(extraArgs = args))
+ val inlineOnlyCompiler = cached("inlineOnlyCompiler", () => newCompiler(extraArgs = "-Yopt:inline-project"))
+ import compiler.genBCode.bTypes
// allows inspecting the caches after a compilation run
def notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses,
- compiler.genBCode.bTypes.callGraph.callsites)
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses,
+ bTypes.callGraph.callsites)
notPerRun foreach compiler.perRunCaches.unrecordCache
- def clear(): Unit = { compiler = null; inlineOnlyCompiler = null }
-}
-
-@RunWith(classOf[JUnit4])
-class InlinerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlinerTest
-
- val compiler = InlinerTest.compiler
import compiler.genBCode.bTypes._
import compiler.genBCode.bTypes.backendUtils._
import inlinerHeuristics._
- val inlineOnlyCompiler = InlinerTest.inlineOnlyCompiler
def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
- InlinerTest.notPerRun.foreach(_.clear())
+ notPerRun.foreach(_.clear())
compileClasses(compiler)(scalaCode, javaCode, allowMessage)
// Use the class nodes stored in the byteCodeRepository. The ones returned by compileClasses are not the same,
// these are created new from the classfile byte array. They are completely separate instances which cannot
@@ -837,7 +829,7 @@ class InlinerTest extends ClearAfterClass {
var c = 0
- compileClasses(newCompiler(extraArgs = InlinerTest.args + " -Yopt-warnings:_"))(
+ compileClasses(newCompiler(extraArgs = args + " -Yopt-warnings:_"))(
scalaCode,
List((javaCode, "A.java")),
allowMessage = i => {c += 1; i.msg contains warn})
@@ -899,7 +891,7 @@ class InlinerTest extends ClearAfterClass {
| def t = System.arraycopy(null, 0, null, 0, 0)
|}
""".stripMargin
- val List(c) = compileClasses(newCompiler(extraArgs = InlinerTest.args + " -Yopt-inline-heuristics:everything"))(code)
+ val List(c) = compileClasses(newCompiler(extraArgs = args + " -Yopt-inline-heuristics:everything"))(code)
assertInvoke(getSingleMethod(c, "t"), "java/lang/System", "arraycopy")
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
index dd7fbd9977..003b2d4880 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
@@ -18,16 +18,9 @@ import ASMConverters._
import scala.tools.testing.ClearAfterClass
import scala.collection.JavaConverters._
-object MethodLevelOptsTest extends ClearAfterClass.Clearable {
- var methodOptCompiler = newCompiler(extraArgs = "-Yopt:l:method")
- def clear(): Unit = { methodOptCompiler = null }
-}
-
@RunWith(classOf[JUnit4])
class MethodLevelOptsTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = MethodLevelOptsTest
-
- val methodOptCompiler = MethodLevelOptsTest.methodOptCompiler
+ val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:method"))
def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
index 8dd23ec3ce..6cb3fd3bba 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
@@ -16,15 +16,9 @@ import ASMConverters._
import scala.collection.JavaConverters._
import scala.tools.testing.ClearAfterClass
-object ScalaInlineInfoTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:none")
- def clear(): Unit = { compiler = null }
-}
-
@RunWith(classOf[JUnit4])
class ScalaInlineInfoTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ScalaInlineInfoTest
- val compiler = ScalaInlineInfoTest.compiler
+ val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
def inlineInfo(c: ClassNode): InlineInfo = c.attrs.asScala.collect({ case a: InlineInfoAttribute => a.inlineInfo }).head
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
index 0021a1784d..46f06d1d39 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
@@ -15,27 +15,13 @@ import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass
-object UnreachableCodeTest extends ClearAfterClass.Clearable {
- // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks,
- // see comment in BCodeBodyBuilder
- var methodOptCompiler = newCompiler(extraArgs = "-Yopt:l:method")
- var dceCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
-
- def clear(): Unit = {
- methodOptCompiler = null
- dceCompiler = null
- noOptCompiler = null
- }
-}
-
@RunWith(classOf[JUnit4])
class UnreachableCodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = UnreachableCodeTest
-
- val methodOptCompiler = UnreachableCodeTest.methodOptCompiler
- val dceCompiler = UnreachableCodeTest.dceCompiler
- val noOptCompiler = UnreachableCodeTest.noOptCompiler
+ // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks,
+ // see comment in BCodeBodyBuilder
+ val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:method"))
+ val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code"))
+ val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
def assertEliminateDead(code: (Instruction, Boolean)*): Unit = {
val method = genMethod()(code.map(_._1): _*)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala
index 4f71df1822..77e73e64b9 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala
@@ -14,16 +14,9 @@ import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass
-object UnusedLocalVariablesTest extends ClearAfterClass.Clearable {
- var dceCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
- def clear(): Unit = { dceCompiler = null }
-}
-
@RunWith(classOf[JUnit4])
class UnusedLocalVariablesTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = UnusedLocalVariablesTest
-
- val dceCompiler = UnusedLocalVariablesTest.dceCompiler
+ val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code"))
@Test
def removeUnusedVar(): Unit = {
diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
index ac558e2e21..aa83520efb 100644
--- a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
+++ b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
@@ -16,18 +16,10 @@ import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass
-object PatmatBytecodeTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- var optCompiler = newCompiler(extraArgs = "-Yopt:l:project")
- def clear(): Unit = { compiler = null; optCompiler = null }
-}
-
@RunWith(classOf[JUnit4])
class PatmatBytecodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = PatmatBytecodeTest
-
- val compiler = PatmatBytecodeTest.compiler
- val optCompiler = PatmatBytecodeTest.optCompiler
+ val compiler = cached("compiler", () => newCompiler())
+ val optCompiler = cached("optCompiler", () => newCompiler(extraArgs = "-Yopt:l:project"))
@Test
def t6956(): Unit = {
diff --git a/test/junit/scala/tools/testing/ClearAfterClass.java b/test/junit/scala/tools/testing/ClearAfterClass.java
index 232d459c4e..95e170ec13 100644
--- a/test/junit/scala/tools/testing/ClearAfterClass.java
+++ b/test/junit/scala/tools/testing/ClearAfterClass.java
@@ -1,20 +1,53 @@
package scala.tools.testing;
-import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
- * Extend this class to use JUnit's @AfterClass. This annotation only works on static methods,
+ * Extend this class to use JUnit's @ClassRule. This annotation only works on static methods,
* which cannot be written in Scala.
*
* Example: {@link scala.tools.nsc.backend.jvm.opt.InlinerTest}
*/
public class ClearAfterClass {
- public static interface Clearable {
- void clear();
+ private static Map<Class<?>, Map<String, Object>> cache = new ConcurrentHashMap<>();
+
+ @ClassRule
+ public static TestRule clearClassCache() {
+ return (statement, desc) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ ConcurrentHashMap<String, Object> perClassCache = new ConcurrentHashMap<>();
+ cache.put(desc.getTestClass(), perClassCache);
+ try {
+ statement.evaluate();
+ } finally {
+ perClassCache.values().forEach(ClearAfterClass::closeIfClosable);
+ cache.remove(desc.getTestClass());
+ }
+ }
+ };
}
- public static Clearable stateToClear;
+ private static void closeIfClosable(Object o) {
+ if (o instanceof Closeable) {
+ try {
+ ((Closeable) o).close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ public <T> T cached(String key, scala.Function0<T> t) {
+ Map<String, Object> perClassCache = cache.get(getClass());
+ return (T) perClassCache.computeIfAbsent(key, s -> t.apply());
+ }
- @AfterClass
- public static void clearState() { stateToClear.clear(); }
}