Skip to content

Commit 645b50f

Browse files
committed
Add more cases
1 parent a601ba5 commit 645b50f

1 file changed

Lines changed: 86 additions & 3 deletions

File tree

src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/BytecodeRemappingTest.kt

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import com.github.jengelman.gradle.plugins.shadow.util.noOpDelegate
1010
import java.io.File
1111
import java.lang.classfile.Attributes
1212
import java.lang.classfile.ClassFile
13+
import java.lang.classfile.instruction.InvokeInstruction
14+
import java.lang.classfile.instruction.TypeCheckInstruction
1315
import java.nio.file.Path
1416
import kotlin.io.path.copyTo
1517
import kotlin.io.path.createParentDirectories
@@ -150,6 +152,76 @@ class BytecodeRemappingTest {
150152
assertThat(methodDescriptors).contains("(BL$relocatedFixtureBase;)L$relocatedFixtureBase;")
151153
}
152154

155+
@Test
156+
fun stringConstantIsRelocated() {
157+
val result = fixtureSubjectDetails.remapClass(relocators)
158+
159+
val classModel = ClassFile.of().parse(result)
160+
// Find the constant string in the bytecode.
161+
val stringConstants =
162+
classModel.constantPool().mapNotNull { entry ->
163+
if (entry is java.lang.classfile.constantpool.StringEntry) entry.stringValue() else null
164+
}
165+
assertThat(stringConstants).contains("com.example.relocated.BytecodeRemappingTest\$FixtureBase")
166+
}
167+
168+
@Test
169+
fun interfaceIsRelocated() {
170+
val result = fixtureSubjectDetails.remapClass(relocators)
171+
172+
val classModel = ClassFile.of().parse(result)
173+
val interfaces = classModel.interfaces().map { it.asInternalName() }
174+
assertThat(interfaces)
175+
.contains($$"com/example/relocated/BytecodeRemappingTest$FixtureInterface")
176+
}
177+
178+
@Test
179+
fun signatureIsRelocated() {
180+
val result = fixtureSubjectDetails.remapClass(relocators)
181+
182+
val classModel = ClassFile.of().parse(result)
183+
val method = classModel.methods().first { it.methodName().stringValue() == "methodWithGeneric" }
184+
val signatureAttr = method.findAttribute(Attributes.signature())
185+
assertThat(signatureAttr.isPresent).isTrue()
186+
val sig = signatureAttr.get().signature().stringValue()
187+
assertThat(sig).contains("L$relocatedFixtureBase;")
188+
}
189+
190+
@Test
191+
fun localVariableIsRelocated() {
192+
val result = fixtureSubjectDetails.remapClass(relocators)
193+
194+
val classModel = ClassFile.of().parse(result)
195+
val method = classModel.methods().first { it.methodName().stringValue() == "method" }
196+
val code = method.code().get()
197+
val lvt = code.findAttribute(Attributes.localVariableTable())
198+
assertThat(lvt.isPresent).isTrue()
199+
val descriptors = lvt.get().localVariables().map { it.type().stringValue() }
200+
assertThat(descriptors).contains("L$relocatedFixtureBase;")
201+
}
202+
203+
@Test
204+
fun instructionIsRelocated() {
205+
val result = fixtureSubjectDetails.remapClass(relocators)
206+
207+
val classModel = ClassFile.of().parse(result)
208+
val method =
209+
classModel.methods().first { it.methodName().stringValue() == "methodWithCheckCast" }
210+
val code = method.code().get()
211+
212+
val hasRelocatedCheckCast =
213+
code.elementStream().anyMatch { element ->
214+
element is TypeCheckInstruction && element.type().asInternalName() == relocatedFixtureBase
215+
}
216+
assertThat(hasRelocatedCheckCast).isTrue()
217+
218+
val hasRelocatedInvoke =
219+
code.elementStream().anyMatch { element ->
220+
element is InvokeInstruction && element.owner().asInternalName() == relocatedFixtureBase
221+
}
222+
assertThat(hasRelocatedInvoke).isTrue()
223+
}
224+
153225
private fun KClass<*>.toFileCopyDetails() =
154226
object : FileCopyDetails by noOpDelegate() {
155227
private val _path = java.name.replace('.', '/') + ".class"
@@ -172,21 +244,32 @@ class BytecodeRemappingTest {
172244

173245
@Retention(AnnotationRetention.RUNTIME)
174246
@Target(AnnotationTarget.CLASS)
175-
private annotation class FixtureAnnotation
247+
annotation class FixtureAnnotation
176248

177-
private open class FixtureBase
249+
interface FixtureInterface
250+
251+
open class FixtureBase
178252

179253
@Suppress("unused") // Used by parsing bytecode.
180254
@FixtureAnnotation
181-
private class FixtureSubject : FixtureBase() {
255+
class FixtureSubject : FixtureBase(), FixtureInterface {
182256
val field: FixtureBase = FixtureBase()
183257
val arrayField: Array<FixtureBase> = emptyArray()
184258
val array2dField: Array<Array<FixtureBase>> = emptyArray()
259+
val stringConstant: String =
260+
$$"com.github.jengelman.gradle.plugins.shadow.internal.BytecodeRemappingTest$FixtureBase"
185261

186262
fun method(arg: FixtureBase): FixtureBase = arg
187263

188264
fun methodMultiArgs(a: FixtureBase, b: FixtureBase): FixtureBase = a
189265

190266
fun methodWithPrimitivePlusClass(b: Byte, arg: FixtureBase): FixtureBase = arg
267+
268+
fun methodWithCheckCast(arg: Any): FixtureBase {
269+
(arg as FixtureBase).toString()
270+
return arg
271+
}
272+
273+
fun methodWithGeneric(list: List<FixtureBase>): FixtureBase = list[0]
191274
}
192275
}

0 commit comments

Comments
 (0)