name.remal.org.objectweb.asm.tree.MethodNode.kt Maven / Gradle / Ivy
package name.remal
import org.objectweb.asm.Opcodes.ACC_ABSTRACT
import org.objectweb.asm.Opcodes.ACC_BRIDGE
import org.objectweb.asm.Opcodes.ACC_FINAL
import org.objectweb.asm.Opcodes.ACC_MANDATED
import org.objectweb.asm.Opcodes.ACC_NATIVE
import org.objectweb.asm.Opcodes.ACC_PRIVATE
import org.objectweb.asm.Opcodes.ACC_PROTECTED
import org.objectweb.asm.Opcodes.ACC_PUBLIC
import org.objectweb.asm.Opcodes.ACC_STATIC
import org.objectweb.asm.Opcodes.ACC_STRICT
import org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED
import org.objectweb.asm.Opcodes.ACC_SYNTHETIC
import org.objectweb.asm.Opcodes.ACC_VARARGS
import org.objectweb.asm.Type
import org.objectweb.asm.tree.AbstractInsnNode
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.JumpInsnNode
import org.objectweb.asm.tree.LabelNode
import org.objectweb.asm.tree.LineNumberNode
import org.objectweb.asm.tree.LookupSwitchInsnNode
import org.objectweb.asm.tree.MethodNode
import org.objectweb.asm.tree.TableSwitchInsnNode
import org.objectweb.asm.tree.TypeAnnotationNode
var MethodNode.isPublic: Boolean
get() = (access and ACC_PUBLIC) != 0
set(value) {
if (value) {
access = access or ACC_PUBLIC
access = access and ACC_PROTECTED.inv()
access = access and ACC_PRIVATE.inv()
} else {
access = access and ACC_PUBLIC.inv()
}
}
var MethodNode.isProtected: Boolean
get() = (access and ACC_PROTECTED) != 0
set(value) {
if (value) {
access = access and ACC_PUBLIC.inv()
access = access or ACC_PROTECTED
access = access and ACC_PRIVATE.inv()
} else {
access = access and ACC_PROTECTED.inv()
}
}
var MethodNode.isPrivate: Boolean
get() = (access and ACC_PRIVATE) != 0
set(value) {
if (value) {
access = access and ACC_PUBLIC.inv()
access = access and ACC_PROTECTED.inv()
access = access or ACC_PRIVATE
} else {
access = access and ACC_PRIVATE.inv()
}
}
var MethodNode.isPackagePrivate: Boolean
get() = !isPublic && !isProtected && !isPrivate
set(value) {
if (value) {
isPublic = false
isProtected = false
isPrivate = false
}
}
var MethodNode.isStatic: Boolean
get() = (access and ACC_STATIC) != 0
set(value) {
access = if (value) access or ACC_STATIC else access and ACC_STATIC.inv()
}
var MethodNode.isFinal: Boolean
get() = (access and ACC_FINAL) != 0
set(value) {
access = if (value) access or ACC_FINAL else access and ACC_FINAL.inv()
}
var MethodNode.isSynchronized: Boolean
get() = (access and ACC_SYNCHRONIZED) != 0
set(value) {
access = if (value) access or ACC_SYNCHRONIZED else access and ACC_SYNCHRONIZED.inv()
}
var MethodNode.isBridge: Boolean
get() = (access and ACC_BRIDGE) != 0
set(value) {
access = if (value) access or ACC_BRIDGE else access and ACC_BRIDGE.inv()
}
var MethodNode.isVarargs: Boolean
get() = (access and ACC_VARARGS) != 0
set(value) {
access = if (value) access or ACC_VARARGS else access and ACC_VARARGS.inv()
}
var MethodNode.isNative: Boolean
get() = (access and ACC_NATIVE) != 0
set(value) {
access = if (value) access or ACC_NATIVE else access and ACC_NATIVE.inv()
}
var MethodNode.isAbstract: Boolean
get() = (access and ACC_ABSTRACT) != 0
set(value) {
access = if (value) access or ACC_ABSTRACT else access and ACC_ABSTRACT.inv()
}
var MethodNode.isStrict: Boolean
get() = (access and ACC_STRICT) != 0
set(value) {
access = if (value) access or ACC_STRICT else access and ACC_STRICT.inv()
}
var MethodNode.isSynthetic: Boolean
get() = (access and ACC_SYNTHETIC) != 0
set(value) {
access = if (value) access or ACC_SYNTHETIC else access and ACC_SYNTHETIC.inv()
}
var MethodNode.isMandated: Boolean
get() = (access and ACC_MANDATED) != 0
set(value) {
access = if (value) access or ACC_MANDATED else access and ACC_MANDATED.inv()
}
val MethodNode.isStaticInitializer: Boolean get() = name == ""
val MethodNode.isConstructor: Boolean get() = name == ""
val MethodNode.hasParameters: Boolean get() = Type.getArgumentTypes(desc).isNotEmpty()
val MethodNode.allAnnotations: List
get() = sequenceOf(visibleAnnotations, invisibleAnnotations)
.filterNotNull()
.flatten()
.toList()
val MethodNode.allTypeAnnotations: List
get() = sequenceOf(visibleTypeAnnotations, invisibleTypeAnnotations)
.filterNotNull()
.flatten()
.toList()
val MethodNode.unusedLabelNodes: Set
get() {
val instructions = this.instructions ?: return emptySet()
return buildSet {
instructions.forEach { if (it is LabelNode) add(it) }
run {
var index = -1
while ((++index) < instructions.size()) {
val insn = instructions[index]
if (insn is LabelNode) {
remove(insn)
break
} else if (insn is LineNumberNode) {
continue
} else {
break
}
}
}
if (isNotEmpty()) {
tryCatchBlocks?.forEach { remove(it.start); remove(it.end); remove(it.handler) }
localVariables?.forEach { remove(it.start); remove(it.end) }
visibleLocalVariableAnnotations?.forEach { it.start?.let(this::removeAll); it.end?.let(this::removeAll) }
invisibleLocalVariableAnnotations?.forEach { it.start?.let(this::removeAll); it.end?.let(this::removeAll) }
instructions.forEach {
if (it is JumpInsnNode) remove(it.label)
if (it is LookupSwitchInsnNode) {
remove(it.dflt)
it.labels?.let(this::removeAll)
}
if (it is TableSwitchInsnNode) {
remove(it.dflt)
it.labels?.let(this::removeAll)
}
}
}
}
}
fun MethodNode.getAllParameterAnnotations(paramIndex: Int): List {
return sequenceOf(visibleParameterAnnotations, invisibleParameterAnnotations)
.flatMap { it?.getOrNull(paramIndex)?.asSequence() ?: emptySequence() }
.filterNotNull()
.toList()
}
data class InstructionNodeContext(
val node: T,
val previousNode: AbstractInsnNode?,
val nextNode: AbstractInsnNode?
)
data class InstructionNodeFilter(
val nodeType: Class,
val predicate: ((context: InstructionNodeContext) -> Boolean)? = null
)
fun Class.toInstructionNodeFilter() = InstructionNodeFilter(this)