diff --git a/pom.xml b/pom.xml
index 6fd1ab9..6e61b6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,6 +119,11 @@
javalang
[4.1.0, 5.0.0)
+
+ org.ow2.asm
+ asm-commons
+ 6.1.1
+
junit
junit
diff --git a/src/main/java/org/walkmod/javalang/compiler/types/ASMClass.java b/src/main/java/org/walkmod/javalang/compiler/types/ASMClass.java
new file mode 100644
index 0000000..e70173f
--- /dev/null
+++ b/src/main/java/org/walkmod/javalang/compiler/types/ASMClass.java
@@ -0,0 +1,73 @@
+package org.walkmod.javalang.compiler.types;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.ClassNode;
+
+import java.io.File;
+
+
+public class ASMClass extends ClassNode {
+
+
+ private String actualName;
+ private Boolean anonymous;
+ private boolean isPrivate = false;
+
+
+ public ASMClass() {
+ super(Opcodes.ASM5);
+ }
+
+ @Override
+ public void visit(int version, int access,
+ String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ actualName = name;
+ isPrivate = access == Opcodes.ACC_PRIVATE;
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outer, String innerName, int access) {
+ super.visitInnerClass(name, outer, innerName, access);
+ if (name.equals(actualName)) {
+ anonymous = innerName == null;
+ }
+ }
+
+ public Boolean isAnonymous() {
+ return anonymous != null && anonymous;
+ }
+
+ public Boolean isMemberClass() {
+ return anonymous != null && !anonymous;
+ }
+
+ public String getActualName() {
+ return actualName;
+ }
+
+ public Boolean isPrivate() {
+ return isPrivate;
+ }
+
+ public String getPackage() {
+ if (!actualName.contains(File.separator)){
+ return null;
+ }
+ return getActualName().substring(0, getActualName().lastIndexOf(File.separator) + 1)
+ .replaceAll(File.separator, "\\.");
+ }
+
+ public String getSimpleName() {
+ int index = getActualName().lastIndexOf(File.separator);
+ if (index != -1){
+ return actualName;
+ } else {
+ return getActualName().substring(index + 1);
+ }
+ }
+
+ public String getCanonicalName() {
+ return getPackage() + "." + getSimpleName().replaceAll("$", "\\.");
+ }
+}
diff --git a/src/main/java/org/walkmod/javalang/compiler/types/TypesLoaderVisitor.java b/src/main/java/org/walkmod/javalang/compiler/types/TypesLoaderVisitor.java
index 3ffcd06..1da227d 100644
--- a/src/main/java/org/walkmod/javalang/compiler/types/TypesLoaderVisitor.java
+++ b/src/main/java/org/walkmod/javalang/compiler/types/TypesLoaderVisitor.java
@@ -14,14 +14,17 @@
*/
package org.walkmod.javalang.compiler.types;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URLClassLoader;
import java.util.*;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.InnerClassNode;
import org.walkmod.javalang.ast.CompilationUnit;
import org.walkmod.javalang.ast.ImportDeclaration;
import org.walkmod.javalang.ast.Node;
@@ -34,10 +37,8 @@
import org.walkmod.javalang.ast.body.TypeDeclaration;
import org.walkmod.javalang.ast.expr.ObjectCreationExpr;
import org.walkmod.javalang.ast.expr.QualifiedNameExpr;
-import org.walkmod.javalang.ast.type.Type;
import org.walkmod.javalang.compiler.actions.LoadStaticImportsAction;
import org.walkmod.javalang.compiler.providers.SymbolActionProvider;
-import org.walkmod.javalang.compiler.symbols.ASTSymbolTypeResolver;
import org.walkmod.javalang.compiler.symbols.ReferenceType;
import org.walkmod.javalang.compiler.symbols.Scope;
import org.walkmod.javalang.compiler.symbols.Symbol;
@@ -450,13 +451,15 @@ public void visit(ImportDeclaration id, T context) {
/**
* @param importedInner {@link @see #resolveSymbolName}
*/
- private void loadNestedClasses(Class> clazz, boolean imported, Node node, final boolean importedInner) {
- Class>[] innerClasses = clazz.getDeclaredClasses();
- if (innerClasses != null) {
- for (int i = 0; i < innerClasses.length; i++) {
- if (!Modifier.isPrivate(innerClasses[i].getModifiers())) {
- String fullName = innerClasses[i].getName();
- SymbolType st = new SymbolType(innerClasses[i]);
+ private void loadNestedClasses(ASMClass clazz, boolean imported, Node node, final boolean importedInner) {
+
+ if (clazz.innerClasses != null) {
+ Iterator it = clazz.innerClasses.iterator();
+ while(it.hasNext()) {
+ InnerClassNode innerClass = it.next();
+ if (innerClass.access != Opcodes.ACC_PRIVATE) {
+ String fullName = innerClass.name;
+ SymbolType st = new SymbolType(fullName);
symbolTable.pushSymbol(resolveSymbolName(fullName, imported, importedInner), ReferenceType.TYPE, st,
node, true);
}
@@ -465,15 +468,53 @@ private void loadNestedClasses(Class> clazz, boolean imported, Node node, fina
}
}
+ private static byte[] readStream(InputStream inputStream, boolean close) throws IOException {
+ if(inputStream == null) {
+ throw new IOException("Class not found");
+ } else {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] data = new byte[4096];
+
+ int bytesRead;
+ while((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
+ outputStream.write(data, 0, bytesRead);
+ }
+
+ outputStream.flush();
+ byte[] var5 = outputStream.toByteArray();
+ return var5;
+ } finally {
+ if(close) {
+ inputStream.close();
+ }
+
+ }
+ }
+ }
+
+ private ASMClass getASMClass(String name) throws IOException {
+ ASMClass visitor = new ASMClass();
+ ClassReader reader = new ClassReader(readStream(
+ classLoader.getResourceAsStream(name.replace('.', '/') + ".class"),
+ true));
+ reader.accept(visitor, 1);
+ return visitor;
+ }
+
private void addType(final String name, boolean imported, Node node, List actions) {
if (classLoader != null && name != null) {
+
+ //check if the file exists in the classpath
try {
- Class> clazz = Class.forName(name, false, classLoader);
- if (!Modifier.isPrivate(clazz.getModifiers()) && !clazz.isAnonymousClass()) {
+
+ ASMClass asmClass = getASMClass(name);
+
+ if (!asmClass.isPrivate() && !asmClass.isAnonymous()){ //anonymous?
boolean overrideSimpleName = true;
- SymbolType st = new SymbolType(clazz);
+ SymbolType st = new SymbolType(name);
if (node instanceof ImportDeclaration) {
ImportDeclaration id = (ImportDeclaration) node;
@@ -481,27 +522,26 @@ private void addType(final String name, boolean imported, Node node, List clazz = Class.forName(internalName, false, classLoader);
+ ASMClass asmClass = getASMClass(internalName);
- if (!Modifier.isPrivate(clazz.getModifiers())) {
+ if (!asmClass.isPrivate()) {
String keyName = resolveSymbolName(internalName, imported, false);
- SymbolType st = new SymbolType(clazz);
+ SymbolType st = new SymbolType(internalName);
Symbol> pushedSymbol =
symbolTable.pushSymbol(keyName, ReferenceType.TYPE, st, node, actions, true);
if (pushedSymbol != null) {
- loadNestedClasses(clazz, imported, node, false);
+ loadNestedClasses(asmClass, imported, node, false);
}
}
- } catch (ClassNotFoundException e1) {
+ } catch (IOException e1) {
int indexDot = internalName.indexOf(".");
if (indexDot == -1) {
throw new RuntimeException("The referenced class " + internalName + " does not exists");