diff options
-rw-r--r-- | src/core/lombok/bytecode/ClassFileMetaData.java | 122 | ||||
-rw-r--r-- | test/bytecode/resource/Foo.java | 11 | ||||
-rw-r--r-- | test/bytecode/src/lombok/bytecode/ClassFileMetaDataTest.java | 76 |
3 files changed, 199 insertions, 10 deletions
diff --git a/src/core/lombok/bytecode/ClassFileMetaData.java b/src/core/lombok/bytecode/ClassFileMetaData.java index df50969a..693a9ad5 100644 --- a/src/core/lombok/bytecode/ClassFileMetaData.java +++ b/src/core/lombok/bytecode/ClassFileMetaData.java @@ -40,6 +40,7 @@ public class ClassFileMetaData { private static final byte NAME_TYPE = 12; private static final int NOT_FOUND = -1; + private static final int START_OF_CONSTANT_POOL = 8; private final byte[] byteCode; @@ -52,12 +53,12 @@ public class ClassFileMetaData { public ClassFileMetaData(byte[] byteCode) { this.byteCode = byteCode; - maxPoolSize = readValue(8) + 1; + maxPoolSize = readValue(START_OF_CONSTANT_POOL); offsets = new int[maxPoolSize]; types = new byte[maxPoolSize]; utf8s = new String[maxPoolSize]; int position = 10; - for (int i = 1; i < maxPoolSize - 1; i++) { + for (int i = 1; i < maxPoolSize; i++) { byte type = byteCode[position]; types[i] = type; position++; @@ -84,6 +85,7 @@ public class ClassFileMetaData { case LONG: case DOUBLE: position += 8; + i++; break; case 0: break; @@ -178,6 +180,65 @@ public class ClassFileMetaData { return false; } + public boolean containsLong(long value) { + for (int i = 1; i < maxPoolSize; i++) { + if (types[i] == LONG && readLong(i) == value) return true; + } + return false; + } + + public boolean containsDouble(double value) { + boolean isNan = Double.isNaN(value); + for (int i = 1; i < maxPoolSize; i++) { + if (types[i] == DOUBLE) { + double d = readDouble(i); + if (d == value || (isNan && Double.isNaN(d))) return true; + } + } + return false; + } + + public boolean containsInteger(int value) { + for (int i = 1; i < maxPoolSize; i++) { + if (types[i] == INTEGER && readInteger(i) == value) return true; + } + return false; + } + + public boolean containsFloat(float value) { + boolean isNan = Float.isNaN(value); + for (int i = 1; i < maxPoolSize; i++) { + if (types[i] == FLOAT) { + float f = readFloat(i); + if (f == value || (isNan && Float.isNaN(f))) return true; + } + } + return false; + } + + private long readLong(int index) { + int pos = offsets[index]; + return ((long)read32(pos)) << 32 | read32(pos + 4); + } + + private double readDouble(int index) { + int pos = offsets[index]; + long bits = ((long)read32(pos)) << 32 | (read32(pos + 4) & 0x00000000FFFFFFFF); + return Double.longBitsToDouble(bits); + } + + private long readInteger(int index) { + return read32(offsets[index]); + } + + private float readFloat(int index) { + return Float.intBitsToFloat(read32(offsets[index])); + } + + private int read32(int pos) { + return (byteCode[pos] & 0xFF) << 24 | (byteCode[pos + 1] & 0xFF) << 16 | (byteCode[pos + 2] & 0xFF) << 8 | (byteCode[pos + 3] &0xFF); + } + public String getClassName() { return getClassName(readValue(endOfPool + 2)); } @@ -197,6 +258,63 @@ public class ClassFileMetaData { return result; } + public String poolContent() { + StringBuilder result = new StringBuilder(); + for (int i = 1; i < maxPoolSize; i++) { + result.append(String.format("#%02d: ", i)); + int pos = offsets[i]; + switch(types[i]) { + case UTF8: + result.append("Utf8 ").append(utf8s[i]); + break; + case CLASS: + result.append("Class ").append(getClassName(i)); + break; + case STRING: + result.append("String \"").append(utf8s[readValue(pos)]).append("\""); + break; + case INTEGER: + result.append("int ").append(readInteger(i)); + break; + case FLOAT: + result.append("float ").append(readFloat(i)); + break; + case FIELD: + appendAccess(result.append("Field "), i); + break; + case METHOD: + case IMETHOD: + appendAccess(result.append("Method "), i); + break; + case NAME_TYPE: + appendNameAndType(result.append("Name&Type "), i); + break; + case LONG: + result.append("long ").append(readLong(i)); + break; + case DOUBLE: + result.append("double ").append(readDouble(i)); + break; + case 0: + result.append("(cont.)"); + break; + } + result.append("\n"); + } + return result.toString(); + } + + private void appendAccess(StringBuilder result, int index) { + int pos = offsets[index]; + result.append(getClassName(readValue(pos))).append("."); + appendNameAndType(result, readValue(pos + 2)); + } + + private void appendNameAndType(StringBuilder result, int index) { + int pos = offsets[index]; + result.append(utf8s[readValue(pos)]).append(":").append(utf8s[readValue(pos + 2)]); + } + private String getClassName(int classIndex) { if (classIndex < 1) return null; return utf8s[readValue(offsets[classIndex])]; diff --git a/test/bytecode/resource/Foo.java b/test/bytecode/resource/Foo.java index 95a2c820..2726026c 100644 --- a/test/bytecode/resource/Foo.java +++ b/test/bytecode/resource/Foo.java @@ -1,5 +1,16 @@ public class Foo implements java.util.RandomAccess { + private static final long LONG = 123L; private static final String ONE = "Eén"; + private static final int INT = 123; + private static final double DOUBLE = 1.23; + private static final double DOUBLE_NAN = Double.NaN; + private static final double DOUBLE_INF = Double.POSITIVE_INFINITY; + private static final double DOUBLE_NEG_INF = Double.NEGATIVE_INFINITY; + + private static final float FLOAT = 1.23F; + private static final float FLOAT_NAN = Float.NaN; + private static final float FLOAT_INF = Float.POSITIVE_INFINITY; + private static final float FLOAT_NEG_INF = Float.NEGATIVE_INFINITY; { String value = toString(); diff --git a/test/bytecode/src/lombok/bytecode/ClassFileMetaDataTest.java b/test/bytecode/src/lombok/bytecode/ClassFileMetaDataTest.java index a2fa919f..191ec70d 100644 --- a/test/bytecode/src/lombok/bytecode/ClassFileMetaDataTest.java +++ b/test/bytecode/src/lombok/bytecode/ClassFileMetaDataTest.java @@ -43,10 +43,24 @@ import org.junit.Test; public class ClassFileMetaDataTest { - private ClassFileMetaData foo = create(new File("test/bytecode/resource/Foo.java")); - private ClassFileMetaData bar = create(new File("test/bytecode/resource/Bar.java")); - private ClassFileMetaData baz = create(new File("test/bytecode/resource/Baz.java")); - private ClassFileMetaData buux = create(new File("test/bytecode/resource/Buux.java")); + private static ClassFileMetaData foo = create(new File("test/bytecode/resource/Foo.java")); + private static ClassFileMetaData bar = create(new File("test/bytecode/resource/Bar.java")); + private static ClassFileMetaData baz = create(new File("test/bytecode/resource/Baz.java")); + private static ClassFileMetaData buux = create(new File("test/bytecode/resource/Buux.java")); + +// @Test +// public void dump() { +// byte[] bytes = compile(new File("test/bytecode/resource/Foo.java")); +// int count = 0; +// for (byte b : bytes) { +// System.out.printf("%02x ", (b & 0xFF)); +// count++; +// if (count % 20 == 0) System.out.println(); +// } +// System.out.println(); +// System.out.println(); +// System.out.println(foo.poolContent()); +// } @Test public void testGetClassName() { @@ -125,13 +139,59 @@ public class ClassFileMetaDataTest { assertTrue(foo.containsStringConstant("TwoFour")); assertTrue(buux.containsStringConstant("H\u3404l\0")); + + assertFalse(foo.containsStringConstant("Seven")); + } + + @Test + public void testContainsDouble() { + assertTrue(foo.containsDouble(1.23)); + assertTrue(foo.containsDouble(Double.NaN)); + assertTrue(foo.containsDouble(Double.POSITIVE_INFINITY)); + assertTrue(foo.containsDouble(Double.NEGATIVE_INFINITY)); + + assertFalse(foo.containsDouble(1.0)); + assertFalse(buux.containsDouble(1.0)); + assertFalse(buux.containsDouble(Double.NaN)); + assertFalse(buux.containsDouble(Double.POSITIVE_INFINITY)); + assertFalse(buux.containsDouble(Double.NEGATIVE_INFINITY)); + } + + @Test + public void testContainsFloat() { + assertTrue(foo.containsFloat(1.23F)); + assertTrue(foo.containsFloat(Float.NaN)); + assertTrue(foo.containsFloat(Float.POSITIVE_INFINITY)); + assertTrue(foo.containsFloat(Float.NEGATIVE_INFINITY)); + + assertFalse(foo.containsFloat(1.0F)); + assertFalse(buux.containsFloat(1.0F)); + assertFalse(buux.containsFloat(Float.NaN)); + assertFalse(buux.containsFloat(Float.POSITIVE_INFINITY)); + assertFalse(buux.containsFloat(Float.NEGATIVE_INFINITY)); + } + + @Test + public void testContainsInteger() { + assertTrue(foo.containsInteger(123)); + + assertFalse(foo.containsInteger(1)); + assertFalse(buux.containsInteger(1)); + } + + @Test + public void testContainsLong() { + assertTrue(foo.containsLong(123)); + + assertFalse(foo.containsLong(1)); + assertFalse(buux.containsLong(1)); } - private ClassFileMetaData create(File file) { + private static ClassFileMetaData create(File file) { return new ClassFileMetaData(compile(file)); } - private byte[] compile(File file) { + private static byte[] compile(File file) { try { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); File tempDir = getTempDir(); @@ -146,7 +206,7 @@ public class ClassFileMetaDataTest { } } - private File getTempDir() { + private static File getTempDir() { String[] rawDirs = { System.getProperty("java.io.tmpdir"), "/tmp", @@ -177,7 +237,7 @@ public class ClassFileMetaDataTest { } } - private String readFileAsString(File file) { + private static String readFileAsString(File file) { try { BufferedReader reader = new BufferedReader(new FileReader(file)); StringWriter writer = new StringWriter(); |