diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-05-20 12:22:06 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-05-20 16:44:24 +0200 |
commit | ba510abcdcf176c06ba93c8e9dc6398015877f5e (patch) | |
tree | 191a71d282f6e23ef669d460f898431c8c5a5732 /test/junit/scala/tools/testing/BytecodeTesting.scala | |
parent | d9ce4dc1eeb351a52e98c6c0fa1551a5cc3b87f5 (diff) | |
download | scala-ba510abcdcf176c06ba93c8e9dc6398015877f5e.tar.gz scala-ba510abcdcf176c06ba93c8e9dc6398015877f5e.tar.bz2 scala-ba510abcdcf176c06ba93c8e9dc6398015877f5e.zip |
Clean up bytecode testing methods.
Diffstat (limited to 'test/junit/scala/tools/testing/BytecodeTesting.scala')
-rw-r--r-- | test/junit/scala/tools/testing/BytecodeTesting.scala | 85 |
1 files changed, 64 insertions, 21 deletions
diff --git a/test/junit/scala/tools/testing/BytecodeTesting.scala b/test/junit/scala/tools/testing/BytecodeTesting.scala index d6f8dbc219..b11ad27148 100644 --- a/test/junit/scala/tools/testing/BytecodeTesting.scala +++ b/test/junit/scala/tools/testing/BytecodeTesting.scala @@ -44,14 +44,23 @@ class Compiler(val global: Global) { } } - def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[(String, Array[Byte])] = { + def compileToBytes(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[(String, Array[Byte])] = { val run = newRun run.compileSources(makeSourceFile(scalaCode, "unitTestSource.scala") :: javaCode.map(p => makeSourceFile(p._1, p._2))) checkReport(allowMessage) getGeneratedClassfiles(global.settings.outputDirs.getSingleOutput.get) } - def compileTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[(String, Array[Byte])] = { + def compileClasses(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = { + readAsmClasses(compileToBytes(code, javaCode, allowMessage)) + } + + def compileClass(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): ClassNode = { + val List(c) = compileClasses(code, javaCode, allowMessage) + c + } + + def compileToBytesTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[(String, Array[Byte])] = { import global._ settings.stopBefore.value = "jvm" :: Nil val run = newRun @@ -68,22 +77,30 @@ class Compiler(val global: Global) { getGeneratedClassfiles(settings.outputDirs.getSingleOutput.get) } - def compileClasses(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = { - readAsmClasses(compile(code, javaCode, allowMessage)) + def compileClassesTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[ClassNode] = + readAsmClasses(compileToBytesTransformed(scalaCode, javaCode, beforeBackend)) + + def compileAsmMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[MethodNode] = { + val c = compileClass(s"class C { $code }", allowMessage = allowMessage) + getAsmMethods(c, _ != "<init>") } - def compileMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[MethodNode] = { - compileClasses(s"class C { $code }", allowMessage = allowMessage).head.methods.asScala.toList.filterNot(_.name == "<init>") + def compileAsmMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): MethodNode = { + val List(m) = compileAsmMethods(code, allowMessage) + m } - def singleMethodInstructions(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Instruction] = { + def compileMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Method] = + compileAsmMethods(code, allowMessage).map(convertMethod) + + def compileMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = { val List(m) = compileMethods(code, allowMessage = allowMessage) - instructionsFromMethod(m) + m } - def singleMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = { + def compileInstructions(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Instruction] = { val List(m) = compileMethods(code, allowMessage = allowMessage) - convertMethod(m) + m.instructions } } @@ -145,7 +162,7 @@ object BytecodeTesting { * The output directory is a physical directory, I have not figured out if / how it's possible to * add a VirtualDirectory to the classpath of a compiler. */ - def compileSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[(String, Array[Byte])] = { + def compileToBytesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[(String, Array[Byte])] = { val outDir = AbstractFile.getDirectory(TempDir.createTempDir()) val outDirPath = outDir.canonicalPath val argsWithOutDir = extraArgs + s" -d $outDirPath -cp $outDirPath" @@ -162,13 +179,11 @@ object BytecodeTesting { classfiles } - def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()) = { - readAsmClasses(compileSeparately(codes, extraArgs, allowMessage, afterEach)) + def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[ClassNode] = { + readAsmClasses(compileToBytesSeparately(codes, extraArgs, allowMessage, afterEach)) } - def readAsmClasses(classfiles: List[(String, Array[Byte])]) = { - classfiles.map(p => AsmUtils.readClass(p._2)).sortBy(_.name) - } + def readAsmClasses(classfiles: List[(String, Array[Byte])]) = classfiles.map(p => AsmUtils.readClass(p._2)).sortBy(_.name) def assertSameCode(method: Method, expected: List[Instruction]): Unit = assertSameCode(method.instructions.dropNonOp, expected) def assertSameCode(actual: List[Instruction], expected: List[Instruction]): Unit = { @@ -218,23 +233,51 @@ object BytecodeTesting { assert(indy.isEmpty, indy) } - def getSingleMethod(classNode: ClassNode, name: String): Method = - convertMethod(classNode.methods.asScala.toList.find(_.name == name).get) + def findClass(cs: List[ClassNode], name: String): ClassNode = { + val List(c) = cs.filter(_.name == name) + c + } + + def getAsmMethods(c: ClassNode, p: String => Boolean): List[MethodNode] = + c.methods.iterator.asScala.filter(m => p(m.name)).toList.sortBy(_.name) - def findAsmMethods(c: ClassNode, p: String => Boolean) = c.methods.iterator.asScala.filter(m => p(m.name)).toList.sortBy(_.name) - def findAsmMethod(c: ClassNode, name: String) = findAsmMethods(c, _ == name).head + def getAsmMethods(c: ClassNode, name: String): List[MethodNode] = + getAsmMethods(c, _ == name) + + def getAsmMethod(c: ClassNode, name: String): MethodNode = { + val List(m) = getAsmMethods(c, name) + m + } + + def getMethods(c: ClassNode, name: String): List[Method] = + getAsmMethods(c, name).map(convertMethod) + + def getMethod(c: ClassNode, name: String): Method = + convertMethod(getAsmMethod(c, name)) + + def getInstructions(c: ClassNode, name: String): List[Instruction] = + getMethod(c, name).instructions /** * Instructions that match `query` when textified. * If `query` starts with a `+`, the next instruction is returned. */ - def findInstr(method: MethodNode, query: String): List[AbstractInsnNode] = { + def findInstrs(method: MethodNode, query: String): List[AbstractInsnNode] = { val useNext = query(0) == '+' val instrPart = if (useNext) query.drop(1) else query val insns = method.instructions.iterator.asScala.filter(i => textify(i) contains instrPart).toList if (useNext) insns.map(_.getNext) else insns } + /** + * Instruction that matches `query` when textified. + * If `query` starts with a `+`, the next instruction is returned. + */ + def findInstr(method: MethodNode, query: String): AbstractInsnNode = { + val List(i) = findInstrs(method, query) + i + } + def assertHandlerLabelPostions(h: ExceptionHandler, instructions: List[Instruction], startIndex: Int, endIndex: Int, handlerIndex: Int): Unit = { val insVec = instructions.toVector assertTrue(h.start == insVec(startIndex) && h.end == insVec(endIndex) && h.handler == insVec(handlerIndex)) |