Я нашел решение, создав класс, расширяющий CheckClassAdapter, и добавив метод с параметром ClassNode. Прочитав исходный код CheckClassAdapter, я обнаружил, что ClassReader все равно посещает узел класса.
public static void verify(
final ClassReader classReader,
final ClassLoader loader,
final boolean printResults,
final PrintWriter printWriter) {
ClassNode classNode = new ClassNode();
classReader.accept(
new CheckClassAdapter(/*latest*/ Opcodes.ASM10_EXPERIMENTAL, classNode, false) {},
ClassReader.SKIP_DEBUG);
Как видите, ASM мог бы предоставить методу только ввод данных в ClassNode, но по какой-то причине этого не сделал.
Вот код класса, который расширяет CheckClassAdapter, добавляя эту функциональность:
public class CheckClassAdapterClassNode extends CheckClassAdapter {
public CheckClassAdapterClassNode(ClassVisitor classVisitor) {
super(classVisitor);
}
/**
* Checks the given class.
*
* @param classNode the class to be checked.
* @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
* {@literal null}.
* @param printResults whether to print the results of the bytecode verification.
* @param printWriter where the results (or the stack trace in case of error) must be printed.
*/
public static void verify(
final ClassNode classNode,
final ClassLoader loader,
final boolean printResults,
final PrintWriter printWriter) {
Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
List<MethodNode> methods = classNode.methods;
List<Type> interfaces = new ArrayList<>();
for (String interfaceName : classNode.interfaces) {
interfaces.add(Type.getObjectType(interfaceName));
}
for (MethodNode method : methods) {
SimpleVerifier verifier =
new SimpleVerifier(
Type.getObjectType(classNode.name),
syperType,
interfaces,
(classNode.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> analyzer = new Analyzer<>(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}
try {
analyzer.analyze(classNode.name, method);
} catch (AnalyzerException e) {
e.printStackTrace(printWriter);
}
if (printResults) {
printAnalyzerResult(method, analyzer, printWriter);
}
}
printWriter.flush();
}
static void printAnalyzerResult(
final MethodNode method, final Analyzer<BasicValue> analyzer, final PrintWriter printWriter) {
Textifier textifier = new Textifier();
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(textifier);
printWriter.println(method.name + method.desc);
for (int i = 0; i < method.instructions.size(); ++i) {
if (method.instructions.get(i) == null) continue;
method.instructions.get(i).accept(traceMethodVisitor);
StringBuilder stringBuilder = new StringBuilder();
Frame<BasicValue> frame = analyzer.getFrames()[i];
if (frame == null) {
stringBuilder.append('?');
} else {
for (int j = 0; j < frame.getLocals(); ++j) {
stringBuilder.append(getUnqualifiedName(frame.getLocal(j).toString())).append(' ');
}
stringBuilder.append(" : ");
for (int j = 0; j < frame.getStackSize(); ++j) {
stringBuilder.append(getUnqualifiedName(frame.getStack(j).toString())).append(' ');
}
}
while (stringBuilder.length() < method.maxStack + method.maxLocals + 1) {
stringBuilder.append(' ');
}
printWriter.print(Integer.toString(i + 100000).substring(1));
printWriter.print(
" " + stringBuilder + " : " + textifier.text.get(textifier.text.size() - 1));
}
for (TryCatchBlockNode tryCatchBlock : method.tryCatchBlocks) {
tryCatchBlock.accept(traceMethodVisitor);
printWriter.print(" " + textifier.text.get(textifier.text.size() - 1));
}
printWriter.println();
}
private static String getUnqualifiedName(final String name) {
int lastSlashIndex = name.lastIndexOf('/');
if (lastSlashIndex == -1) {
return name;
} else {
int endIndex = name.length();
if (name.charAt(endIndex - 1) == ';') {
endIndex--;
}
return name.substring(lastSlashIndex + 1, endIndex);
}
}
}
Скорее всего, я создам задачу в репозитории ASM и добавлю запрос на извлечение, чтобы добавить это.
person
Nirvana
schedule
16.01.2021
classNode
? - person kriegaex   schedule 16.01.2021