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");