Skip to content

Commit

Permalink
Moved most of the code into sbtassembly.scalasig package.
Browse files Browse the repository at this point in the history
Added test for EntryTable
  • Loading branch information
jeroentervoorde committed Apr 16, 2020
1 parent de199d3 commit e843a4f
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 14 deletions.
3 changes: 2 additions & 1 deletion src/main/scala/org/pantsbuild/jarjar/ScalaSigProcessor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.pantsbuild.jarjar

import org.objectweb.asm.{ClassReader, ClassWriter}
import org.pantsbuild.jarjar.util.{EntryStruct, JarProcessor}
import sbtassembly.scalasig.ScalaSigClassVisitor

class ScalaSigProcessor(renamer: String => Option[String]) extends JarProcessor {
override def process(struct: EntryStruct): Boolean = {
Expand All @@ -11,7 +12,7 @@ class ScalaSigProcessor(renamer: String => Option[String]) extends JarProcessor
val classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS)
val reader = new ClassReader(struct.data)

reader.accept(new ScalaSigClassVisitor(struct.name, classWriter, renamer), ClassReader.EXPAND_FRAMES)
reader.accept(new ScalaSigClassVisitor(classWriter, renamer), ClassReader.EXPAND_FRAMES)
struct.data = classWriter.toByteArray
true
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/sbtassembly/Shader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package sbtassembly

import java.io.File

import org.pantsbuild.jarjar._
import org.pantsbuild.jarjar.{JJProcessor, _}
import org.pantsbuild.jarjar.util.EntryStruct
import sbt._

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.pantsbuild.jarjar
package sbtassembly.scalasig

// Utility class to read the content of a single table entry
class ByteArrayReader(bytes: Array[Byte]) extends Nat.Reader {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.pantsbuild.jarjar
package sbtassembly.scalasig

import java.io.ByteArrayOutputStream

Expand All @@ -19,6 +19,12 @@ class EntryTable(majorVersion: Int, minorVersion: Int, entries: mutable.Buffer[T
}:_*
)

/**
* Return the current table entries as an immutable seq.
* @return table entries
*/
def toSeq: Seq[TaggedEntry] = entries.toVector

/**
* Rename term and type entries in this table according to the renamer function.
* A name or type is referred to by a Ref entry. The existing ref entries are reused to references to them will remain intact.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.pantsbuild.jarjar
package sbtassembly.scalasig

/**
* Utility methods for reading and writing nat encoded numbers.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package org.pantsbuild.jarjar
package sbtassembly.scalasig

import java.io.ByteArrayOutputStream

import org.objectweb.asm.{AnnotationVisitor, ClassVisitor, Opcodes}

import scala.reflect.internal.pickling.ByteCodecs

class ScalaSigClassVisitor(fileName: String, cv: ClassVisitor, renamer: String => Option[String]) extends ClassVisitor(Opcodes.ASM7, cv) {
class ScalaSigClassVisitor(cv: ClassVisitor, renamer: String => Option[String]) extends ClassVisitor(Opcodes.ASM7, cv) {

override def visitAnnotation(descriptor: String, visible: Boolean): AnnotationVisitor = {
if (descriptor == "Lscala/reflect/ScalaSignature;" || descriptor == "Lscala/reflect/ScalaLongSignature;") {
new ScalaSigAnnotationVisitor(fileName, descriptor, visible, cv, renamer)
new ScalaSigAnnotationVisitor(visible, cv, renamer)
} else {
super.visitAnnotation(descriptor, visible)
}
}
}

class ScalaSigAnnotationVisitor(
fileName: String,
descriptor: String,
visible: Boolean,
cv: ClassVisitor,
renamer: String => Option[String]
Expand All @@ -44,7 +44,7 @@ class ScalaSigAnnotationVisitor(
val table = EntryTable.fromBytes(encoded.slice(0, len))
table.renameEntries(renamer)

val chars = ubytesToCharArray(mapToNextModSevenBits(scala.reflect.internal.pickling.ByteCodecs.encode8to7(table.toBytes)))
val chars = ubytesToCharArray(mapToNextModSevenBits(ByteCodecs.encode8to7(table.toBytes)))
val utf8EncodedLength = chars.foldLeft(0) { (count, next) => if (next == 0) count + 2 else count + 1}

if (utf8EncodedLength > MaxStringSizeInBytes) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.pantsbuild.jarjar
package sbtassembly.scalasig

import java.io.ByteArrayOutputStream

Expand All @@ -12,8 +12,8 @@ trait TaggedEntry {
/**
* Unparsed entry
*/
case class RawEntry(tag: Int, bytes: Array[Byte]) extends TaggedEntry {
override def toBytes: Array[Byte] = bytes
case class RawEntry(tag: Int, bytes: Seq[Byte]) extends TaggedEntry {
override def toBytes: Array[Byte] = bytes.toArray
}

/**
Expand Down
82 changes: 82 additions & 0 deletions src/test/scala/sbtassembly/scalasig/EntryTableSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package sbtassembly.scalasig

import org.scalatest.OptionValues
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec

import scala.reflect.ScalaSignature
import scala.reflect.internal.pickling.ByteCodecs

class Test

abstract class Test2 {
val test: Test
}

class EntryTableSpec extends AnyWordSpec with Matchers with OptionValues {

"entry table" should {
"parse annotation bytes" in {
val encoded = classOf[Test2].getAnnotation(classOf[ScalaSignature])
val bytes = encoded.bytes().getBytes("UTF-8")

val len = ByteCodecs.decode(bytes)
val table = EntryTable.fromBytes(bytes.slice(0, len))

resolveName(table, "Test") shouldBe Some("sbtassembly.scalasig.Test")
}

"rename package" in {
val encoded = classOf[Test2].getAnnotation(classOf[ScalaSignature])
val bytes = encoded.bytes().getBytes("UTF-8")

val len = ByteCodecs.decode(bytes)
val table = EntryTable.fromBytes(bytes.slice(0, len))

table.renameEntries {
case pckg if pckg.startsWith("sbtassembly.scalasig") => Some("shaded.sbtassembly.scalasig")
case _ => None
}

resolveName(table, "Test") shouldBe Some("shaded.sbtassembly.scalasig.Test")

table.renameEntries {
case pckg if pckg.startsWith("shaded.sbtassembly.scalasig") => Some("sbtassembly.scalasig.shadedtoo")
case _ => None
}

resolveName(table, "Test") shouldBe Some("sbtassembly.scalasig.shadedtoo.Test")
}

"return same serialized bytes" in {
val encoded = classOf[Test2].getAnnotation(classOf[ScalaSignature])
val bytes = encoded.bytes().getBytes("UTF-8")

val len = ByteCodecs.decode(bytes)
val decoded = bytes.slice(0, len)
val table = EntryTable.fromBytes(decoded)

val serialized = table.toBytes

serialized.length shouldBe decoded.length +- 1 // Scala compiler (sometimes) adds an extra zero. We don't.
EntryTable.fromBytes(serialized).toSeq shouldBe table.toSeq
}
}

private def resolveName(entryTable: EntryTable, name: String): Option[String] = {
val entries = entryTable.toSeq.zipWithIndex
def findNameIndex: Option[Int] = entries.collectFirst {
case (e: NameEntry, index) if e.name == name => index
}

def findRefEntry(nameIndex: Int): Option[RefEntry] = entries.collectFirst {
case (e: RefEntry, _) if e.nameRef == nameIndex => e
}

for {
index <- findNameIndex
ref <- findRefEntry(index)
resolved <- entryTable.resolveRef(ref)
} yield resolved
}
}

0 comments on commit e843a4f

Please sign in to comment.