Bufix in CompilerEnvironment. development
authorJan Vrany <jan.vrany@fit.cvut.cz>
Tue, 02 Apr 2013 23:08:51 +0100
branchdevelopment
changeset 2477 6e37b62e21b5
parent 2476 d24ce8174195
child 2478 126adef4626a
Bufix in CompilerEnvironment. Build correct java name from passed array. Fixes compilation of 'import static x.y.Z.*;'
experiments/java/src/stx/libjava/tools/compiler/ecj/CompilationUnit.java
experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerAdapter.java
experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerEnvironment.java
experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerTypeRegistry.java
experiments/java/src/stx/libjava/tools/compiler/ecj/tests/CompilerTests.java
--- a/experiments/java/src/stx/libjava/tools/compiler/ecj/CompilationUnit.java	Sun Mar 31 19:25:00 2013 +0100
+++ b/experiments/java/src/stx/libjava/tools/compiler/ecj/CompilationUnit.java	Tue Apr 02 23:08:51 2013 +0100
@@ -63,4 +63,10 @@
 		}
 		return packagename;
 	}
+
+	@Override
+	public boolean ignoreOptionalProblems() {
+		// TODO Auto-generated method stub
+		return false;
+	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerAdapter.java	Tue Apr 02 23:08:51 2013 +0100
@@ -0,0 +1,86 @@
+package stx.libjava.tools.compiler.ecj;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
+import org.eclipse.jdt.internal.compiler.IProblemFactory;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+
+public class CompilerAdapter implements ICompilerRequestor {
+	protected CompilerTypeRegistry types = new CompilerTypeRegistry();
+	protected INameEnvironment environment = new CompilerEnvironment(types);
+	protected CompilationResult result;
+	
+	
+	public CompilationResult getResult() {
+		return result;
+	}
+
+	/**
+	 * Compiles classes in given source. The resulting .class files are added
+	 * to an internal list which can be later retrieved by getClassFiles().
+	 * 
+	 * @param name fully qualified java name of class being compiled. 
+	 * @param source source code of the class as String.   
+	 * @return true, if compilation succeeded, false otherwise.
+	 */
+	public boolean compile(String name, String source) {
+		ICompilerRequestor requestor = this;
+		IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems();
+	    IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
+	    ICompilationUnit[] units = new ICompilationUnit[1];
+	    units[0] = new CompilationUnit(name, source);
+		
+		org.eclipse.jdt.internal.compiler.Compiler compiler = new org.eclipse.jdt.internal.compiler.Compiler(environment, policy, getDefaultCompilerOptions(), requestor, problemFactory);
+		compiler.compile(units);
+		return getResult().hasErrors();
+	}
+	
+	/**
+	 * Returns a list of JavaClassFiles that contains results of the compilation. 
+	 * 
+	 * @return resulting class files
+	 */
+	public ClassFile[] getClassFiles() {
+		return getResult().getClassFiles();
+	}
+	
+	public static Map<String, Object> getDefaultCompilerSettings() {
+		String javaSpecVersion = System.getProperty("java.specification.version");
+        Map<String, Object> settings = new HashMap<String, Object>();
+        settings.put(CompilerOptions.OPTION_Source, javaSpecVersion);
+        settings.put(CompilerOptions.OPTION_TargetPlatform, javaSpecVersion);
+        settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE);
+        return settings;
+	}
+
+    public static CompilerOptions getDefaultCompilerOptions() {
+    	return new CompilerOptions(getDefaultCompilerSettings());
+    }
+
+	@Override
+	public void acceptResult(CompilationResult result) {
+		this.result = result;
+		for (ClassFile cf : this.result.getClassFiles()) {
+			StringBuilder sb = new StringBuilder();
+			for (int i = 0; i < cf.getCompoundName().length; i++) {
+				sb.append(cf.getCompoundName()[i]);
+				if (i < cf.getCompoundName().length - 1) {
+					sb.append('.');
+				}
+			}
+			types.put(sb.toString(), cf.getBytes());
+		}
+	}
+	
+
+}
--- a/experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerEnvironment.java	Sun Mar 31 19:25:00 2013 +0100
+++ b/experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerEnvironment.java	Tue Apr 02 23:08:51 2013 +0100
@@ -1,14 +1,28 @@
 package stx.libjava.tools.compiler.ecj;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 
 public class CompilerEnvironment implements INameEnvironment {
+	protected CompilerTypeRegistry types;
+	
+	public CompilerEnvironment() {
+		 types = new CompilerTypeRegistry();
+	}
+	
+	public CompilerEnvironment(CompilerTypeRegistry types) {
+		this.types = types;
+	}
+	
 	/**
 	 * Find a type with the given compound name.
 	 * Answer the binary form of the type if it is known to be consistent.
@@ -28,29 +42,47 @@
 		if (compoundTypeName.length > 1) {
 			for (int i = 0; i < compoundTypeName.length - 1; i++) {
 				sb.append(compoundTypeName[i]);
+				sb.append('.');
 			}		
 		}
 		sb.append(compoundTypeName[compoundTypeName.length-1]);
 		return findType(sb.toString());
 	}
 	
-	protected NameEnvironmentAnswer findType(String javaname) {
+	/** 
+	 * Returns a IBinaryType for class with given name or null
+	 * if there's no such class. 
+	 * @param name
+	 * @return binary type or null (if no type is found)
+	 */
+	protected IBinaryType findTypeForClassNamed(String name) {
+		IBinaryType type;
+		
+		type = types.get(name);
+		if (type != null) return type;
+		
 		try {
-			Class<?> c = Class.forName(javaname);
-			ClassLoader cl = c.getClassLoader();
-			if (cl == null) { 
-				cl = ClassLoader.getSystemClassLoader();
+			Class<?> c = Class.forName(name);
+			InputStream cfs = findClassFileForClass(c);
+			if (cfs == null) {
+				return null;
+			} else {
+				types.put(name, cfs);
+				return types.get(name);
 			}
-			String cfilename = (new String(c.getName())).replace('.', '/') + ".class";
-			InputStream cfs = cl.getResourceAsStream(cfilename);
-			return new NameEnvironmentAnswer(ClassFileReader.read(cfs, cfilename), null);
 		} catch (ClassNotFoundException cnfe) {
 			return null;
-		} catch (ClassFormatException e) {
+		} catch (RuntimeException e) {
 			e.printStackTrace();
 			return null;
-		} catch (IOException e) {
-			e.printStackTrace();
+		}		
+	}
+	
+	protected NameEnvironmentAnswer findType(String name) {
+		IBinaryType type = findTypeForClassNamed(name);
+		if (type != null) {
+			return new NameEnvironmentAnswer(type, null);
+		} else {
 			return null;
 		}
 	}
@@ -100,7 +132,30 @@
 	 * the code which created it to decide when it is a good time to clean it up.
 	 */
 	public void cleanup() {
-		
+
 	}
-
+	
+	/**
+	 * Given a class, return an InputStream on corresponding .class file. 
+	 * @return InputStream or null
+	 */
+	public InputStream findClassFileForClass(Class<?> c) {
+		/* STX:LIBJAVA specific: ask the class for its classfile bytes... */
+		if (System.getProperty("java.vm.name").equals("Smalltalk/X")) {
+			byte[] bytes = findClassBytesForClass0(c);
+			if (bytes != null) {
+				return new ByteArrayInputStream(bytes);
+			}
+		}
+	
+		ClassLoader cl = c.getClassLoader();
+		if (cl == null) { 
+			cl = ClassLoader.getSystemClassLoader();
+		}
+		String cfilename = (new String(c.getName())).replace('.', '/') + ".class";
+		return cl.getResourceAsStream(cfilename);		
+	}
+	
+	public native byte[] findClassBytesForClass0(Class<?> c); 
+	
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/experiments/java/src/stx/libjava/tools/compiler/ecj/CompilerTypeRegistry.java	Tue Apr 02 23:08:51 2013 +0100
@@ -0,0 +1,45 @@
+package stx.libjava.tools.compiler.ecj;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+
+/**
+ * A registry for binary types. Eventually will do some caching in the future...
+ * @author Jan Vrany
+ *
+ */
+public class CompilerTypeRegistry {
+	protected Map<String, IBinaryType> typeMap = new HashMap<String, IBinaryType>();
+	
+	public IBinaryType get(String name) {
+		return typeMap.get(name);
+	}
+	
+	public void put(String name, IBinaryType type) {
+		typeMap.put(name,type);
+	}
+		
+	public void put(String name, InputStream classfile) {
+		try {
+			put(name, ClassFileReader.read(classfile, (new String(name).replace('.', '/') + ".class")));
+		} catch (ClassFormatException e) {
+			throw new RuntimeException(e);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	public void put(String name, byte[] classfile) {
+		put(name, new ByteArrayInputStream(classfile));
+	}
+	
+	
+
+}
--- a/experiments/java/src/stx/libjava/tools/compiler/ecj/tests/CompilerTests.java	Sun Mar 31 19:25:00 2013 +0100
+++ b/experiments/java/src/stx/libjava/tools/compiler/ecj/tests/CompilerTests.java	Tue Apr 02 23:08:51 2013 +0100
@@ -4,7 +4,7 @@
 
 import java.lang.reflect.InvocationTargetException;
 
-import stx.libjava.tools.compiler.ecj.Compiler;
+import stx.libjava.tools.compiler.ecj.CompilerAdapter;
 
 import org.eclipse.jdt.internal.compiler.ClassFile;
 import org.junit.Test;
@@ -21,7 +21,7 @@
 
 	@Test
 	public void test_01() {
-		Compiler c = new Compiler();
+		CompilerAdapter c = new CompilerAdapter();
 		ClassLoader l = new ClassLoader();
 				
 		c.compile("test.pkg.Foo", "package test.pkg; public class Foo {}");
@@ -43,7 +43,7 @@
 	 */
 	@Test
 	public void test_02() {
-		Compiler c = new Compiler();
+		CompilerAdapter c = new CompilerAdapter();
 		ClassLoader l = new ClassLoader();
 				
 		c.compile("test.pkg.Foo", "package test.pkg; public class Foo { public void f() { g(); } }");		
@@ -68,5 +68,40 @@
 		}
 	}
 
+	/**
+	 * Tests compilation of depending classes
+	 */
+	@Test
+	public void test_03() {
+		CompilerAdapter c = new CompilerAdapter();
+		ClassLoader l = new ClassLoader();
+				
+		c.compile("test.pkg.Foo", "package test.pkg; public class Foo { public void f() {  } }");
+		assertEquals(1, c.getClassFiles().length);
+		assertFalse(c.getResult().hasErrors());
+		
+		c.compile("test.pkg.Bar", "package test.pkg; public class Bar { public void f() { new Foo(); } }");
+		assertEquals(1, c.getClassFiles().length);
+		assertFalse(c.getResult().hasErrors());
+		
+	}
 
+	@Test
+	public void test_04() {
+		CompilerAdapter c = new CompilerAdapter();
+		ClassLoader l = new ClassLoader();
+				
+		c.compile("test.pkg.Foo", "package test.pkg; import static java.lang.System.*; public class Foo {}");
+		
+		assertFalse(c.getResult().hasErrors());
+		
+		ClassFile[] classfiles = c.getResult().getClassFiles();
+		
+		assertEquals(1, classfiles.length);
+		
+		Class<?> clazz = l.load(classfiles[0].getBytes());
+		
+		assertEquals("test.pkg.Foo" , clazz.getName());
+	}
+	
 }