mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[ByteCodeViewer] Improve and simplify testing
Make all tests have two variants: with and without debug info. Also, move bytecode fixtures out of BytecodeLineMappingTest because it adds too much noise there. Move it to the newly created testData directory instead. GitOrigin-RevId: 1b44b118d470ace068774d9714eafc2704119e86
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ea6d36e854
commit
ca5906a4f7
@@ -2,22 +2,25 @@
|
||||
package com.intellij.byteCodeViewer
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* This method removes the following debugging information from `bytecode`:
|
||||
* This method removes the following debug information from `bytecode`:
|
||||
* - `LINENUMBER`
|
||||
* - `LOCALVARIABLE`
|
||||
*
|
||||
* ### Why is this needed?
|
||||
*
|
||||
* Ideally, we would use `ClassReader#SKIP_DEBUG` flag, but it has problematic behavior when it comes to labels.
|
||||
* Ideally, to get bytecode without debug information, we would use [ClassReader] from the ASM library, and parse bytecode with the [ClassReader.SKIP_DEBUG] flag.
|
||||
* Unfortunately, this flag doesn't achieve what we want because it removes labels from the bytecode.
|
||||
*
|
||||
* When parsing bytecode with ASM's `ClassReader`, we want to set `ClassReader#SKIP_DEBUG`, because it's actually not part of bytecode.
|
||||
* Unfortunately, `ClassReader#SKIP_DEBUG` also removes labels from the bytecode in most cases.
|
||||
* This is bad because labels are often targets of conditional jumps.
|
||||
* Also, we do want to display labels.
|
||||
* They're useful.
|
||||
*
|
||||
* @param bytecodeWithDebugInfo - bytecode returned by ASM [ClassReader] and [Textifier] with [ClassReader.SKIP_FRAMES] flag.
|
||||
* @see BytecodeToolWindowPanel.deserializeBytecode
|
||||
*/
|
||||
internal fun removeDebugInfo(bytecodeWithDebugInfo: String): String = bytecodeWithDebugInfo.lines()
|
||||
.filter { line -> !isDebugLine(line.trim()) }
|
||||
@@ -27,14 +30,14 @@ internal fun removeDebugInfo(bytecodeWithDebugInfo: String): String = bytecodeWi
|
||||
/**
|
||||
* Maps the line numbers from the provided bytecode to the source code line numbers within a specified range.
|
||||
*
|
||||
* @param bytecodeWithDebugInfo The Java bytecode in ASM format, with debugging information included (see [ClassReader.SKIP_DEBUG])
|
||||
* @param bytecodeWithDebugInfo The Java bytecode in ASM format, with debug information included (see [ClassReader.SKIP_DEBUG])
|
||||
* @param sourceStartLine The starting line number in the source code to map from.
|
||||
* @param sourceEndLine The ending line number in the source code to map to.
|
||||
* @return A pair where the first element is the start line number in the bytecode, and the second element is the end line number in the bytecode. Returns (0, 0) if no valid mapping
|
||||
* is found.
|
||||
*/
|
||||
internal fun mapLines(bytecodeWithDebugInfo: String, sourceStartLine: Int, sourceEndLine: Int, showDebugInfo: Boolean = true): IntRange {
|
||||
var sourceStartLine = sourceStartLine // + 1 // editor selection is 0-indexed
|
||||
var sourceStartLine = sourceStartLine // editor selection is 0-indexed
|
||||
var currentBytecodeLine = 0
|
||||
var bytecodeStartLine = -1
|
||||
var bytecodeEndLine = -1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
package simple1;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello world");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// class version 67.0 (67)
|
||||
// access flags 0x21
|
||||
public class simple1/Main {
|
||||
|
||||
// compiled from: Main.java
|
||||
|
||||
// access flags 0x1
|
||||
public <init>()V
|
||||
L0
|
||||
ALOAD 0
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
RETURN
|
||||
L1
|
||||
MAXSTACK = 1
|
||||
MAXLOCALS = 1
|
||||
|
||||
// access flags 0x9
|
||||
public static main([Ljava/lang/String;)V
|
||||
L0
|
||||
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
LDC "hello world"
|
||||
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||||
L1
|
||||
RETURN
|
||||
L2
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 1
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// class version 67.0 (67)
|
||||
// access flags 0x21
|
||||
public class simple1/Main {
|
||||
|
||||
// compiled from: Main.java
|
||||
|
||||
// access flags 0x1
|
||||
public <init>()V
|
||||
L0
|
||||
LINENUMBER 3 L0
|
||||
ALOAD 0
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
RETURN
|
||||
L1
|
||||
LOCALVARIABLE this Lsimple1/Main; L0 L1 0
|
||||
MAXSTACK = 1
|
||||
MAXLOCALS = 1
|
||||
|
||||
// access flags 0x9
|
||||
public static main([Ljava/lang/String;)V
|
||||
L0
|
||||
LINENUMBER 5 L0
|
||||
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
LDC "hello world"
|
||||
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||||
L1
|
||||
LINENUMBER 6 L1
|
||||
RETURN
|
||||
L2
|
||||
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 1
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package simple2;
|
||||
|
||||
public class Main {
|
||||
public static String name = "Charlie";
|
||||
public static Object obj = new Object();
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello world");
|
||||
int argCount = args.length;
|
||||
System.out.println("there are " + argCount + " args");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// class version 67.0 (67)
|
||||
// access flags 0x21
|
||||
public class simple2/Main {
|
||||
|
||||
// compiled from: Main.java
|
||||
// access flags 0x19
|
||||
public final static INNERCLASS java/lang/invoke/MethodHandles$Lookup java/lang/invoke/MethodHandles Lookup
|
||||
|
||||
// access flags 0x9
|
||||
public static Ljava/lang/String; name
|
||||
|
||||
// access flags 0x9
|
||||
public static Ljava/lang/Object; obj
|
||||
|
||||
// access flags 0x1
|
||||
public <init>()V
|
||||
L0
|
||||
ALOAD 0
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
RETURN
|
||||
L1
|
||||
MAXSTACK = 1
|
||||
MAXLOCALS = 1
|
||||
|
||||
// access flags 0x9
|
||||
public static main([Ljava/lang/String;)V
|
||||
L0
|
||||
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
LDC "hello world"
|
||||
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||||
L1
|
||||
ALOAD 0
|
||||
ARRAYLENGTH
|
||||
ISTORE 1
|
||||
L2
|
||||
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
ILOAD 1
|
||||
INVOKEDYNAMIC makeConcatWithConstants(I)Ljava/lang/String; [
|
||||
// handle kind 0x6 : INVOKESTATIC
|
||||
java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
|
||||
// arguments:
|
||||
"there are \u0001 args"
|
||||
]
|
||||
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||||
L3
|
||||
RETURN
|
||||
L4
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x8
|
||||
static <clinit>()V
|
||||
L0
|
||||
LDC "Charlie"
|
||||
PUTSTATIC simple2/Main.name : Ljava/lang/String;
|
||||
L1
|
||||
NEW java/lang/Object
|
||||
DUP
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
PUTSTATIC simple2/Main.obj : Ljava/lang/Object;
|
||||
RETURN
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 0
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// class version 67.0 (67)
|
||||
// access flags 0x21
|
||||
public class simple2/Main {
|
||||
|
||||
// compiled from: Main.java
|
||||
// access flags 0x19
|
||||
public final static INNERCLASS java/lang/invoke/MethodHandles$Lookup java/lang/invoke/MethodHandles Lookup
|
||||
|
||||
// access flags 0x9
|
||||
public static Ljava/lang/String; name
|
||||
|
||||
// access flags 0x9
|
||||
public static Ljava/lang/Object; obj
|
||||
|
||||
// access flags 0x1
|
||||
public <init>()V
|
||||
L0
|
||||
LINENUMBER 3 L0
|
||||
ALOAD 0
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
RETURN
|
||||
L1
|
||||
LOCALVARIABLE this Lsimple2/Main; L0 L1 0
|
||||
MAXSTACK = 1
|
||||
MAXLOCALS = 1
|
||||
|
||||
// access flags 0x9
|
||||
public static main([Ljava/lang/String;)V
|
||||
L0
|
||||
LINENUMBER 8 L0
|
||||
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
LDC "hello world"
|
||||
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||||
L1
|
||||
LINENUMBER 9 L1
|
||||
ALOAD 0
|
||||
ARRAYLENGTH
|
||||
ISTORE 1
|
||||
L2
|
||||
LINENUMBER 10 L2
|
||||
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
ILOAD 1
|
||||
INVOKEDYNAMIC makeConcatWithConstants(I)Ljava/lang/String; [
|
||||
// handle kind 0x6 : INVOKESTATIC
|
||||
java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
|
||||
// arguments:
|
||||
"there are \u0001 args"
|
||||
]
|
||||
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||||
L3
|
||||
LINENUMBER 11 L3
|
||||
RETURN
|
||||
L4
|
||||
LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
|
||||
LOCALVARIABLE argCount I L2 L4 1
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x8
|
||||
static <clinit>()V
|
||||
L0
|
||||
LINENUMBER 4 L0
|
||||
LDC "Charlie"
|
||||
PUTSTATIC simple2/Main.name : Ljava/lang/String;
|
||||
L1
|
||||
LINENUMBER 5 L1
|
||||
NEW java/lang/Object
|
||||
DUP
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
PUTSTATIC simple2/Main.obj : Ljava/lang/Object;
|
||||
RETURN
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 0
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package simple3;
|
||||
|
||||
public class Main {
|
||||
String method1(boolean value) {
|
||||
if (value == true) {
|
||||
return "baz";
|
||||
}
|
||||
return "baz";
|
||||
}
|
||||
|
||||
String method2(boolean value) {
|
||||
if (value == Boolean.TRUE) {
|
||||
return "bar";
|
||||
}
|
||||
return "baz";
|
||||
}
|
||||
|
||||
String method3(boolean value) {
|
||||
if (value == Boolean.FALSE) {
|
||||
return "bar";
|
||||
}
|
||||
return "baz";
|
||||
}
|
||||
|
||||
String method(boolean value) {
|
||||
if (Boolean.TRUE.equals(returnsBool(value))) {
|
||||
return "foo";
|
||||
}
|
||||
return "baz";
|
||||
}
|
||||
|
||||
public Boolean returnsBool(boolean value) {
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
}
|
||||
103
plugins/ByteCodeViewer/testData/lineMapping/simple3/bytecode.txt
Normal file
103
plugins/ByteCodeViewer/testData/lineMapping/simple3/bytecode.txt
Normal file
@@ -0,0 +1,103 @@
|
||||
// class version 67.0 (67)
|
||||
// access flags 0x21
|
||||
public class simple3/Main {
|
||||
|
||||
// compiled from: Main.java
|
||||
|
||||
// access flags 0x1
|
||||
public <init>()V
|
||||
L0
|
||||
ALOAD 0
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
RETURN
|
||||
L1
|
||||
MAXSTACK = 1
|
||||
MAXLOCALS = 1
|
||||
|
||||
// access flags 0x0
|
||||
method1(Z)Ljava/lang/String;
|
||||
L0
|
||||
ILOAD 1
|
||||
ICONST_1
|
||||
IF_ICMPNE L1
|
||||
L2
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x0
|
||||
method2(Z)Ljava/lang/String;
|
||||
L0
|
||||
ILOAD 1
|
||||
GETSTATIC java/lang/Boolean.TRUE : Ljava/lang/Boolean;
|
||||
INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z
|
||||
IF_ICMPNE L1
|
||||
L2
|
||||
LDC "bar"
|
||||
ARETURN
|
||||
L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x0
|
||||
method3(Z)Ljava/lang/String;
|
||||
L0
|
||||
ILOAD 1
|
||||
GETSTATIC java/lang/Boolean.FALSE : Ljava/lang/Boolean;
|
||||
INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z
|
||||
IF_ICMPNE L1
|
||||
L2
|
||||
LDC "bar"
|
||||
ARETURN
|
||||
L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x0
|
||||
method(Z)Ljava/lang/String;
|
||||
L0
|
||||
GETSTATIC java/lang/Boolean.TRUE : Ljava/lang/Boolean;
|
||||
ALOAD 0
|
||||
ILOAD 1
|
||||
INVOKEVIRTUAL simple3/Main.returnsBool (Z)Ljava/lang/Boolean;
|
||||
INVOKEVIRTUAL java/lang/Boolean.equals (Ljava/lang/Object;)Z
|
||||
IFEQ L1
|
||||
L2
|
||||
LDC "foo"
|
||||
ARETURN
|
||||
L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
MAXSTACK = 3
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x1
|
||||
public returnsBool(Z)Ljava/lang/Boolean;
|
||||
L0
|
||||
INVOKESTATIC java/lang/Math.random ()D
|
||||
LDC 0.5
|
||||
DCMPL
|
||||
IFLE L1
|
||||
ICONST_1
|
||||
GOTO L2
|
||||
L1
|
||||
ICONST_0
|
||||
L2
|
||||
INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;
|
||||
ARETURN
|
||||
L3
|
||||
MAXSTACK = 4
|
||||
MAXLOCALS = 2
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// class version 67.0 (67)
|
||||
// access flags 0x21
|
||||
public class simple3/Main {
|
||||
|
||||
// compiled from: Main.java
|
||||
|
||||
// access flags 0x1
|
||||
public <init>()V
|
||||
L0
|
||||
LINENUMBER 3 L0
|
||||
ALOAD 0
|
||||
INVOKESPECIAL java/lang/Object.<init> ()V
|
||||
RETURN
|
||||
L1
|
||||
LOCALVARIABLE this Lsimple3/Main; L0 L1 0
|
||||
MAXSTACK = 1
|
||||
MAXLOCALS = 1
|
||||
|
||||
// access flags 0x0
|
||||
method1(Z)Ljava/lang/String;
|
||||
L0
|
||||
LINENUMBER 5 L0
|
||||
ILOAD 1
|
||||
ICONST_1
|
||||
IF_ICMPNE L1
|
||||
L2
|
||||
LINENUMBER 6 L2
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L1
|
||||
LINENUMBER 8 L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
LOCALVARIABLE this Lsimple3/Main; L0 L3 0
|
||||
LOCALVARIABLE value Z L0 L3 1
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x0
|
||||
method2(Z)Ljava/lang/String;
|
||||
L0
|
||||
LINENUMBER 12 L0
|
||||
ILOAD 1
|
||||
GETSTATIC java/lang/Boolean.TRUE : Ljava/lang/Boolean;
|
||||
INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z
|
||||
IF_ICMPNE L1
|
||||
L2
|
||||
LINENUMBER 13 L2
|
||||
LDC "bar"
|
||||
ARETURN
|
||||
L1
|
||||
LINENUMBER 15 L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
LOCALVARIABLE this Lsimple3/Main; L0 L3 0
|
||||
LOCALVARIABLE value Z L0 L3 1
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x0
|
||||
method3(Z)Ljava/lang/String;
|
||||
L0
|
||||
LINENUMBER 19 L0
|
||||
ILOAD 1
|
||||
GETSTATIC java/lang/Boolean.FALSE : Ljava/lang/Boolean;
|
||||
INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z
|
||||
IF_ICMPNE L1
|
||||
L2
|
||||
LINENUMBER 20 L2
|
||||
LDC "bar"
|
||||
ARETURN
|
||||
L1
|
||||
LINENUMBER 22 L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
LOCALVARIABLE this Lsimple3/Main; L0 L3 0
|
||||
LOCALVARIABLE value Z L0 L3 1
|
||||
MAXSTACK = 2
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x0
|
||||
method(Z)Ljava/lang/String;
|
||||
L0
|
||||
LINENUMBER 26 L0
|
||||
GETSTATIC java/lang/Boolean.TRUE : Ljava/lang/Boolean;
|
||||
ALOAD 0
|
||||
ILOAD 1
|
||||
INVOKEVIRTUAL simple3/Main.returnsBool (Z)Ljava/lang/Boolean;
|
||||
INVOKEVIRTUAL java/lang/Boolean.equals (Ljava/lang/Object;)Z
|
||||
IFEQ L1
|
||||
L2
|
||||
LINENUMBER 27 L2
|
||||
LDC "foo"
|
||||
ARETURN
|
||||
L1
|
||||
LINENUMBER 29 L1
|
||||
LDC "baz"
|
||||
ARETURN
|
||||
L3
|
||||
LOCALVARIABLE this Lsimple3/Main; L0 L3 0
|
||||
LOCALVARIABLE value Z L0 L3 1
|
||||
MAXSTACK = 3
|
||||
MAXLOCALS = 2
|
||||
|
||||
// access flags 0x1
|
||||
public returnsBool(Z)Ljava/lang/Boolean;
|
||||
L0
|
||||
LINENUMBER 33 L0
|
||||
INVOKESTATIC java/lang/Math.random ()D
|
||||
LDC 0.5
|
||||
DCMPL
|
||||
IFLE L1
|
||||
ICONST_1
|
||||
GOTO L2
|
||||
L1
|
||||
ICONST_0
|
||||
L2
|
||||
INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;
|
||||
ARETURN
|
||||
L3
|
||||
LOCALVARIABLE this Lsimple3/Main; L0 L3 0
|
||||
LOCALVARIABLE value Z L0 L3 1
|
||||
MAXSTACK = 4
|
||||
MAXLOCALS = 2
|
||||
}
|
||||
Reference in New Issue
Block a user