Author: j...@google.com Date: Wed Feb 4 16:56:06 2009 New Revision: 4631 Added: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompiledClass.java (contents, props changed) changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/SourceCompiledClass.java (contents, props changed) Removed: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompiledClassVisitor.java Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnit.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnitBuilder.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompilationUnit.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
Log: Split CompiledClass into BinaryCompiledClass and SourceCompiledClass. Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnit.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnit.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnit.java Wed Feb 4 16:56:06 2009 @@ -18,6 +18,7 @@ import org.eclipse.jdt.core.compiler.CategorizedProblem; +import java.util.HashSet; import java.util.Set; /** @@ -26,6 +27,8 @@ */ public class BinaryCompilationUnit extends CompilationUnit { + private Set<BinaryCompiledClass> compiledClasses = new HashSet<BinaryCompiledClass>();; + /* (non-Javadoc) * @see com.google.gwt.dev.javac.CompilationUnit#getDisplayLocation() */ @@ -54,7 +57,6 @@ */ @Override public String getSource() { - // TODO(jat): Auto-generated method stub return null; } @@ -85,19 +87,16 @@ return false; } - /* (non-Javadoc) - * @see com.google.gwt.dev.javac.CompilationUnit#isSuperSource() - */ @Override public boolean isSuperSource() { - // TODO(jat): Auto-generated method stub return false; } @Override protected Set<CompiledClass> computeCompiledClasses() { - // TODO(jat): Auto-generated method stub - return null; + Set<CompiledClass> classes = new HashSet<CompiledClass>(); + classes.addAll(compiledClasses); + return classes; } /* (non-Javadoc) @@ -105,22 +104,18 @@ */ @Override protected Set<String> computeFileNameRefs() { - // TODO(jat): Auto-generated method stub + Set<String> filenames = new HashSet<String>(); + for (BinaryCompiledClass compiledClass : compiledClasses) { + filenames.add(compiledClass.getClassResource().getLocation()); + } return null; } - /* (non-Javadoc) - * @see com.google.gwt.dev.javac.CompilationUnit#getErrors() - */ @Override CategorizedProblem[] getErrors() { - // TODO(jat): Auto-generated method stub return null; } - /* (non-Javadoc) - * @see com.google.gwt.dev.javac.CompilationUnit#setState(com.google.gwt.dev.javac.CompilationUnit.State) - */ @Override void setState(State newState) { // TODO(jat): Auto-generated method stub Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnitBuilder.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnitBuilder.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompilationUnitBuilder.java Wed Feb 4 16:56:06 2009 @@ -17,21 +17,150 @@ package com.google.gwt.dev.javac; import com.google.gwt.dev.asm.ClassReader; -import com.google.gwt.dev.javac.BinaryCompiledClassVisitor.ClassNotSuitableException; +import com.google.gwt.dev.asm.FieldVisitor; +import com.google.gwt.dev.asm.MethodVisitor; +import com.google.gwt.dev.asm.Opcodes; +import com.google.gwt.dev.asm.commons.EmptyVisitor; import com.google.gwt.dev.resource.Resource; import com.google.gwt.dev.util.Util; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; /** * Builds a BinaryCompilationUnit from a set of class files. */ public class BinaryCompilationUnitBuilder { + /** + * Exception thrown when the supplied class is not suitable for use from a + * class file rather than source. + */ + public static class ClassNotSuitableException extends RuntimeException { + + public ClassNotSuitableException(String msg) { + super(msg); + } + } + + /** + * Reads the bytecode for a class and, if suitable, builds a + * BinaryCompilationUnit and its BinaryCompileClass entries. + */ + public class BinaryCompiledClassVisitor extends EmptyVisitor { + + private String source = null; + private List<Resource> innerClasses = new ArrayList<Resource>(); + private String name; + private String signature; + private String superName; + private String[] interfaces; + private byte[] bytes; + private Resource classResource; + + public BinaryCompiledClassVisitor(Resource classResource, byte[] bytes) { + this.classResource = classResource; + this.bytes = bytes; + } + + public BinaryCompiledClass getBinaryCompiledClass() { + CompiledClass enclosingClass = null; + // TODO(jat): Auto-generated method stub + return new BinaryCompiledClass(classResource, bytes, enclosingClass, name, signature, superName, + interfaces, innerClasses); + } + + /** + * Called at the beginning of visiting the class. + * + * @param version classfile version (ie, Opcodes.V1_5 etc) + * @param access access flags (ie, bitwise or of Opcodes.ACC_*) + * @param name binary name of this class (ie, com/google/Foo) + * @param signature generic signature or null + * @param superName binary name of superclass (ie, java/lang/Object) + * @param interfaces array of binary names of implemented interfaces + */ + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + // Is there anything we should check here, such as if it implements a JSO? + this.name = name; + this.signature = signature; + this.superName = superName; + this.interfaces = interfaces; + } + + /** + * Called for each field. + * + * @param access access flags for field + * @param name field name + * @param desc type descriptor (ie, Ljava/lang/String;) + * @param signature generic signature (null if not generic) + * @param value initialized value if constant + */ + @Override + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { + // TODO(jat): Collect fields & annotations for TypeOracle building + return null; + } + + /** + * Called once for every inner class of this class. + * + * @param name binary name of inner class (ie, com/google/Foo$1) + * @param outerName binary name of enclosing class (null if not a member + * class or anonymous) + * @param innerName simple name of the inner class (null if anonymous) + * @param access access flags (bitwise or of Opcodes.ACC_*) as declared in + * the enclosing class + */ + @Override + public void visitInnerClass(String name, String outerName, String innerName, + int access) { + Resource innerClass = binaryMap.get(innerName + ".class"); + if (innerClass != null) { + addClass(innerClass); + innerClasses.add(innerClass); + } + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + if ((access & Opcodes.ACC_NATIVE) != 0) { + throw new ClassNotSuitableException("Has native methods"); + } + // TODO(jat): Collect annotations/etc for TypeOracle + return null; + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + // TODO(jat): Auto-generated method stub + super.visitOuterClass(owner, name, desc); + } + + /** + * If compiled with debug, visit the source information. + * + * @param source unqualified filename containing source (ie, Foo.java) + * @param debug additional debug information (may be null) + */ + @Override + public void visitSource(String source, String debug) { + this.source = source; + } + } + + private final Map<String, Resource> binaryMap; + private ArrayList<Resource> processQueue = new ArrayList<Resource>(); - private Map<String, Resource> binaryMap; private ArrayList<BinaryCompiledClass> classes = new ArrayList<BinaryCompiledClass>(); public BinaryCompilationUnitBuilder(Map<String, Resource> binaryMap) { @@ -43,13 +172,18 @@ } public BinaryCompilationUnit getBinaryCompilationUnit() { + Set<BinaryCompiledClass> seen = new HashSet<BinaryCompiledClass>(); while (!processQueue.isEmpty()) { BinaryCompiledClass compiledClass = processClass(processQueue.remove(0)); + if (seen.contains(compiledClass)) { + continue; + } + seen.add(compiledClass); if (compiledClass != null) { classes.add(compiledClass); } } - return null; + return new BinaryCompilationUnit(); } private BinaryCompiledClass processClass(Resource classResource) { @@ -63,7 +197,8 @@ } try { ClassReader reader = new ClassReader(classBytes); - BinaryCompiledClassVisitor visitor = new BinaryCompiledClassVisitor(); + BinaryCompiledClassVisitor visitor = new BinaryCompiledClassVisitor( + classResource, classBytes); reader.accept(visitor, ClassReader.SKIP_CODE); return visitor.getBinaryCompiledClass(); } catch (ClassNotSuitableException e) { Added: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompiledClass.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/BinaryCompiledClass.java Wed Feb 4 16:56:06 2009 @@ -0,0 +1,107 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.dev.javac; + +import com.google.gwt.dev.js.ast.JsProgram; +import com.google.gwt.dev.resource.Resource; + +import java.util.Collections; +import java.util.List; + +/** + * @author j...@google.com (Your Name Here) + * + */ +public class BinaryCompiledClass extends CompiledClass { + + private String name; + private String signature; + private Object superName; + private String[] interfaces; + private List<Resource> innerClasses; + private Resource classResource; + + BinaryCompiledClass(CompiledClass enclosingClass) { + super(null, enclosingClass); + // TODO Auto-generated constructor stub + } + + public BinaryCompiledClass(Resource classResource, byte[] bytes, + CompiledClass enclosingClass, String name, String signature, + String superName, String[] interfaces, List<Resource> innerClasses) { + super(null, enclosingClass); + this.classResource = classResource; + this.bytes = bytes; + this.name = name; + this.signature = signature; + this.superName = superName; + this.interfaces = interfaces; + this.innerClasses = innerClasses; + } + + Resource getClassResource() { + return classResource; + } + + private byte[] bytes; + + @Override + void checked() { + // TODO Auto-generated method stub + + } + + @Override + public String getBinaryName() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see com.google.gwt.dev.javac.CompiledClass#getBytes() + */ + @Override + public byte[] getBytes() { + return bytes; + } + + /* (non-Javadoc) + * @see com.google.gwt.dev.javac.CompiledClass#getPackageName() + */ + @Override + public String getPackageName() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see com.google.gwt.dev.javac.CompiledClass#getSourceName() + */ + @Override + public String getSourceName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List<JsniMethod> getJsniMethods(JsProgram program, + JnsiErrorCallback callback) { + // Currently we do not support JSNI in binary classes. + return Collections.emptyList(); + } + +} Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java Wed Feb 4 16:56:06 2009 @@ -106,7 +106,7 @@ changed = false; Set<String> validRefs = new HashSet<String>(); for (CompilationUnit unit : validUnits) { - validRefs.add(unit.getDisplayLocation()); + validRefs.addAll(unit.getFileNameRefs()); } for (Iterator<CompilationUnit> it = validUnits.iterator(); it.hasNext();) { CompilationUnit unit = it.next(); Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java Wed Feb 4 16:56:06 2009 @@ -16,152 +16,89 @@ package com.google.gwt.dev.javac; import com.google.gwt.core.ext.typeinfo.JRealClassType; -import com.google.gwt.dev.javac.impl.Shared; +import com.google.gwt.dev.js.ast.JsProgram; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +import java.util.List; /** * Encapsulates the state of a single compiled class file. */ -public final class CompiledClass { +public abstract class CompiledClass { - private static ClassFile getClassFile(TypeDeclaration typeDecl, - String binaryName) { - for (ClassFile tryClassFile : typeDecl.compilationResult().getClassFiles()) { - char[] tryBinaryName = CharOperation.concatWith( - tryClassFile.getCompoundName(), '/'); - if (binaryName.equals(String.valueOf(tryBinaryName))) { - return tryClassFile; - } - } - assert false; - return null; - } + /** + * @author j...@google.com (Your Name Here) + * + */ + public interface JnsiErrorCallback { - private static String getPackagePrefix(String packageName) { - return packageName.length() > 0 ? packageName + "." : ""; + boolean reportError(String msg); } - protected final String binaryName; - protected final byte[] bytes; protected final CompiledClass enclosingClass; - protected final String location; - protected final String packageName; - protected final String sourceName; - protected final CompilationUnit unit; + protected CompilationUnit unit; // The state below is transient. - private NameEnvironmentAnswer nameEnvironmentAnswer; private JRealClassType realClassType; - // Can be killed after parent is CHECKED. - private TypeDeclaration typeDeclaration; - CompiledClass(CompilationUnit unit, TypeDeclaration typeDeclaration, - CompiledClass enclosingClass) { + CompiledClass(CompilationUnit unit, CompiledClass enclosingClass) { this.unit = unit; - this.typeDeclaration = typeDeclaration; this.enclosingClass = enclosingClass; - SourceTypeBinding binding = typeDeclaration.binding; - this.binaryName = CharOperation.charToString(binding.constantPoolName()); - this.packageName = Shared.getPackageNameFromBinary(binaryName); - if (binding instanceof LocalTypeBinding) { - // The source name of a local type must be determined from binary. - String qualifiedName = binaryName.replace('/', '.'); - this.sourceName = qualifiedName.replace('$', '.'); - } else { - this.sourceName = getPackagePrefix(packageName) - + String.valueOf(binding.qualifiedSourceName()); - } - ClassFile classFile = getClassFile(typeDeclaration, binaryName); - this.bytes = classFile.getBytes(); - this.location = String.valueOf(classFile.fileName()); } /** * Returns the binary class name, e.g. {...@code java/util/Map$Entry}. */ - public String getBinaryName() { - return binaryName; - } + public abstract String getBinaryName(); /** * Returns the bytes of the compiled class. */ - public byte[] getBytes() { - return bytes; - } + public abstract byte[] getBytes(); - public CompiledClass getEnclosingClass() { + public final CompiledClass getEnclosingClass() { return enclosingClass; } + + public abstract List<JsniMethod> getJsniMethods(JsProgram program, + JnsiErrorCallback callback); /** * Returns the enclosing package, e.g. {...@code java.util}. */ - public String getPackageName() { - return packageName; - } + public abstract String getPackageName(); /** * Returns the qualified source name, e.g. {...@code java.util.Map.Entry}. */ - public String getSourceName() { - return sourceName; - } + public abstract String getSourceName(); - public CompilationUnit getUnit() { + public final CompilationUnit getUnit() { return unit; } @Override public String toString() { - return binaryName; + return getBinaryName(); } /** * All checking is done, free up internal state. */ void checked() { - this.typeDeclaration = null; } - NameEnvironmentAnswer getNameEnvironmentAnswer() { - if (nameEnvironmentAnswer == null) { - try { - ClassFileReader cfr = new ClassFileReader(bytes, location.toCharArray()); - nameEnvironmentAnswer = new NameEnvironmentAnswer(cfr, null); - } catch (ClassFormatException e) { - throw new RuntimeException("Unexpectedly unable to parse class file", e); - } - } - return nameEnvironmentAnswer; - } - - JRealClassType getRealClassType() { + final JRealClassType getRealClassType() { return realClassType; } - TypeDeclaration getTypeDeclaration() { - return typeDeclaration; - } - void invalidate() { - nameEnvironmentAnswer = null; - typeDeclaration = null; if (realClassType != null) { realClassType.invalidate(); realClassType = null; } } - void setRealClassType(JRealClassType realClassType) { + final void setRealClassType(JRealClassType realClassType) { this.realClassType = realClassType; } } Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompilationUnit.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompilationUnit.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompilationUnit.java Wed Feb 4 16:56:06 2009 @@ -55,7 +55,7 @@ * uninstantiable, it won't bother allocating a local name. */ if (typeDecl.binding.constantPoolName() != null) { - CompiledClass newClass = new CompiledClass(JdtCompilationUnit.this, + CompiledClass newClass = new SourceCompiledClass(JdtCompilationUnit.this, typeDecl, enclosingClass); map.put(typeDecl.binding, newClass); } @@ -66,7 +66,7 @@ public boolean visit(TypeDeclaration typeDecl, ClassScope scope) { CompiledClass enclosingClass = map.get(typeDecl.binding.enclosingType()); assert (enclosingClass != null); - CompiledClass newClass = new CompiledClass(JdtCompilationUnit.this, + CompiledClass newClass = new SourceCompiledClass(JdtCompilationUnit.this, typeDecl, enclosingClass); map.put(typeDecl.binding, newClass); return true; @@ -75,7 +75,7 @@ @Override public boolean visit(TypeDeclaration typeDecl, CompilationUnitScope scope) { assert (typeDecl.binding.enclosingType() == null); - CompiledClass newClass = new CompiledClass(JdtCompilationUnit.this, + CompiledClass newClass = new SourceCompiledClass(JdtCompilationUnit.this, typeDecl, null); map.put(typeDecl.binding, newClass); return true; Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java Wed Feb 4 16:56:06 2009 @@ -132,11 +132,20 @@ char[] binaryNameChars = CharOperation.concatWith(compoundTypeName, '/'); String binaryName = String.valueOf(binaryNameChars); CompiledClass compiledClass = binaryTypes.get(binaryName); - if (compiledClass != null) { - return compiledClass.getNameEnvironmentAnswer(); + if (compiledClass instanceof SourceCompiledClass) { + return ((SourceCompiledClass) compiledClass).getNameEnvironmentAnswer(); } if (isPackage(binaryName)) { return null; + } + if (compiledClass != null) { + try { + // TODO(jat): is this right? + ClassFileReader cfr = new ClassFileReader(compiledClass.getBytes(), + compiledClass.getSourceName().toCharArray()); + return new NameEnvironmentAnswer(cfr, null); + } catch (ClassFormatException e) { + } } try { URL resource = getClassLoader().getResource(binaryName + ".class"); Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java Wed Feb 4 16:56:06 2009 @@ -17,6 +17,7 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.dev.javac.CompilationUnit.State; +import com.google.gwt.dev.javac.CompiledClass.JnsiErrorCallback; import com.google.gwt.dev.js.JsParser; import com.google.gwt.dev.js.JsParserException; import com.google.gwt.dev.js.JsParserException.SourceDetail; @@ -29,8 +30,6 @@ import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.util.Util; import java.io.IOException; import java.io.StringReader; @@ -57,7 +56,7 @@ } } - private static final class JsniMethodImpl extends JsniMethod { + static final class JsniMethodImpl extends JsniMethod { private JsFunction func; private final int line; private final String location; @@ -66,7 +65,7 @@ private final String source; private final JsProgram program; - private JsniMethodImpl(String name, String source, String[] paramNames, + JsniMethodImpl(String name, String source, String[] paramNames, int line, String location, JsProgram program) { this.name = name; this.source = source; @@ -157,40 +156,17 @@ /** * TODO: log real errors, replacing GenerateJavaScriptAST? */ - private static List<JsniMethod> collectJsniMethods(TreeLogger logger, + private static List<JsniMethod> collectJsniMethods(final TreeLogger logger, String loc, String source, CompiledClass compiledClass, JsProgram program) { - TypeDeclaration typeDecl = compiledClass.getTypeDeclaration(); - int[] lineEnds = typeDecl.compilationResult.getLineSeparatorPositions(); - List<JsniMethod> jsniMethods = new ArrayList<JsniMethod>(); - String enclosingType = compiledClass.getBinaryName().replace('/', '.'); - AbstractMethodDeclaration[] methods = typeDecl.methods; - if (methods != null) { - for (AbstractMethodDeclaration method : methods) { - if (!method.isNative()) { - continue; - } - Interval interval = findJsniSource(source, method); - if (interval == null) { - String msg = "No JavaScript body found for native method '" + method - + "' in type '" + compiledClass.getSourceName() + "'"; - logger.log(TreeLogger.ERROR, msg, null); - continue; - } - - String js = source.substring(interval.start, interval.end); - int startLine = Util.getLineNumber(interval.start, lineEnds, 0, - lineEnds.length - 1); - String jsniSignature = getJsniSignature(enclosingType, method); - String[] paramNames = getParamNames(method); - - jsniMethods.add(new JsniMethodImpl(jsniSignature, js, paramNames, - startLine, loc, program)); + return compiledClass.getJsniMethods(program, new JnsiErrorCallback() { + public boolean reportError(String msg) { + logger.log(TreeLogger.ERROR, msg, null); + return true; } - } - return jsniMethods; + }); } - private static Interval findJsniSource(String source, + static Interval findJsniSource(String source, AbstractMethodDeclaration method) { assert (method.isNative()); int bodyStart = method.bodyStart; @@ -218,7 +194,7 @@ * Gets a unique name for this method and its signature (this is used to * determine whether one method overrides another). */ - private static String getJsniSignature(String enclosingType, + static String getJsniSignature(String enclosingType, AbstractMethodDeclaration method) { return '@' + enclosingType + "::" + getMemberSignature(method); } @@ -241,7 +217,7 @@ return sb.toString(); } - private static String[] getParamNames(AbstractMethodDeclaration method) { + static String[] getParamNames(AbstractMethodDeclaration method) { if (method.arguments != null) { String[] paramNames = new String[method.arguments.length]; for (int i = 0; i < paramNames.length; ++i) { Added: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/SourceCompiledClass.java ============================================================================== --- (empty file) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/SourceCompiledClass.java Wed Feb 4 16:56:06 2009 @@ -0,0 +1,194 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.javac; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.typeinfo.JRealClassType; +import com.google.gwt.dev.javac.JsniCollector.Interval; +import com.google.gwt.dev.javac.JsniCollector.JsniMethodImpl; +import com.google.gwt.dev.javac.impl.Shared; +import com.google.gwt.dev.js.ast.JsProgram; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ClassFile; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +import org.eclipse.jdt.internal.compiler.util.Util; + +import java.util.ArrayList; +import java.util.List; + +/** + * Encapsulates the state of a single compiled class file. + */ +public class SourceCompiledClass extends CompiledClass { + + private static ClassFile getClassFile(TypeDeclaration typeDecl, + String binaryName) { + for (ClassFile tryClassFile : typeDecl.compilationResult().getClassFiles()) { + char[] tryBinaryName = CharOperation.concatWith( + tryClassFile.getCompoundName(), '/'); + if (binaryName.equals(String.valueOf(tryBinaryName))) { + return tryClassFile; + } + } + assert false; + return null; + } + + private static String getPackagePrefix(String packageName) { + return packageName.length() > 0 ? packageName + "." : ""; + } + + protected final byte[] bytes; + protected final String binaryName; + protected final String location; + protected final String packageName; + protected final String sourceName; + + // The state below is transient. + private NameEnvironmentAnswer nameEnvironmentAnswer; + private JRealClassType realClassType; + // Can be killed after parent is CHECKED. + private TypeDeclaration typeDeclaration; + + SourceCompiledClass(CompilationUnit unit, TypeDeclaration typeDeclaration, + CompiledClass enclosingClass) { + super(unit, enclosingClass); + this.typeDeclaration = typeDeclaration; + SourceTypeBinding binding = typeDeclaration.binding; + this.binaryName = CharOperation.charToString(binding.constantPoolName()); + this.packageName = Shared.getPackageNameFromBinary(binaryName); + if (binding instanceof LocalTypeBinding) { + // The source name of a local type must be determined from binary. + String qualifiedName = binaryName.replace('/', '.'); + this.sourceName = qualifiedName.replace('$', '.'); + } else { + this.sourceName = getPackagePrefix(packageName) + + String.valueOf(binding.qualifiedSourceName()); + } + ClassFile classFile = getClassFile(typeDeclaration, binaryName); + this.bytes = classFile.getBytes(); + this.location = String.valueOf(classFile.fileName()); + } + + /** + * Returns the binary class name, e.g. {...@code java/util/Map$Entry}. + */ + @Override + public String getBinaryName() { + return binaryName; + } + + /** + * Returns the bytes of the compiled class. + */ + @Override + public byte[] getBytes() { + return bytes; + } + + /** + * Returns the enclosing package, e.g. {...@code java.util}. + */ + @Override + public String getPackageName() { + return packageName; + } + + /** + * Returns the qualified source name, e.g. {...@code java.util.Map.Entry}. + */ + @Override + public String getSourceName() { + return sourceName; + } + + /** + * All checking is done, free up internal state. + */ + @Override + void checked() { + this.typeDeclaration = null; + } + + NameEnvironmentAnswer getNameEnvironmentAnswer() { + if (nameEnvironmentAnswer == null) { + try { + ClassFileReader cfr = new ClassFileReader(bytes, location.toCharArray()); + nameEnvironmentAnswer = new NameEnvironmentAnswer(cfr, null); + } catch (ClassFormatException e) { + throw new RuntimeException("Unexpectedly unable to parse class file", e); + } + } + return nameEnvironmentAnswer; + } + + TypeDeclaration getTypeDeclaration() { + return typeDeclaration; + } + + @Override + void invalidate() { + nameEnvironmentAnswer = null; + typeDeclaration = null; + super.invalidate(); + } + + @Override + public List<JsniMethod> getJsniMethods(JsProgram program, + JnsiErrorCallback callback) { + TypeDeclaration typeDecl = typeDeclaration; + int[] lineEnds = typeDecl.compilationResult.getLineSeparatorPositions(); + List<JsniMethod> jsniMethods = new ArrayList<JsniMethod>(); + String enclosingType = getBinaryName().replace('/', '.'); + String source = unit.getSource(); + AbstractMethodDeclaration[] methods = typeDecl.methods; + if (methods != null) { + for (AbstractMethodDeclaration method : methods) { + if (!method.isNative()) { + continue; + } + Interval interval = JsniCollector.findJsniSource(source, method); + if (interval == null) { + String msg = "No JavaScript body found for native method '" + method + + "' in type '" + getSourceName() + "'"; + if (callback.reportError(msg)) { + continue; + } else { + break; + } + } + + String js = source.substring(interval.start, interval.end); + int startLine = Util.getLineNumber(interval.start, lineEnds, 0, + lineEnds.length - 1); + String jsniSignature = JsniCollector.getJsniSignature(enclosingType, + method); + String[] paramNames = JsniCollector.getParamNames(method); + + jsniMethods.add(new JsniCollector.JsniMethodImpl(jsniSignature, js, + paramNames, startLine, unit.getDisplayLocation(), program)); + } + } + return jsniMethods; + } +} Modified: changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java ============================================================================== --- changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java (original) +++ changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java Wed Feb 4 16:56:06 2009 @@ -389,12 +389,16 @@ Set<CompiledClass> compiledClasses = unit.getCompiledClasses(); for (CompiledClass compiledClass : compiledClasses) { if (unresolvedTypes.remove(compiledClass.getRealClassType())) { - TypeDeclaration typeDeclaration = compiledClass.getTypeDeclaration(); - if (!resolveTypeDeclaration(cudLogger, unit.getSource(), - typeDeclaration)) { - logger.log(TreeLogger.WARN, - "Unexpectedly unable to fully resolve type " - + compiledClass.getSourceName()); + // TODO(jat): do we need to do anything here for binary classes? + if (compiledClass instanceof SourceCompiledClass) { + SourceCompiledClass srcClass = (SourceCompiledClass) compiledClass; + TypeDeclaration typeDeclaration = srcClass.getTypeDeclaration(); + if (!resolveTypeDeclaration(cudLogger, unit.getSource(), + typeDeclaration)) { + logger.log(TreeLogger.WARN, + "Unexpectedly unable to fully resolve type " + + compiledClass.getSourceName()); + } } } } @@ -475,8 +479,12 @@ realClassType = createType(compiledClass, enclosingType); if (realClassType != null) { unresolvedTypes.add(realClassType); - sourceMapper.put(compiledClass.getTypeDeclaration().binding, - realClassType); + // TODO(jat): anything here for binary classes? + if (compiledClass instanceof SourceCompiledClass) { + SourceCompiledClass srcClass = (SourceCompiledClass) compiledClass; + sourceMapper.put(srcClass.getTypeDeclaration().binding, + realClassType); + } compiledClass.setRealClassType(realClassType); } } @@ -489,6 +497,29 @@ * TypeParameters are mapped into JTypeParameters. */ private JRealClassType createType(CompiledClass compiledClass, + JRealClassType enclosingType) { + if (compiledClass instanceof SourceCompiledClass) { + return createTypeFromSource((SourceCompiledClass) compiledClass, + enclosingType); + } else if (compiledClass instanceof BinaryCompiledClass) { + return createTypeFromClass((BinaryCompiledClass) compiledClass, + enclosingType); + } + return null; + } + + private JRealClassType createTypeFromClass(BinaryCompiledClass compiledClass, + JRealClassType enclosingType) { + // TODO(jat): implement + return null; + } + + /** + * Maps a TypeDeclaration into a JRealClassType. If the TypeDeclaration has + * TypeParameters (i.e, it is a generic type or method), then the + * TypeParameters are mapped into JTypeParameters. + */ + private JRealClassType createTypeFromSource(SourceCompiledClass compiledClass, JRealClassType enclosingType) { TypeDeclaration typeDecl = compiledClass.getTypeDeclaration(); SourceTypeBinding binding = typeDecl.binding; --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---