Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

**Added**
- Add `--summary-only` flag.
- Support diffing bytecode versions for classes.

**Fixed**
- Significantly improve `.jar` diff performance.
Expand Down
3 changes: 2 additions & 1 deletion formats/api/formats.api
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,9 @@ public abstract interface class com/jakewharton/diffuse/format/BinaryFormat {

public final class com/jakewharton/diffuse/format/Class {
public static final field Companion Lcom/jakewharton/diffuse/format/Class$Companion;
public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;ILjava/util/List;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getBytecodeVersion ()I
public final fun getDeclaredMembers ()Ljava/util/List;
public final fun getDescriptor-BeHrSHk ()Ljava/lang/String;
public final fun getReferencedMembers ()Ljava/util/List;
Expand Down
25 changes: 23 additions & 2 deletions formats/src/main/kotlin/com/jakewharton/diffuse/format/Class.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ import org.objectweb.asm.Opcodes
class Class
private constructor(
val descriptor: TypeDescriptor,
val bytecodeVersion: Int,
val declaredMembers: List<Member>,
val referencedMembers: List<Member>,
) {
override fun toString() = descriptor.toString()

override fun hashCode() = Objects.hash(descriptor, declaredMembers, referencedMembers)
override fun hashCode() =
Objects.hash(descriptor, bytecodeVersion, declaredMembers, referencedMembers)

override fun equals(other: Any?) =
other is Class &&
descriptor == other.descriptor &&
bytecodeVersion == other.bytecodeVersion &&
declaredMembers == other.declaredMembers &&
referencedMembers == other.referencedMembers

Expand All @@ -36,15 +39,33 @@ private constructor(
val declaredVisitor = DeclaredMembersVisitor(type, referencedVisitor)
reader.accept(declaredVisitor, 0)

return Class(type, declaredVisitor.members.sorted(), referencedVisitor.members.sorted())
return Class(
type,
declaredVisitor.version,
declaredVisitor.members.sorted(),
referencedVisitor.members.sorted(),
)
}
}
}

private class DeclaredMembersVisitor(val type: TypeDescriptor, val methodVisitor: MethodVisitor) :
ClassVisitor(Opcodes.ASM9) {
var version: Int = 0
val members = mutableListOf<Member>()

override fun visit(
version: Int,
access: Int,
name: String,
signature: String?,
superName: String?,
interfaces: Array<out String>?,
) {
this.version = version
super.visit(version, access, name, signature, superName, interfaces)
}

override fun visitMethod(
access: Int,
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ internal class JarsDiff(
val newMapping: ApiMapping,
) {
val classes = componentDiff(oldJars, newJars) { it.classes.map(Class::descriptor) }
val bytecodeVersions =
componentDiff(oldJars, newJars) { jar ->
jar.classes.map { "${it.descriptor}: ${it.bytecodeVersion}" }
}
val methods = componentDiff(oldJars, newJars) { it.members.filterIsInstance<Method>() }
val declaredMethods =
componentDiff(oldJars, newJars) { it.declaredMembers.filterIsInstance<Method>() }
Expand All @@ -29,7 +33,7 @@ internal class JarsDiff(
val referencedFields =
componentDiff(oldJars, newJars) { it.referencedMembers.filterIsInstance<Field>() }

val changed = methods.changed || fields.changed
val changed = bytecodeVersions.changed || methods.changed || fields.changed
}

internal fun JarsDiff.toSummaryTable(name: String) =
Expand Down Expand Up @@ -72,6 +76,7 @@ internal fun JarsDiff.toSummaryTable(name: String) =
internal fun JarsDiff.toDetailReport() = buildString {
// TODO appendComponentDiff("STRINGS", strings)?
appendComponentDiff("CLASSES", classes)
appendComponentDiff("BYTECODE VERSIONS", bytecodeVersions)
appendComponentDiff("METHODS", methods)
appendComponentDiff("FIELDS", fields)
}