FLAMING SWORD OF DEATH
Review by: bruce (TBR)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2742 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
index a480c17..a6dee8e 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
@@ -176,14 +176,12 @@
properties = Collections.unmodifiableSortedSet(mutableProperties);
for (Script script : module.getScripts()) {
- artifacts.add(new StandardScriptReference(script.getSrc(),
- module.findPublicFile(script.getSrc())));
+ artifacts.add(new StandardScriptReference(script.getSrc()));
logger.log(TreeLogger.SPAM, "Added script " + script.getSrc(), null);
}
for (String style : module.getStyles()) {
- artifacts.add(new StandardStylesheetReference(style,
- module.findPublicFile(style)));
+ artifacts.add(new StandardStylesheetReference(style));
logger.log(TreeLogger.SPAM, "Added style " + style, null);
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
index 913580c..401b1b8 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
@@ -18,30 +18,24 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.PublicResource;
+import com.google.gwt.dev.resource.Resource;
-import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
/**
* The standard implementation of {@link PublicResource}.
*/
public class StandardPublicResource extends PublicResource {
- private final URL url;
+ private final Resource resource;
- public StandardPublicResource(String partialPath, URL url) {
+ public StandardPublicResource(String partialPath, Resource resource) {
super(StandardLinkerContext.class, partialPath);
- this.url = url;
+ this.resource = resource;
}
@Override
public InputStream getContents(TreeLogger logger)
throws UnableToCompleteException {
- try {
- return url.openStream();
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Unable to open file", e);
- throw new UnableToCompleteException();
- }
+ return resource.openContents();
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardScriptReference.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardScriptReference.java
index 2410e12..79cc00a 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardScriptReference.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardScriptReference.java
@@ -17,18 +17,12 @@
import com.google.gwt.core.ext.linker.ScriptReference;
-import java.net.URL;
-
/**
* The standard implementation of {@link ScriptReference}.
*/
public class StandardScriptReference extends ScriptReference {
- /**
- * Might use <code>url</code>someday.
- */
- @SuppressWarnings("unused")
- public StandardScriptReference(String src, URL url) {
+ public StandardScriptReference(String src) {
super(StandardLinkerContext.class, src);
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardStylesheetReference.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardStylesheetReference.java
index 3e0540b..49211fa 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardStylesheetReference.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardStylesheetReference.java
@@ -17,18 +17,12 @@
import com.google.gwt.core.ext.linker.StylesheetReference;
-import java.net.URL;
-
/**
* The standard implementation of {@link StylesheetReference}.
*/
public class StandardStylesheetReference extends StylesheetReference {
- /**
- * Might use <code>url</code>someday.
- */
- @SuppressWarnings("unused")
- public StandardStylesheetReference(String src, URL url) {
+ public StandardStylesheetReference(String src) {
super(StandardLinkerContext.class, src);
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/CompilationUnitProvider.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/CompilationUnitProvider.java
deleted file mode 100644
index 4d2aa8a..0000000
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/CompilationUnitProvider.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.core.ext.typeinfo;
-
-import com.google.gwt.core.ext.UnableToCompleteException;
-
-import java.util.Comparator;
-
-/**
- * Provides information about a single compilation unit on demand.
- */
-public interface CompilationUnitProvider {
-
- Comparator<CompilationUnitProvider> LOCATION_COMPARATOR = new Comparator<CompilationUnitProvider>() {
- public int compare(CompilationUnitProvider cups1,
- CompilationUnitProvider cups2) {
- String loc1 = cups1.getLocation();
- String loc2 = cups2.getLocation();
- return loc1.compareTo(loc2);
- }
- };
-
- long getLastModified() throws UnableToCompleteException;
-
- String getLocation();
-
- /**
- * Returns the, not <code>null</code>, name of the top level public type.
- *
- */
- String getMainTypeName();
-
- String getPackageName();
-
- char[] getSource() throws UnableToCompleteException;
-
- boolean isTransient();
-}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
index 8d931c6..aa54e64 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
@@ -28,14 +28,6 @@
private final Annotations annotations;
- private int bodyEnd;
-
- private int bodyStart;
-
- private final int declEnd;
-
- private final int declStart;
-
private boolean isVarArgs = false;
private final HasMetaData metaData = new MetaData();
@@ -52,10 +44,6 @@
JAbstractMethod(JAbstractMethod srcMethod) {
this.annotations = new Annotations(srcMethod.annotations);
- this.bodyEnd = srcMethod.bodyEnd;
- this.bodyStart = srcMethod.bodyStart;
- this.declEnd = srcMethod.declEnd;
- this.declStart = srcMethod.declStart;
this.isVarArgs = srcMethod.isVarArgs;
MetaData.copy(this, srcMethod.metaData);
this.modifierBits = srcMethod.modifierBits;
@@ -63,21 +51,16 @@
}
// Only the builder can construct
- JAbstractMethod(String name, int declStart, int declEnd, int bodyStart,
- int bodyEnd,
+ JAbstractMethod(String name,
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
JTypeParameter[] jtypeParameters) {
this.name = name;
- this.declStart = declStart;
- this.declEnd = declEnd;
- this.bodyStart = bodyStart;
- this.bodyEnd = bodyEnd;
annotations = new Annotations();
annotations.addAnnotations(declaredAnnotations);
-
+
if (jtypeParameters != null) {
for (JTypeParameter jtypeParameter : jtypeParameters) {
- addTypeParameter(jtypeParameter);
+ addTypeParameter(jtypeParameter);
}
}
}
@@ -108,22 +91,6 @@
return annotations.getAnnotation(annotationClass);
}
- public int getBodyEnd() {
- return bodyEnd;
- }
-
- public int getBodyStart() {
- return bodyStart;
- }
-
- public int getDeclEnd() {
- return declEnd;
- }
-
- public int getDeclStart() {
- return declStart;
- }
-
/**
* Gets the type in which this method or constructor was declared.
*/
@@ -281,8 +248,8 @@
}
return true;
}
-
+
private void addTypeParameter(JTypeParameter typeParameter) {
typeParams.add(typeParameter);
- }
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java
index 4b74e4f..4896191 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationMethod.java
@@ -29,11 +29,9 @@
private final Object defaultValue;
public JAnnotationMethod(JClassType enclosingType, String name,
- int declStart, int declEnd, int bodyStart, int bodyEnd,
Object defaultValue,
Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
- super(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd,
- declaredAnnotations, null);
+ super(enclosingType, name, declaredAnnotations, null);
this.defaultValue = defaultValue;
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationType.java
index fbec74e..912e20e 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JAnnotationType.java
@@ -22,12 +22,11 @@
*/
public class JAnnotationType extends JRealClassType {
- public JAnnotationType(TypeOracle oracle, CompilationUnitProvider cup,
- JPackage declaringPackage, JClassType enclosingType, boolean isLocalType,
- String name, int declStart, int declEnd, int bodyStart, int bodyEnd,
+ public JAnnotationType(TypeOracle oracle, JPackage declaringPackage,
+ JClassType enclosingType, boolean isLocalType, String name,
boolean isInterface) {
- super(oracle, cup, declaringPackage, enclosingType, isLocalType, name,
- declStart, declEnd, bodyStart, bodyEnd, isInterface);
+ super(oracle, declaringPackage, enclosingType, isLocalType, name,
+ isInterface);
}
@Override
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
index f66cd10..f238f41 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.core.ext.typeinfo;
-import com.google.gwt.core.ext.UnableToCompleteException;
-
import java.lang.annotation.Annotation;
import java.util.Map;
@@ -82,21 +80,6 @@
return null;
}
- @Override
- public int getBodyEnd() {
- return 0;
- }
-
- @Override
- public int getBodyStart() {
- return 0;
- }
-
- @Override
- public CompilationUnitProvider getCompilationUnit() {
- return null;
- }
-
public JType getComponentType() {
return componentType;
}
@@ -113,16 +96,6 @@
}
@Override
- public int getDeclEnd() {
- return 0;
- }
-
- @Override
- public int getDeclStart() {
- return 0;
- }
-
- @Override
public JClassType getEnclosingType() {
return null;
}
@@ -272,20 +245,6 @@
}
@Override
- public String getTypeHash() throws UnableToCompleteException {
- JType leafType = getLeafType();
- JClassType leafClassType = leafType.isClassOrInterface();
- if (leafClassType != null) {
- return leafClassType.getTypeHash();
- }
-
- // Arrays of primitive types should have a stable hash
- assert (leafType.isPrimitive() != null);
-
- return leafType.getQualifiedSourceName();
- }
-
- @Override
public boolean isAbstract() {
return false;
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
index 569e25d..eeb18ce 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.core.ext.typeinfo;
-import com.google.gwt.core.ext.UnableToCompleteException;
-
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Map;
@@ -338,21 +336,11 @@
public abstract <T extends Annotation> T getAnnotation(
Class<T> annotationClass);
- public abstract int getBodyEnd();
-
- public abstract int getBodyStart();
-
- public abstract CompilationUnitProvider getCompilationUnit();
-
public abstract JConstructor getConstructor(JType[] paramTypes)
throws NotFoundException;
public abstract JConstructor[] getConstructors();
- public abstract int getDeclEnd();
-
- public abstract int getDeclStart();
-
public abstract JClassType getEnclosingType();
public abstract JClassType getErasedType();
@@ -412,8 +400,6 @@
public abstract JClassType getSuperclass();
- public abstract String getTypeHash() throws UnableToCompleteException;
-
public abstract boolean isAbstract();
public abstract boolean isAnnotationPresent(
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java
index a52b4e1..5767abc 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JConstructor.java
@@ -24,18 +24,15 @@
public class JConstructor extends JAbstractMethod {
private final JClassType enclosingType;
- public JConstructor(JClassType enclosingType, String name, int declStart,
- int declEnd, int bodyStart, int bodyEnd) {
- this(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, null, null);
+ public JConstructor(JClassType enclosingType, String name) {
+ this(enclosingType, name, null, null);
}
- public JConstructor(JClassType enclosingType, String name, int declStart,
- int declEnd, int bodyStart, int bodyEnd,
+ public JConstructor(JClassType enclosingType, String name,
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
JTypeParameter[] jtypeParameters) {
- super(name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations,
- jtypeParameters);
-
+ super(name, declaredAnnotations, jtypeParameters);
+
this.enclosingType = enclosingType;
enclosingType.addConstructor(this);
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
index ad16306..3f3e0d4 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JDelegatingClassType.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.core.ext.typeinfo;
-import com.google.gwt.core.ext.UnableToCompleteException;
-
import java.lang.annotation.Annotation;
import java.util.Map;
@@ -83,21 +81,6 @@
return baseType;
}
- @Override
- public int getBodyEnd() {
- return baseType.getBodyEnd();
- }
-
- @Override
- public int getBodyStart() {
- return baseType.getBodyStart();
- }
-
- @Override
- public CompilationUnitProvider getCompilationUnit() {
- return baseType.getCompilationUnit();
- }
-
/**
* Delegating types generally cannot be constructed.
*/
@@ -116,16 +99,6 @@
}
@Override
- public int getDeclEnd() {
- return baseType.getDeclEnd();
- }
-
- @Override
- public int getDeclStart() {
- return baseType.getDeclStart();
- }
-
- @Override
public JClassType getEnclosingType() {
// TODO this can be wrong if the enclosing type is a parameterized type. For
// example, if a generic class has a non-static generic inner class.
@@ -228,11 +201,6 @@
}
@Override
- public String getTypeHash() throws UnableToCompleteException {
- return baseType.getTypeHash();
- }
-
- @Override
public int hashCode() {
return baseType.hashCode();
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java
index 6097392..7989c03 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JEnumType.java
@@ -37,12 +37,11 @@
* @param bodyEnd
* @param isInterface
*/
- public JEnumType(TypeOracle oracle, CompilationUnitProvider cup,
- JPackage declaringPackage, JClassType enclosingType, boolean isLocalType,
- String name, int declStart, int declEnd, int bodyStart, int bodyEnd,
+ public JEnumType(TypeOracle oracle, JPackage declaringPackage,
+ JClassType enclosingType, boolean isLocalType, String name,
boolean isInterface) {
- super(oracle, cup, declaringPackage, enclosingType, isLocalType, name,
- declStart, declEnd, bodyStart, bodyEnd, isInterface);
+ super(oracle, declaringPackage, enclosingType, isLocalType, name,
+ isInterface);
}
/**
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
index d6a2173..a1286dc 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JGenericType.java
@@ -27,16 +27,15 @@
private final List<JTypeParameter> typeParams = new ArrayList<JTypeParameter>();
- public JGenericType(TypeOracle oracle, CompilationUnitProvider cup,
- JPackage declaringPackage, JClassType enclosingType, boolean isLocalType,
- String name, int declStart, int declEnd, int bodyStart, int bodyEnd,
+ public JGenericType(TypeOracle oracle, JPackage declaringPackage,
+ JClassType enclosingType, boolean isLocalType, String name,
boolean isInterface, JTypeParameter[] jtypeParameters) {
- super(oracle, cup, declaringPackage, enclosingType, isLocalType, name,
- declStart, declEnd, bodyStart, bodyEnd, isInterface);
-
- if (jtypeParameters != null) {
+ super(oracle, declaringPackage, enclosingType, isLocalType, name,
+ isInterface);
+
+ if (jtypeParameters != null) {
for (JTypeParameter jtypeParameter : jtypeParameters) {
- addTypeParameter(jtypeParameter);
+ addTypeParameter(jtypeParameter);
}
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java
index 3bcdb7d..8de3b43 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JMethod.java
@@ -27,18 +27,14 @@
private JType returnType;
- public JMethod(JClassType enclosingType, String name, int declStart,
- int declEnd, int bodyStart, int bodyEnd) {
- this(enclosingType, name, declStart, declEnd, bodyStart, bodyEnd, null,
- null);
+ public JMethod(JClassType enclosingType, String name) {
+ this(enclosingType, name, null, null);
}
- public JMethod(JClassType enclosingType, String name, int declStart,
- int declEnd, int bodyStart, int bodyEnd,
+ public JMethod(JClassType enclosingType, String name,
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
JTypeParameter[] jtypeParameters) {
- super(name, declStart, declEnd, bodyStart, bodyEnd, declaredAnnotations,
- jtypeParameters);
+ super(name, declaredAnnotations, jtypeParameters);
this.enclosingType = enclosingType;
enclosingType.addMethod(this);
}
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
index be91bc0..13329a8 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -15,10 +15,6 @@
*/
package com.google.gwt.core.ext.typeinfo;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.util.Util;
-
-import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashSet;
@@ -35,18 +31,8 @@
private final Annotations annotations = new Annotations();
- private final int bodyEnd;
-
- private final int bodyStart;
-
- private final CompilationUnitProvider cup;
-
private final JPackage declaringPackage;
- private final int declEnd;
-
- private final int declStart;
-
private final JClassType enclosingType;
private final List<JClassType> interfaces = new ArrayList<JClassType>();
@@ -55,8 +41,6 @@
private final boolean isLocalType;
- private String lazyHash;
-
private String lazyQualifiedName;
private final AbstractMembers members = new Members(this);
@@ -73,21 +57,14 @@
private JClassType superclass;
- public JRealClassType(TypeOracle oracle, CompilationUnitProvider cup,
- JPackage declaringPackage, JClassType enclosingType, boolean isLocalType,
- String name, int declStart, int declEnd, int bodyStart, int bodyEnd,
+ public JRealClassType(TypeOracle oracle, JPackage declaringPackage,
+ JClassType enclosingType, boolean isLocalType, String name,
boolean isInterface) {
- oracle.recordTypeInCompilationUnit(cup, this);
this.oracle = oracle;
- this.cup = cup;
this.declaringPackage = declaringPackage;
this.enclosingType = enclosingType;
this.isLocalType = isLocalType;
this.name = name;
- this.declStart = declStart;
- this.declEnd = declEnd;
- this.bodyStart = bodyStart;
- this.bodyEnd = bodyEnd;
this.isInterface = isInterface;
if (enclosingType == null) {
// Add myself to my package.
@@ -155,18 +132,6 @@
return annotations.getAnnotation(annotationClass);
}
- public int getBodyEnd() {
- return bodyEnd;
- }
-
- public int getBodyStart() {
- return bodyStart;
- }
-
- public CompilationUnitProvider getCompilationUnit() {
- return cup;
- }
-
@Override
public JConstructor getConstructor(JType[] paramTypes)
throws NotFoundException {
@@ -178,14 +143,6 @@
return members.getConstructors();
}
- public int getDeclEnd() {
- return declEnd;
- }
-
- public int getDeclStart() {
- return declStart;
- }
-
public JClassType getEnclosingType() {
return enclosingType;
}
@@ -298,19 +255,11 @@
return superclass;
}
- public String getTypeHash() throws UnableToCompleteException {
- if (lazyHash == null) {
- char[] source = cup.getSource();
- int length = declEnd - declStart + 1;
- String s = new String(source, declStart, length);
- try {
- lazyHash = Util.computeStrongName(s.getBytes(Util.DEFAULT_ENCODING));
- } catch (UnsupportedEncodingException e) {
- // Details, details...
- throw new UnableToCompleteException();
- }
- }
- return lazyHash;
+ /**
+ * TODO: solve this better.
+ */
+ public void invalidate() {
+ oracle.invalidate(this);
}
public boolean isAbstract() {
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
index 8105085..fdc7a64 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
@@ -143,7 +143,7 @@
* @return true if the type has been invalidated
*/
private static boolean isInvalidatedTypeRecursive(JType type,
- Set<JClassType> invalidTypes) {
+ Set<JRealClassType> invalidTypes) {
if (type instanceof JParameterizedType) {
JParameterizedType parameterizedType = (JParameterizedType) type;
if (isInvalidatedTypeRecursive(parameterizedType.getBaseType(),
@@ -168,6 +168,8 @@
private final Map<JType, JArrayType> arrayTypes = new IdentityHashMap<JType, JArrayType>();
+ private final Set<JRealClassType> invalidatedTypes = new HashSet<JRealClassType>();
+
private JClassType javaLangObject;
private final Map<String, JPackage> packages = new HashMap<String, JPackage>();
@@ -176,8 +178,6 @@
private int reloadCount = 0;
- private final Map<CompilationUnitProvider, JClassType[]> typesByCup = new IdentityHashMap<CompilationUnitProvider, JClassType[]>();
-
private final Map<String, List<JWildcardType>> wildcardTypes = new HashMap<String, List<JWildcardType>>();
public TypeOracle() {
@@ -267,6 +267,7 @@
* <code>java.lang.Object</code>.
*/
public JClassType getJavaLangObject() {
+ assert javaLangObject != null;
return javaLangObject;
}
@@ -347,7 +348,7 @@
throw new IllegalArgumentException("Generic type '"
+ genericType.getParameterizedQualifiedSourceName()
+ "' is a non-static member type, but the enclosing type '"
- + enclosingType.getQualifiedSourceName()
+ + enclosingType.getQualifiedSourceName()
+ "' is not a parameterized or raw type");
}
}
@@ -459,22 +460,13 @@
JPackage pkg = pkgs[i];
JClassType[] types = pkg.getTypes();
for (int j = 0; j < types.length; j++) {
- JClassType type = types[j];
+ JRealClassType type = (JRealClassType) types[j];
buildAllTypesImpl(allTypes, type);
}
}
return allTypes.toArray(NO_JCLASSES);
}
- public JClassType[] getTypesInCompilationUnit(CompilationUnitProvider cup) {
- JClassType[] types = typesByCup.get(cup);
- if (types != null) {
- return types;
- } else {
- return NO_JCLASSES;
- }
- }
-
public JWildcardType getWildcardType(JWildcardType.BoundType boundType,
JClassType typeBound) {
JWildcardType wildcardType = new JWildcardType(boundType, typeBound);
@@ -528,6 +520,42 @@
}
/**
+ * Updates relationships within this type oracle. Should be called after any
+ * changes are made.
+ *
+ * <p>
+ * Throws <code>TypeOracleException</code> thrown if fundamental baseline
+ * correctness criteria are violated, most notably the absence of
+ * "java.lang.Object"
+ * </p>
+ *
+ * TODO: make this not public.
+ */
+ public void refresh(TreeLogger logger) throws NotFoundException {
+ if (javaLangObject == null) {
+ javaLangObject = findType("java.lang.Object");
+ if (javaLangObject == null) {
+ throw new NotFoundException("java.lang.Object");
+ }
+ }
+ computeHierarchyRelationships();
+ consumeTypeArgMetaData(logger);
+ }
+
+ /**
+ * Removes all types that are no longer valid.
+ *
+ * TODO: make not public?
+ */
+ public void removeInvalidatedTypes() {
+ if (!invalidatedTypes.isEmpty()) {
+ invalidateTypes(invalidatedTypes);
+ invalidatedTypes.clear();
+ ++reloadCount;
+ }
+ }
+
+ /**
* Convenience method to sort class types in a consistent way. Note that the
* order is subject to change and is intended to generate an "aesthetically
* pleasing" order rather than a computationally reliable order.
@@ -586,77 +614,16 @@
});
}
- void incrementReloadCount() {
- reloadCount++;
+ void invalidate(JRealClassType realClassType) {
+ invalidatedTypes.add(realClassType);
}
- /**
- * Note, this method is called reflectively from the
- * {@link com.google.gwt.dev.jdt.CacheManager#invalidateOnRefresh(TypeOracle)}.
- *
- * @param cup compilation unit whose types will be invalidated
- */
- void invalidateTypesInCompilationUnit(CompilationUnitProvider cup) {
- Set<JClassType> invalidTypes = new HashSet<JClassType>();
- JClassType[] types = typesByCup.get(cup);
- if (types == null) {
- return;
- }
-
- for (int i = 0; i < types.length; i++) {
- JClassType classTypeToInvalidate = types[i];
- invalidTypes.add(classTypeToInvalidate);
- }
-
- typesByCup.remove(cup);
-
- removeInvalidatedArrayTypes(invalidTypes);
-
- removeInvalidatedParameterizedTypes(invalidTypes);
-
- removeTypes(invalidTypes);
- }
-
- void recordTypeInCompilationUnit(CompilationUnitProvider cup, JClassType type) {
- JClassType[] types = typesByCup.get(cup);
- if (types == null) {
- types = new JClassType[] {type};
- } else {
- JClassType[] temp = new JClassType[types.length + 1];
- System.arraycopy(types, 0, temp, 0, types.length);
- temp[types.length] = type;
- types = temp;
- }
- typesByCup.put(cup, types);
- }
-
- /**
- * Updates relationships within this type oracle. Should be called after any
- * changes are made.
- *
- * <p>
- * Throws <code>TypeOracleException</code> thrown if fundamental baseline
- * correctness criteria are violated, most notably the absence of
- * "java.lang.Object"
- * </p>
- */
- void refresh(TreeLogger logger) throws NotFoundException {
- if (javaLangObject == null) {
- javaLangObject = findType("java.lang.Object");
- if (javaLangObject == null) {
- throw new NotFoundException("java.lang.Object");
- }
- }
- computeHierarchyRelationships();
- consumeTypeArgMetaData(logger);
- }
-
- private void buildAllTypesImpl(Set<JClassType> allTypes, JClassType type) {
+ private void buildAllTypesImpl(Set<JClassType> allTypes, JRealClassType type) {
boolean didAdd = allTypes.add(type);
assert (didAdd);
JClassType[] nestedTypes = type.getNestedTypes();
for (int i = 0; i < nestedTypes.length; i++) {
- JClassType nestedType = nestedTypes[i];
+ JRealClassType nestedType = (JRealClassType) nestedTypes[i];
buildAllTypesImpl(allTypes, nestedType);
}
}
@@ -843,6 +810,12 @@
return resultingType;
}
+ private void invalidateTypes(Set<JRealClassType> invalidTypes) {
+ removeInvalidatedArrayTypes(invalidTypes);
+ removeInvalidatedParameterizedTypes(invalidTypes);
+ removeTypes(invalidTypes);
+ }
+
private JType parseImpl(String type) throws NotFoundException,
ParseException, BadTypeArgsException {
if (type.endsWith("[]")) {
@@ -991,7 +964,7 @@
*
* @param invalidTypes set of types that have been invalidated.
*/
- private void removeInvalidatedArrayTypes(Set<JClassType> invalidTypes) {
+ private void removeInvalidatedArrayTypes(Set<JRealClassType> invalidTypes) {
arrayTypes.keySet().removeAll(invalidTypes);
}
@@ -1001,7 +974,8 @@
*
* @param invalidTypes set of types known to have been invalidated
*/
- private void removeInvalidatedParameterizedTypes(Set<JClassType> invalidTypes) {
+ private void removeInvalidatedParameterizedTypes(
+ Set<JRealClassType> invalidTypes) {
Iterator<List<JParameterizedType>> listIterator = parameterizedTypes.values().iterator();
while (listIterator.hasNext()) {
@@ -1021,10 +995,8 @@
*
* @param invalidTypes set of types to remove
*/
- private void removeTypes(Set<JClassType> invalidTypes) {
- Iterator<JClassType> iter = invalidTypes.iterator();
-
- while (iter.hasNext()) {
+ private void removeTypes(Set<JRealClassType> invalidTypes) {
+ for (Iterator<JRealClassType> iter = invalidTypes.iterator(); iter.hasNext();) {
JClassType classType = iter.next();
JPackage pkg = classType.getPackage();
if (pkg != null) {
@@ -1032,6 +1004,7 @@
}
classType.removeFromSupertypes();
+ iter.remove();
}
}
}
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index a83801e..7505c9f 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -22,9 +22,7 @@
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.impl.StandardCompilationResult;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.Properties;
@@ -32,9 +30,9 @@
import com.google.gwt.dev.cfg.PropertyPermutations;
import com.google.gwt.dev.cfg.Rules;
import com.google.gwt.dev.cfg.StaticPropertyOracle;
-import com.google.gwt.dev.jdt.CacheManager;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.jdt.RebindPermutationOracle;
-import com.google.gwt.dev.jdt.StandardSourceOracle;
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
@@ -122,8 +120,8 @@
private final Map<String, String> cache = new HashMap<String, String>();
public CompilationRebindOracle(ArtifactSet generatorArtifacts) {
- super(typeOracle, propOracle, module, rules, genDir,
- generatorResourcesDir, cacheManager, generatorArtifacts);
+ super(compilationState, propOracle, module, rules, genDir,
+ generatorResourcesDir, generatorArtifacts);
}
/**
@@ -146,31 +144,8 @@
String msg = "Rebind answer for '" + in + "' found in cache " + out;
logger.log(TreeLogger.DEBUG, msg, null);
}
-
- if (recordDecision(in, out)) {
- List<JClassType> genTypes = generatedTypesByResultTypeName.get(out);
- if (genTypes != null) {
- for (JClassType genType : genTypes) {
- String sourceHash = genType.getTypeHash();
- String genTypeName = genType.getQualifiedSourceName();
- recordGeneratedTypeHash(genTypeName, sourceHash);
- }
- }
- }
-
return out;
}
-
- @SuppressWarnings("unused")
- protected boolean recordDecision(String in, String out) {
- // TODO(bobv): consider caching compilations again?
- return false;
- }
-
- @SuppressWarnings("unused")
- protected void recordGeneratedTypeHash(String typeName, String sourceHash) {
- // TODO(bobv): consider caching compilations again?
- }
}
private class DistillerRebindPermutationOracle implements
@@ -179,9 +154,8 @@
private final StandardRebindOracle rebindOracle;
public DistillerRebindPermutationOracle(ArtifactSet generatorArtifacts) {
- rebindOracle = new StandardRebindOracle(typeOracle, propOracle, module,
- rules, genDir, generatorResourcesDir, cacheManager,
- generatorArtifacts) {
+ rebindOracle = new StandardRebindOracle(compilationState, propOracle,
+ module, rules, genDir, generatorResourcesDir, generatorArtifacts) {
/**
* Record generated types.
@@ -246,20 +220,7 @@
System.exit(1);
}
- /**
- * Returns the fully-qualified main type name of a compilation unit.
- */
- private static String makeTypeName(CompilationUnitProvider cup) {
- if (cup.getPackageName().length() > 0) {
- return cup.getPackageName() + "." + cup.getMainTypeName();
- } else {
- return cup.getMainTypeName();
- }
- }
-
- private final CacheManager cacheManager;
-
- private File generatorResourcesDir;
+ private CompilationState compilationState;
private String[] declEntryPts;
@@ -267,6 +228,8 @@
private Map<String, List<JClassType>> generatedTypesByResultTypeName = new HashMap<String, List<JClassType>>();
+ private File generatorResourcesDir;
+
private JavaToJavaScriptCompiler jjs;
private JJSOptions jjsOptions = new JJSOptions();
@@ -289,17 +252,9 @@
private Rules rules;
- private StandardSourceOracle sourceOracle;
-
- private TypeOracle typeOracle;
-
private boolean useGuiLogger;
public GWTCompiler() {
- this(null);
- }
-
- public GWTCompiler(CacheManager cacheManager) {
registerHandler(new ArgHandlerLogLevel() {
@Override
public void setLogLevel(Type level) {
@@ -344,13 +299,12 @@
});
registerHandler(new ArgHandlerValidateOnlyFlag());
-
- this.cacheManager = cacheManager;
}
public void distill(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException {
this.module = moduleDef;
+ this.compilationState = moduleDef.getCompilationState();
// Set up all the initial state.
checkModule(logger);
@@ -369,18 +323,20 @@
Util.recursiveDelete(generatorResourcesDir, true);
generatorResourcesDir.mkdirs();
+ // TODO: All JDT checks now before even building TypeOracle?
+ compilationState.compile(logger);
+
rules = module.getRules();
- typeOracle = module.getTypeOracle(logger);
- sourceOracle = new StandardSourceOracle(typeOracle);
if (jjsOptions.isValidateOnly()) {
+ // TODO: revisit this.. do we even need to run JJS?
logger.log(TreeLogger.INFO, "Validating compilation " + module.getName(),
null);
// Pretend that every single compilation unit is an entry point.
- CompilationUnitProvider[] compilationUnits = module.getCompilationUnits();
- declEntryPts = new String[compilationUnits.length];
- for (int i = 0; i < compilationUnits.length; ++i) {
- CompilationUnitProvider cup = compilationUnits[i];
- declEntryPts[i] = makeTypeName(cup);
+ Set<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
+ declEntryPts = new String[compilationUnits.size()];
+ int i = 0;
+ for (CompilationUnit unit : compilationUnits) {
+ declEntryPts[i++] = unit.getTypeName();
}
} else {
logger.log(TreeLogger.INFO, "Compiling module " + module.getName(), null);
@@ -393,7 +349,7 @@
properties = module.getProperties();
perms = new PropertyPermutations(properties);
WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
- sourceOracle, rebindPermOracle);
+ compilationState, rebindPermOracle);
jjs = new JavaToJavaScriptCompiler(logger, frontEnd, declEntryPts,
jjsOptions);
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index f22c3ef..61ba6ad 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -160,27 +160,6 @@
}
/**
- * handles the -saveJsni command line flag.
- */
- protected class ArgHandlerSaveJsni extends ArgHandlerFlag {
- @Override
- public String getPurpose() {
- return "Save generated JSNI source in the supplied gen directory (if any)";
- }
-
- @Override
- public String getTag() {
- return "-saveJsni";
- }
-
- @Override
- public boolean setFlag() {
- saveJsni = true;
- return true;
- }
- }
-
- /**
* Handles the list of startup urls that can be passed on the command line.
*/
protected class ArgHandlerStartupURLs extends ArgHandlerExtra {
@@ -403,8 +382,6 @@
private boolean runTomcat = true;
- private boolean saveJsni = false;
-
private boolean started;
private final List<String> startupUrls = new ArrayList<String>();
@@ -442,8 +419,6 @@
}
});
- registerHandler(new ArgHandlerSaveJsni());
-
if (!noURLs) {
registerHandler(new ArgHandlerStartupURLs());
}
@@ -644,7 +619,7 @@
*/
protected void compile(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException {
- GWTCompiler compiler = new GWTCompiler(moduleDef.getCacheManager());
+ GWTCompiler compiler = new GWTCompiler();
compiler.setCompilerOptions(jjsOptions);
compiler.setGenDir(genDir);
compiler.setOutDir(outDir);
@@ -668,7 +643,7 @@
TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef,
File genDir, File shellDir) {
return new ShellModuleSpaceHost(logger, typeOracle, moduleDef, genDir,
- shellDir, saveJsni);
+ shellDir);
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index e716af6..9cddd07 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -20,22 +20,23 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.CacheManager;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
-import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.JavaSourceFile;
+import com.google.gwt.dev.javac.JavaSourceOracle;
+import com.google.gwt.dev.javac.impl.JavaSourceOracleImpl;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.impl.PathPrefix;
+import com.google.gwt.dev.resource.impl.PathPrefixSet;
+import com.google.gwt.dev.resource.impl.ResourceFilter;
+import com.google.gwt.dev.resource.impl.ResourceOracleImpl;
import com.google.gwt.dev.util.Empty;
-import com.google.gwt.dev.util.FileOracle;
-import com.google.gwt.dev.util.FileOracleFactory;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
-import com.google.gwt.dev.util.FileOracleFactory.FileFilter;
import org.apache.tools.ant.types.ZipScanner;
import java.io.File;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -84,22 +85,17 @@
private Class<? extends Linker> activePrimaryLinker;
- private final ArrayList<URLCompilationUnitProvider> allCups = new ArrayList<URLCompilationUnitProvider>();
-
- private final Set<String> alreadySeenFiles = new HashSet<String>();
-
- private final CacheManager cacheManager = new CacheManager(".gwt-cache",
- new TypeOracle());
-
- private CompilationUnitProvider[] cups = new CompilationUnitProvider[0];
+ private CompilationState compilationState;
private final List<String> entryPointTypeNames = new ArrayList<String>();
private final Set<File> gwtXmlFiles = new HashSet<File>();
- private FileOracle lazyPublicOracle;
+ private JavaSourceOracle lazyJavaSourceOracle;
- private FileOracle lazySourceOracle;
+ private ResourceOracleImpl lazyPublicOracle;
+
+ private ResourceOracleImpl lazySourceOracle;
private TypeOracle lazyTypeOracle;
@@ -117,7 +113,7 @@
private final Properties properties = new Properties();
- private final FileOracleFactory publicPathEntries = new FileOracleFactory();
+ private PathPrefixSet publicPrefixSet = new PathPrefixSet();
private final Rules rules = new Rules();
@@ -125,7 +121,7 @@
private final Map<String, String> servletClassNamesByPath = new HashMap<String, String>();
- private final FileOracleFactory sourcePathEntries = new FileOracleFactory();
+ private PathPrefixSet sourcePrefixSet = new PathPrefixSet();
private final Styles styles = new Styles();
@@ -164,12 +160,11 @@
final ZipScanner scanner = getScanner(includeList, excludeList,
defaultExcludes, caseSensitive);
- // index from this package down
- publicPathEntries.addRootPackage(publicPackage, new FileFilter() {
- public boolean accept(String name) {
- return scanner.match(name);
+ publicPrefixSet.add(new PathPrefix(publicPackage, new ResourceFilter() {
+ public boolean allows(String path) {
+ return scanner.match(path);
}
- });
+ }, true));
}
public void addSourcePackage(String sourcePackage, String[] includeList,
@@ -195,17 +190,15 @@
final ZipScanner scanner = getScanner(includeList, excludeList,
defaultExcludes, caseSensitive);
- final FileFilter sourceFileFilter = new FileFilter() {
- public boolean accept(String name) {
- return scanner.match(name);
+ ResourceFilter sourceFileFilter = new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith(".java") && scanner.match(path);
}
};
- if (isSuperSource) {
- sourcePathEntries.addRootPackage(sourcePackage, sourceFileFilter);
- } else {
- sourcePathEntries.addPackage(sourcePackage, sourceFileFilter);
- }
+ PathPrefix pathPrefix = new PathPrefix(sourcePackage, sourceFileFilter,
+ isSuperSource);
+ sourcePrefixSet.add(pathPrefix);
}
public void addSuperSourcePackage(String superSourcePackage,
@@ -223,13 +216,12 @@
linkerTypesByName.put(name, linker);
}
- public synchronized URL findPublicFile(String partialPath) {
- return lazyPublicOracle.find(partialPath);
+ public synchronized Resource findPublicFile(String partialPath) {
+ return lazyPublicOracle.getResourceMap().get(partialPath);
}
public synchronized String findServletForPath(String actual) {
// Walk in backwards sorted order to find the longest path match first.
- //
Set<Entry<String, String>> entrySet = servletClassNamesByPath.entrySet();
Entry<String, String>[] entries = Util.toArray(Entry.class, entrySet);
Arrays.sort(entries, REV_NAME_CMP);
@@ -257,11 +249,7 @@
}
public String[] getAllPublicFiles() {
- return lazyPublicOracle.getAllFiles();
- }
-
- public CacheManager getCacheManager() {
- return cacheManager;
+ return lazyPublicOracle.getPathNames().toArray(Empty.STRINGS);
}
/**
@@ -272,8 +260,8 @@
return name;
}
- public synchronized CompilationUnitProvider[] getCompilationUnits() {
- return cups;
+ public CompilationState getCompilationState() {
+ return compilationState;
}
public synchronized String[] getEntryPointTypeNames() {
@@ -332,7 +320,8 @@
public synchronized TypeOracle getTypeOracle(TreeLogger logger)
throws UnableToCompleteException {
if (lazyTypeOracle == null) {
- lazyTypeOracle = createTypeOracle(logger);
+ lazyTypeOracle = compilationState.getTypeOracle();
+ updateTypeOracle(logger);
}
return lazyTypeOracle;
}
@@ -363,11 +352,17 @@
public synchronized void refresh(TreeLogger logger)
throws UnableToCompleteException {
PerfLogger.start("ModuleDef.refresh");
- cacheManager.invalidateVolatileFiles();
- normalize(logger);
- lazyTypeOracle = createTypeOracle(logger);
- Util.invokeInaccessableMethod(TypeOracle.class, "incrementReloadCount",
- new Class[] {}, lazyTypeOracle, new Object[] {});
+
+ // Refresh the public path.
+ lazyPublicOracle.refresh(logger);
+
+ // Refreshes source internally.
+ compilationState.refresh();
+
+ // Refresh type oracle if needed.
+ if (lazyTypeOracle != null) {
+ updateTypeOracle(logger);
+ }
PerfLogger.end();
}
@@ -388,8 +383,8 @@
* @param partialPath
* @return
*/
- synchronized URL findSourceFile(String partialPath) {
- return lazySourceOracle.find(partialPath);
+ synchronized JavaSourceFile findSourceFile(String partialPath) {
+ return lazyJavaSourceOracle.getSourceMap().get(partialPath);
}
/**
@@ -424,111 +419,32 @@
}
}
- // Create the source path.
- //
- TreeLogger branch = Messages.SOURCE_PATH_LOCATIONS.branch(logger, null);
- lazySourceOracle = sourcePathEntries.create(branch);
+ // Create the public path.
+ TreeLogger branch = Messages.PUBLIC_PATH_LOCATIONS.branch(logger, null);
+ // lazyPublicOracle = publicPathEntries.create(branch);
+ if (lazyPublicOracle == null) {
+ lazyPublicOracle = new ResourceOracleImpl(branch);
+ lazyPublicOracle.setPathPrefixes(publicPrefixSet);
+ }
+ lazyPublicOracle.refresh(branch);
- if (lazySourceOracle.isEmpty()) {
+ // Create the source path.
+ branch = Messages.SOURCE_PATH_LOCATIONS.branch(logger, null);
+ lazySourceOracle = new ResourceOracleImpl(branch);
+ lazySourceOracle.setPathPrefixes(sourcePrefixSet);
+ lazySourceOracle.refresh(branch);
+ if (lazySourceOracle.getResources().isEmpty()) {
branch.log(TreeLogger.WARN,
"No source path entries; expect subsequent failures", null);
- } else {
- // Create the CUPs
- String[] allFiles = lazySourceOracle.getAllFiles();
- Set<String> files = new HashSet<String>();
- files.addAll(Arrays.asList(allFiles));
- files.removeAll(alreadySeenFiles);
- for (Iterator<String> iter = files.iterator(); iter.hasNext();) {
- String fileName = iter.next();
- int pos = fileName.lastIndexOf('/');
- String packageName;
- if (pos >= 0) {
- packageName = fileName.substring(0, pos);
- packageName = packageName.replace('/', '.');
- } else {
- packageName = "";
- }
- URL url = lazySourceOracle.find(fileName);
- allCups.add(new URLCompilationUnitProvider(url, packageName));
- }
- alreadySeenFiles.addAll(files);
- this.cups = allCups.toArray(this.cups);
}
+ lazyJavaSourceOracle = new JavaSourceOracleImpl(lazySourceOracle);
- // Create the public path.
- //
- branch = Messages.PUBLIC_PATH_LOCATIONS.branch(logger, null);
- lazyPublicOracle = publicPathEntries.create(branch);
+ // Create the compilation state.
+ compilationState = new CompilationState(lazyJavaSourceOracle);
PerfLogger.end();
}
- private TypeOracle createTypeOracle(TreeLogger logger)
- throws UnableToCompleteException {
-
- TypeOracle newTypeOracle = null;
-
- try {
- String msg = "Analyzing source in module '" + getName() + "'";
- TreeLogger branch = logger.branch(TreeLogger.TRACE, msg, null);
- long before = System.currentTimeMillis();
- TypeOracleBuilder builder = new TypeOracleBuilder(getCacheManager());
- CompilationUnitProvider[] currentCups = getCompilationUnits();
- Arrays.sort(currentCups, CompilationUnitProvider.LOCATION_COMPARATOR);
-
- TreeLogger subBranch = null;
- if (branch.isLoggable(TreeLogger.DEBUG)) {
- subBranch = branch.branch(TreeLogger.DEBUG,
- "Adding compilation units...", null);
- }
-
- for (int i = 0; i < currentCups.length; i++) {
- CompilationUnitProvider cup = currentCups[i];
- if (subBranch != null) {
- subBranch.log(TreeLogger.DEBUG, cup.getLocation(), null);
- }
- builder.addCompilationUnit(currentCups[i]);
- }
-
- if (lazyTypeOracle != null) {
- cacheManager.invalidateOnRefresh(lazyTypeOracle);
- }
-
- newTypeOracle = builder.build(branch);
- long after = System.currentTimeMillis();
- branch.log(TreeLogger.TRACE, "Finished in " + (after - before) + " ms",
- null);
- } catch (UnableToCompleteException e) {
- logger.log(TreeLogger.ERROR, "Failed to complete analysis", null);
- throw new UnableToCompleteException();
- }
-
- // Sanity check the seed types and don't even start it they're missing.
- //
- boolean seedTypesMissing = false;
- if (newTypeOracle.findType("java.lang.Object") == null) {
- Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
- seedTypesMissing = true;
- } else {
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "Finding entry point classes", null);
- String[] typeNames = getEntryPointTypeNames();
- for (int i = 0; i < typeNames.length; i++) {
- String typeName = typeNames[i];
- if (newTypeOracle.findType(typeName) == null) {
- Util.logMissingTypeErrorWithHints(branch, typeName);
- seedTypesMissing = true;
- }
- }
- }
-
- if (seedTypesMissing) {
- throw new UnableToCompleteException();
- }
-
- return newTypeOracle;
- }
-
private ZipScanner getScanner(String[] includeList, String[] excludeList,
boolean defaultExcludes, boolean caseSensitive) {
/*
@@ -552,4 +468,37 @@
return scanner;
}
+ private void updateTypeOracle(TreeLogger logger)
+ throws UnableToCompleteException {
+ PerfLogger.start("ModuleDef.updateTypeOracle");
+ TreeLogger branch = logger.branch(TreeLogger.TRACE,
+ "Compiling Java source files in module '" + getName() + "'");
+ compilationState.compile(branch);
+ PerfLogger.end();
+
+ TypeOracle typeOracle = compilationState.getTypeOracle();
+
+ // Sanity check the seed types and don't even start it they're missing.
+ boolean seedTypesMissing = false;
+ if (typeOracle.findType("java.lang.Object") == null) {
+ Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
+ seedTypesMissing = true;
+ } else {
+ branch = logger.branch(TreeLogger.TRACE, "Finding entry point classes",
+ null);
+ String[] typeNames = getEntryPointTypeNames();
+ for (int i = 0; i < typeNames.length; i++) {
+ String typeName = typeNames[i];
+ if (typeOracle.findType(typeName) == null) {
+ Util.logMissingTypeErrorWithHints(branch, typeName);
+ seedTypesMissing = true;
+ }
+ }
+ }
+
+ if (seedTypesMissing) {
+ throw new UnableToCompleteException();
+ }
+ }
+
}
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index 5cb3086..f61e01c 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -101,7 +101,7 @@
*/
public static ModuleDef loadFromClassPath(TreeLogger logger, String moduleName)
throws UnableToCompleteException {
- return loadFromClassPath(logger, moduleName, true);
+ return loadFromClassPath(logger, moduleName, false);
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/cfg/PublicOracle.java b/dev/core/src/com/google/gwt/dev/cfg/PublicOracle.java
index 3709608..c88f852 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/PublicOracle.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/PublicOracle.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -15,7 +15,7 @@
*/
package com.google.gwt.dev.cfg;
-import java.net.URL;
+import com.google.gwt.dev.resource.Resource;
/**
* Abstracts the process of querying for public files.
@@ -28,7 +28,7 @@
* @param partialPath a file path relative to the root of any public package
* @return the url of the file, or <code>null</code> if no such file exists
*/
- URL findPublicFile(String partialPath);
+ Resource findPublicFile(String partialPath);
/**
* Returns all available public files.
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java b/dev/core/src/com/google/gwt/dev/javac/AnnotationProxyFactory.java
similarity index 98%
rename from dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java
rename to dev/core/src/com/google/gwt/dev/javac/AnnotationProxyFactory.java
index d3ae321..28627e7 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java
+++ b/dev/core/src/com/google/gwt/dev/javac/AnnotationProxyFactory.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
@@ -284,7 +284,7 @@
AnnotationProxyInvocationHandler annotationInvocationHandler = new AnnotationProxyInvocationHandler(
identifierToValue, annotationClass);
Annotation proxy = (Annotation) Proxy.newProxyInstance(
- AnnotationProxyFactory.class.getClassLoader(), new Class<?>[] {
+ Thread.currentThread().getContextClassLoader(), new Class<?>[] {
java.lang.annotation.Annotation.class, annotationClass},
annotationInvocationHandler);
annotationInvocationHandler.setProxy(proxy);
diff --git a/dev/core/src/com/google/gwt/dev/jdt/BinaryTypeReferenceRestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsChecker.java
similarity index 85%
rename from dev/core/src/com/google/gwt/dev/jdt/BinaryTypeReferenceRestrictionsChecker.java
rename to dev/core/src/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsChecker.java
index 8d4382a..3fc0ba4 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/BinaryTypeReferenceRestrictionsChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsChecker.java
@@ -13,7 +13,9 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
+
+import com.google.gwt.dev.jdt.TypeRefVisitor;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
@@ -33,13 +35,13 @@
* Check a {@link CompilationUnitDeclaration} for references to binary types
* outside the context of an annotation.
*/
-class BinaryTypeReferenceRestrictionsChecker {
+public class BinaryTypeReferenceRestrictionsChecker {
/**
* Records the location from which a {@link BinaryTypeBinding} is referenced.
*/
static class BinaryTypeReferenceSite {
- private final Expression expression;
private final BinaryTypeBinding binaryTypeBinding;
+ private final Expression expression;
BinaryTypeReferenceSite(Expression expression,
BinaryTypeBinding binaryTypeBinding) {
@@ -107,17 +109,24 @@
* is reported against the {@link CompilationUnitDeclaration} for the first
* instance of each unique {@link BinaryTypeBinding}.
*/
- public static void check(CompilationUnitDeclaration cud) {
- List<BinaryTypeReferenceSite> binaryTypeReferenceSites = findInvalidBinaryTypeReferenceSites(cud);
- Set<BinaryTypeBinding> invalidBindaryTypeBindings = new HashSet<BinaryTypeBinding>();
+ public static void check(CompilationUnitDeclaration cud,
+ Set<String> validBinaryTypeNames) {
+ List<BinaryTypeReferenceSite> binaryTypeReferenceSites = findAllBinaryTypeReferenceSites(cud);
+ Set<BinaryTypeBinding> alreadySeenTypeBindings = new HashSet<BinaryTypeBinding>();
for (BinaryTypeReferenceSite binaryTypeReferenceSite : binaryTypeReferenceSites) {
BinaryTypeBinding binaryTypeBinding = binaryTypeReferenceSite.getBinaryTypeBinding();
- if (invalidBindaryTypeBindings.contains(binaryTypeBinding)) {
+ if (alreadySeenTypeBindings.contains(binaryTypeBinding)) {
continue;
}
- invalidBindaryTypeBindings.add(binaryTypeBinding);
+ alreadySeenTypeBindings.add(binaryTypeBinding);
+ String binaryName = String.valueOf(binaryTypeBinding.constantPoolName());
+ if (validBinaryTypeNames.contains(binaryName)) {
+ // This binary name is valid; it is a reference to a unit that was
+ // compiled in a previous JDT run.
+ continue;
+ }
String qualifiedTypeName = binaryTypeBinding.debugName();
String error = formatBinaryTypeRefErrorMessage(qualifiedTypeName);
@@ -127,7 +136,7 @@
}
}
- static List<BinaryTypeReferenceSite> findInvalidBinaryTypeReferenceSites(
+ static List<BinaryTypeReferenceSite> findAllBinaryTypeReferenceSites(
CompilationUnitDeclaration cud) {
List<BinaryTypeReferenceSite> binaryTypeReferenceSites = new ArrayList<BinaryTypeReferenceSite>();
BinaryTypeReferenceVisitor binaryTypeReferenceVisitor = new BinaryTypeReferenceVisitor(
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
new file mode 100644
index 0000000..bdf9c2c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
@@ -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.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.CompilationUnit.State;
+import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
+import com.google.gwt.dev.js.ast.JsProgram;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Encapsulates the state of active compilation units in a particular module.
+ * State is accumulated throughout the life cycle of the containing module and
+ * may be invalidated at certain times and recomputed.
+ */
+public class CompilationState {
+ protected final Map<String, CompilationUnit> unitMap = new HashMap<String, CompilationUnit>();
+ private Set<JavaSourceFile> cachedSourceFiles = Collections.emptySet();
+ private Map<String, CompiledClass> exposedClassFileMap = null;
+ private final Map<String, CompilationUnit> exposedUnitMap = Collections.unmodifiableMap(unitMap);
+ private Set<CompilationUnit> exposedUnits = Collections.emptySet();
+ private final TypeOracleMediator mediator = new TypeOracleMediator();
+ private final JavaSourceOracle sourceOracle;
+
+ /**
+ * Construct a new {@link CompilationState}.
+ *
+ * @param sourceOracle an oracle used to retrieve source code and check for
+ * changes in the underlying source code base
+ */
+ public CompilationState(JavaSourceOracle sourceOracle) {
+ this.sourceOracle = sourceOracle;
+ refresh();
+ }
+
+ public void addGeneratedCompilationUnit(CompilationUnit unit) {
+ String typeName = unit.getTypeName();
+ assert (!unitMap.containsKey(typeName));
+ unitMap.put(typeName, unit);
+ updateExposedUnits();
+ }
+
+ /**
+ * Compile all units and updates all internal state. Invalidate any units with
+ * compile errors.
+ */
+ public void compile(TreeLogger logger) throws UnableToCompleteException {
+ JdtCompiler.compile(getCompilationUnits());
+ CompilationUnitInvalidator.validateCompilationUnits(getCompilationUnits(),
+ getClassFileMap());
+
+ // TODO: Move into validation & log errors?
+ JsniCollector.collectJsniMethods(logger, getCompilationUnits(),
+ new JsProgram());
+
+ CompilationUnitInvalidator.invalidateUnitsWithErrors(logger,
+ getCompilationUnits());
+
+ mediator.refresh(logger, getCompilationUnits());
+
+ // Any surviving units are now checked.
+ for (CompilationUnit unit : getCompilationUnits()) {
+ if (unit.getState() == State.COMPILED) {
+ unit.setState(State.CHECKED);
+ }
+ }
+
+ updateExposedUnits();
+ }
+
+ /**
+ * Returns a map of all compiled classes by binary name.
+ */
+ public Map<String, CompiledClass> getClassFileMap() {
+ if (exposedClassFileMap == null) {
+ HashMap<String, CompiledClass> classFileMap = new HashMap<String, CompiledClass>();
+ for (CompilationUnit unit : getCompilationUnits()) {
+ if (unit.isCompiled()) {
+ for (CompiledClass compiledClass : unit.getCompiledClasses()) {
+ classFileMap.put(compiledClass.getBinaryName(), compiledClass);
+ }
+ }
+ }
+ exposedClassFileMap = Collections.unmodifiableMap(classFileMap);
+ }
+ return exposedClassFileMap;
+ }
+
+ /**
+ * Returns an unmodifiable view of the set of compilation units, mapped by the
+ * main type's qualified source name.
+ */
+ public Map<String, CompilationUnit> getCompilationUnitMap() {
+ return exposedUnitMap;
+ }
+
+ /**
+ * Returns an unmodifiable view of the set of compilation units.
+ */
+ public Set<CompilationUnit> getCompilationUnits() {
+ return exposedUnits;
+ }
+
+ public TypeOracle getTypeOracle() {
+ return mediator.getTypeOracle();
+ }
+
+ /**
+ * Synchronize against the source oracle to check for added/removed/updated
+ * units. Updated units are invalidated, and any units depending on changed
+ * units are also invalidated. All generated units are removed.
+ *
+ * TODO: something more optimal with generated files?
+ */
+ public void refresh() {
+ // Always remove all generated compilation units.
+ for (Iterator<CompilationUnit> it = unitMap.values().iterator(); it.hasNext();) {
+ CompilationUnit unit = it.next();
+ if (unit.isGenerated()) {
+ unit.setState(State.FRESH);
+ it.remove();
+ }
+ }
+
+ refreshFromSourceOracle();
+ // Don't log about invalidated units via refresh.
+ CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(TreeLogger.NULL,
+ getCompilationUnits());
+ updateExposedUnits();
+ }
+
+ private void refreshFromSourceOracle() {
+ // See if the source oracle has changed.
+ Set<JavaSourceFile> newSourceFiles = sourceOracle.getSourceFiles();
+ if (cachedSourceFiles == newSourceFiles) {
+ return;
+ }
+
+ // Divide resources into changed and unchanged.
+ Set<JavaSourceFile> unchanged = new HashSet<JavaSourceFile>(
+ cachedSourceFiles);
+ unchanged.retainAll(newSourceFiles);
+
+ Set<JavaSourceFile> changed = new HashSet<JavaSourceFile>(newSourceFiles);
+ changed.removeAll(unchanged);
+
+ // First remove any stale units.
+ for (Iterator<CompilationUnit> it = unitMap.values().iterator(); it.hasNext();) {
+ CompilationUnit unit = it.next();
+ SourceFileCompilationUnit sourceFileUnit = (SourceFileCompilationUnit) unit;
+ if (!unchanged.contains(sourceFileUnit.getSourceFile())) {
+ unit.setState(State.FRESH);
+ it.remove();
+ }
+ }
+
+ // Then add any new source files.
+ for (JavaSourceFile newSourceFile : changed) {
+ String typeName = newSourceFile.getTypeName();
+ assert (!unitMap.containsKey(typeName));
+ unitMap.put(typeName, new SourceFileCompilationUnit(newSourceFile));
+ }
+
+ // Record the update.
+ cachedSourceFiles = newSourceFiles;
+ }
+
+ private void updateExposedUnits() {
+ exposedUnits = Collections.unmodifiableSet(new HashSet<CompilationUnit>(
+ unitMap.values()));
+ exposedClassFileMap = null;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
new file mode 100644
index 0000000..e4e723a
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -0,0 +1,258 @@
+/*
+ * 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.dev.jdt.TypeRefVisitor;
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Encapsulates the state of a single active compilation unit in a particular
+ * module. State is accumulated throughout the life cycle of the containing
+ * module and may be invalidated at certain times and recomputed.
+ */
+public abstract class CompilationUnit {
+
+ enum State {
+ COMPILED, CHECKED, ERROR, FRESH
+ }
+
+ private class FindTypesInCud extends ASTVisitor {
+ Map<SourceTypeBinding, CompiledClass> map = new IdentityHashMap<SourceTypeBinding, CompiledClass>();
+
+ public Set<CompiledClass> getClasses() {
+ return new HashSet<CompiledClass>(map.values());
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration typeDecl, BlockScope scope) {
+ CompiledClass enclosingClass = map.get(typeDecl.binding.enclosingType());
+ assert (enclosingClass != null);
+ /*
+ * Weird case: if JDT determines that this local class is totally
+ * uninstantiable, it won't bother allocating a local name.
+ */
+ if (typeDecl.binding.constantPoolName() != null) {
+ CompiledClass newClass = new CompiledClass(typeDecl, enclosingClass);
+ map.put(typeDecl.binding, newClass);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration typeDecl, ClassScope scope) {
+ CompiledClass enclosingClass = map.get(typeDecl.binding.enclosingType());
+ assert (enclosingClass != null);
+ CompiledClass newClass = new CompiledClass(typeDecl, enclosingClass);
+ map.put(typeDecl.binding, newClass);
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration typeDecl, CompilationUnitScope scope) {
+ assert (typeDecl.binding.enclosingType() == null);
+ CompiledClass newClass = new CompiledClass(typeDecl, null);
+ map.put(typeDecl.binding, newClass);
+ return true;
+ }
+ }
+
+ private static Set<String> computeFileNameRefs(CompilationUnitDeclaration cud) {
+ final Set<String> result = new HashSet<String>();
+ cud.traverse(new TypeRefVisitor() {
+ @Override
+ protected void onTypeRef(SourceTypeBinding referencedType,
+ CompilationUnitDeclaration unitOfReferrer) {
+ // Map the referenced type to the target compilation unit file.
+ result.add(String.valueOf(referencedType.getFileName()));
+ }
+ }, cud.scope);
+ return result;
+ }
+
+ private CompilationUnitDeclaration cud;
+ private CategorizedProblem[] errors;
+ private Set<CompiledClass> exposedCompiledClasses;
+ private Set<String> fileNameRefs;
+ private State state = State.FRESH;
+
+ /**
+ * Overridden to finalize; always returns object identity.
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns the user-relevant location of the source file. No programmatic
+ * assumptions should be made about the return value.
+ */
+ public abstract String getDisplayLocation();
+
+ /**
+ * Returns the source code for this unit.
+ */
+ public abstract String getSource();
+
+ /**
+ * Returns the fully-qualified name of the top level public type.
+ */
+ public abstract String getTypeName();
+
+ /**
+ * Overridden to finalize; always returns identity hash code.
+ */
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Returns <code>true</code> if this unit is compiled and valid.
+ */
+ public boolean isCompiled() {
+ return state == State.COMPILED || state == State.CHECKED;
+ }
+
+ /**
+ * Returns <code>true</code> if this unit was generated by a
+ * {@link com.google.gwt.core.ext.Generator}.
+ */
+ public abstract boolean isGenerated();
+
+ /**
+ * Overridden to finalize; always returns {@link #getDisplayLocation()}.
+ */
+ public final String toString() {
+ return getDisplayLocation();
+ }
+
+ /**
+ * Called when this unit no longer needs to keep an internal cache of its
+ * source.
+ */
+ protected void dumpSource() {
+ }
+
+ /**
+ * If compiled, returns all contained classes; otherwise returns
+ * <code>null</code>.
+ */
+ Set<CompiledClass> getCompiledClasses() {
+ if (!isCompiled()) {
+ return null;
+ }
+ if (exposedCompiledClasses == null) {
+ FindTypesInCud typeFinder = new FindTypesInCud();
+ cud.traverse(typeFinder, cud.scope);
+ Set<CompiledClass> compiledClasses = typeFinder.getClasses();
+ exposedCompiledClasses = Collections.unmodifiableSet(compiledClasses);
+ }
+ return exposedCompiledClasses;
+ }
+
+ CategorizedProblem[] getErrors() {
+ return errors;
+ }
+
+ Set<String> getFileNameRefs() {
+ if (fileNameRefs == null) {
+ fileNameRefs = computeFileNameRefs(cud);
+ }
+ return fileNameRefs;
+ }
+
+ /**
+ * If compiled, returns the JDT compilation unit declaration; otherwise
+ * <code>null</code>.
+ */
+ CompilationUnitDeclaration getJdtCud() {
+ return cud;
+ }
+
+ State getState() {
+ return state;
+ }
+
+ /**
+ * Sets the compiled JDT AST for this unit.
+ */
+ void setJdtCud(CompilationUnitDeclaration cud) {
+ this.cud = cud;
+ state = State.COMPILED;
+ }
+
+ /**
+ * Changes the compilation unit's internal state.
+ */
+ void setState(State newState) {
+ assert (newState != State.COMPILED);
+ if (state == newState) {
+ return;
+ }
+ state = newState;
+
+ dumpSource();
+ switch (newState) {
+ case CHECKED:
+ // Must cache before we destroy the cud.
+ assert (cud != null);
+ getFileNameRefs();
+ for (CompiledClass compiledClass : getCompiledClasses()) {
+ compiledClass.checked();
+ }
+ cud = null;
+ break;
+
+ case ERROR:
+ this.errors = cud.compilationResult().getErrors();
+ invalidate();
+ break;
+ case FRESH:
+ this.errors = null;
+ invalidate();
+ break;
+ }
+ }
+
+ /**
+ * Removes all accumulated state associated with compilation.
+ */
+ private void invalidate() {
+ cud = null;
+ fileNameRefs = null;
+ if (exposedCompiledClasses != null) {
+ for (CompiledClass compiledClass : exposedCompiledClasses) {
+ compiledClass.invalidate();
+ }
+ exposedCompiledClasses = null;
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
new file mode 100644
index 0000000..0a670ed
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
@@ -0,0 +1,155 @@
+/*
+ * 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.TreeLogger.HelpInfo;
+import com.google.gwt.dev.javac.CompilationUnit.State;
+import com.google.gwt.dev.util.Util;
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * Helper class to invalidate units in a set based on errors or references to
+ * other invalidate units.
+ *
+ * TODO: {@link ClassFileReader#hasStructuralChanges(byte[])} could help us
+ * optimize this process!
+ */
+public class CompilationUnitInvalidator {
+
+ public static void invalidateUnitsWithErrors(TreeLogger logger,
+ Set<CompilationUnit> units) {
+ logger = logger.branch(TreeLogger.TRACE, "Removing units with errors");
+ // Start by removing units with a known problem.
+ boolean anyRemoved = false;
+ for (CompilationUnit unit : units) {
+ CompilationUnitDeclaration cud = unit.getJdtCud();
+ if (cud == null) {
+ continue;
+ }
+ CompilationResult result = cud.compilationResult();
+ if (result.hasErrors()) {
+ anyRemoved = true;
+
+ // TODO: defer this until later?
+ TreeLogger branch = logger.branch(TreeLogger.ERROR, "Errors in '"
+ + unit.getDisplayLocation() + "'", null);
+
+ for (CategorizedProblem error : result.getErrors()) {
+ // Append 'Line #: msg' to the error message.
+ StringBuffer msgBuf = new StringBuffer();
+ int line = error.getSourceLineNumber();
+ if (line > 0) {
+ msgBuf.append("Line ");
+ msgBuf.append(line);
+ msgBuf.append(": ");
+ }
+ msgBuf.append(error.getMessage());
+
+ HelpInfo helpInfo = null;
+ if (error instanceof GWTProblem) {
+ GWTProblem gwtProblem = (GWTProblem) error;
+ helpInfo = gwtProblem.getHelpInfo();
+ }
+ branch.log(TreeLogger.ERROR, msgBuf.toString(), null, helpInfo);
+ }
+
+ Util.maybeDumpSource(branch, unit.getDisplayLocation(),
+ unit.getSource(), unit.getTypeName());
+
+ // TODO: hold onto errors?
+ unit.setState(State.ERROR);
+ }
+ }
+
+ if (anyRemoved) {
+ // Then removing anything else that won't compile as a result.
+ invalidateUnitsWithInvalidRefs(logger, units);
+ }
+ }
+
+ public static void invalidateUnitsWithInvalidRefs(TreeLogger logger,
+ Set<CompilationUnit> units) {
+ logger = logger.branch(TreeLogger.TRACE, "Removing invalidate units");
+
+ // Map all units by file name.
+ Map<String, CompilationUnit> unitsByFileName = new HashMap<String, CompilationUnit>();
+ for (CompilationUnit unit : units) {
+ unitsByFileName.put(unit.getDisplayLocation(), unit);
+ }
+ // First, compute a map from all targets all referents.
+ Map<CompilationUnit, Set<CompilationUnit>> refTargetToReferents = new HashMap<CompilationUnit, Set<CompilationUnit>>();
+ for (CompilationUnit referentUnit : units) {
+ if (referentUnit.isCompiled()) {
+ Set<String> fileNameRefs = referentUnit.getFileNameRefs();
+ for (String fileNameRef : fileNameRefs) {
+ CompilationUnit targetUnit = unitsByFileName.get(fileNameRef);
+ if (targetUnit != null) {
+ Set<CompilationUnit> referents = refTargetToReferents.get(targetUnit);
+ if (referents == null) {
+ referents = new HashSet<CompilationUnit>();
+ refTargetToReferents.put(targetUnit, referents);
+ }
+ // Add myself as a referent.
+ referents.add(referentUnit);
+ }
+ }
+ }
+ }
+
+ // Now use the map to transitively blow away invalid units.
+ for (Entry<CompilationUnit, Set<CompilationUnit>> entry : refTargetToReferents.entrySet()) {
+ CompilationUnit maybeInvalidUnit = entry.getKey();
+ if (!maybeInvalidUnit.isCompiled()) {
+ // Invalidate all dependent units.
+ Set<CompilationUnit> invalidReferentUnits = entry.getValue();
+ TreeLogger branch = logger.branch(TreeLogger.TRACE,
+ "Compilation unit '" + maybeInvalidUnit + "' is invalid");
+ State why = maybeInvalidUnit.getState();
+ for (CompilationUnit invalidReferentUnit : invalidReferentUnits) {
+ if (invalidReferentUnit.isCompiled()) {
+ // Set it to the same state as the unit it depends on.
+ invalidReferentUnit.setState(why);
+ branch.log(TreeLogger.TRACE, "Removing dependent unit '"
+ + invalidReferentUnit + "'");
+ }
+ }
+ }
+ }
+ }
+
+ public static void validateCompilationUnits(Set<CompilationUnit> units,
+ Map<String, CompiledClass> compiledClasses) {
+ for (CompilationUnit unit : units) {
+ if (unit.getState() != State.CHECKED) {
+ CompilationUnitDeclaration jdtCud = unit.getJdtCud();
+ JSORestrictionsChecker.check(jdtCud);
+ LongFromJSNIChecker.check(jdtCud);
+ BinaryTypeReferenceRestrictionsChecker.check(jdtCud,
+ compiledClasses.keySet());
+ }
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java b/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java
new file mode 100644
index 0000000..f3e1080
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/CompiledClass.java
@@ -0,0 +1,173 @@
+/*
+ * 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.typeinfo.JRealClassType;
+import com.google.gwt.dev.javac.impl.Shared;
+
+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.Collections;
+import java.util.List;
+
+/**
+ * Encapsulates the state of a single compiled class file.
+ */
+public final 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;
+ }
+
+ private static String getPackagePrefix(String packageName) {
+ return packageName.length() > 0 ? packageName + "." : "";
+ }
+
+ protected final String binaryName;
+ protected final byte[] bytes;
+ protected final CompiledClass enclosingClass;
+ protected final String location;
+ protected final String packageName;
+ protected final String sourceName;
+
+ // The state below is transient.
+ private List<JsniMethod> jsniMethods;
+ private NameEnvironmentAnswer nameEnvironmentAnswer;
+ private JRealClassType realClassType;
+ // Can be killed after parent is CHECKED.
+ private TypeDeclaration typeDeclaration;
+
+ CompiledClass(TypeDeclaration typeDeclaration, CompiledClass enclosingClass) {
+ SourceTypeBinding binding = typeDeclaration.binding;
+ this.typeDeclaration = typeDeclaration;
+ this.enclosingClass = enclosingClass;
+ 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;
+ }
+
+ /**
+ * Returns the bytes of the compiled class.
+ */
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public CompiledClass getEnclosingClass() {
+ return enclosingClass;
+ }
+
+ public List<JsniMethod> getJsniMethods() {
+ return jsniMethods;
+ }
+
+ /**
+ * Returns the enclosing package, e.g. {@code java.util}.
+ */
+ public String getPackageName() {
+ return packageName;
+ }
+
+ /**
+ * Returns the qualified source name, e.g. {@code java.util.Map.Entry}.
+ */
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ @Override
+ public String toString() {
+ return binaryName;
+ }
+
+ /**
+ * 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() {
+ return realClassType;
+ }
+
+ TypeDeclaration getTypeDeclaration() {
+ return typeDeclaration;
+ }
+
+ void invalidate() {
+ nameEnvironmentAnswer = null;
+ typeDeclaration = null;
+ jsniMethods = null;
+ if (realClassType != null) {
+ realClassType.invalidate();
+ realClassType = null;
+ }
+ }
+
+ void setJsniMethods(List<JsniMethod> jsniMethods) {
+ this.jsniMethods = Collections.unmodifiableList(jsniMethods);
+ }
+
+ void setRealClassType(JRealClassType realClassType) {
+ this.realClassType = realClassType;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/GWTProblem.java b/dev/core/src/com/google/gwt/dev/javac/GWTProblem.java
similarity index 94%
rename from dev/core/src/com/google/gwt/dev/jdt/GWTProblem.java
rename to dev/core/src/com/google/gwt/dev/javac/GWTProblem.java
index b61688e..645b6b7 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/GWTProblem.java
+++ b/dev/core/src/com/google/gwt/dev/javac/GWTProblem.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.ext.TreeLogger.HelpInfo;
@@ -30,7 +30,7 @@
*/
public class GWTProblem extends DefaultProblem {
- static void recordInCud(ASTNode node, CompilationUnitDeclaration cud,
+ public static void recordInCud(ASTNode node, CompilationUnitDeclaration cud,
String message, HelpInfo helpInfo) {
CompilationResult compResult = cud.compilationResult();
int[] lineEnds = compResult.getLineSeparatorPositions();
diff --git a/dev/core/src/com/google/gwt/dev/jdt/JSORestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
similarity index 60%
rename from dev/core/src/com/google/gwt/dev/jdt/JSORestrictionsChecker.java
rename to dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
index 43e3df3..b6c7390 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/JSORestrictionsChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
@@ -13,12 +13,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
-import com.google.gwt.dev.shell.JsValueGlue;
import com.google.gwt.dev.util.InstalledHelpInfo;
-import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
@@ -33,9 +31,10 @@
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
-import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import java.util.Stack;
+
/**
* Check a compilation unit for violations of
* {@link com.google.gwt.core.client.JavaScriptObject JavaScriptObject} (JSO)
@@ -58,100 +57,134 @@
* Any violations found are attached as errors on the
* CompilationUnitDeclaration.
*/
-class JSORestrictionsChecker {
+public class JSORestrictionsChecker {
private class JSORestrictionsVisitor extends ASTVisitor implements
ClassFileConstants {
+ private final Stack<Boolean> isJsoStack = new Stack<Boolean>();
+
@Override
public void endVisit(AllocationExpression exp, BlockScope scope) {
- if (exp.type != null && isJSOSubclass(exp.type.resolveType(scope))) {
+ // Anywhere an allocation occurs is wrong.
+ if (exp.type != null && isJsoSubclass(exp.type.resolveType(scope))) {
errorOn(exp, ERR_NEW_JSO);
}
}
@Override
public void endVisit(ConstructorDeclaration meth, ClassScope scope) {
- if (isForJSOSubclass(scope)) {
- if ((meth.arguments != null) && (meth.arguments.length > 0)) {
- errorOn(meth, ERR_CONSTRUCTOR_WITH_PARAMETERS);
- }
- if ((meth.modifiers & AccProtected) == 0) {
- errorOn(meth, ERR_NONPROTECTED_CONSTRUCTOR);
- }
- if (meth.statements != null && meth.statements.length > 0) {
- errorOn(meth, ERR_NONEMPTY_CONSTRUCTOR);
- }
+ if (!isJso()) {
+ return;
+ }
+ if ((meth.arguments != null) && (meth.arguments.length > 0)) {
+ errorOn(meth, ERR_CONSTRUCTOR_WITH_PARAMETERS);
+ }
+ if ((meth.modifiers & AccProtected) == 0) {
+ errorOn(meth, ERR_NONPROTECTED_CONSTRUCTOR);
+ }
+ if (meth.statements != null && meth.statements.length > 0) {
+ errorOn(meth, ERR_NONEMPTY_CONSTRUCTOR);
}
}
@Override
public void endVisit(FieldDeclaration field, MethodScope scope) {
- if (isForJSOSubclass(scope)) {
- if (!field.isStatic()) {
- errorOn(field, ERR_INSTANCE_FIELD);
- }
+ if (!isJso()) {
+ return;
+ }
+ if (!field.isStatic()) {
+ errorOn(field, ERR_INSTANCE_FIELD);
}
}
@Override
public void endVisit(MethodDeclaration meth, ClassScope scope) {
- if (isForJSOSubclass(scope)) {
- if ((meth.modifiers & (AccFinal | AccPrivate | AccStatic)) == 0) {
- // The method's modifiers allow it to be overridden. Make
- // one final check to see if the surrounding class is final.
- if ((meth.scope == null)
- || !meth.scope.enclosingSourceType().isFinal()) {
- errorOn(meth, ERR_INSTANCE_METHOD_NONFINAL);
- }
+ if (!isJso()) {
+ return;
+ }
+ if ((meth.modifiers & (AccFinal | AccPrivate | AccStatic)) == 0) {
+ // The method's modifiers allow it to be overridden. Make
+ // one final check to see if the surrounding class is final.
+ if ((meth.scope == null) || !meth.scope.enclosingSourceType().isFinal()) {
+ errorOn(meth, ERR_INSTANCE_METHOD_NONFINAL);
}
+ }
- // Should not have to check isStatic() here, but isOverriding() appears
- // to be set for static methods.
- if (!meth.isStatic()
- && (meth.binding != null && meth.binding.isOverriding())) {
- errorOn(meth, ERR_OVERRIDDEN_METHOD);
- }
+ // Should not have to check isStatic() here, but isOverriding() appears
+ // to be set for static methods.
+ if (!meth.isStatic()
+ && (meth.binding != null && meth.binding.isOverriding())) {
+ errorOn(meth, ERR_OVERRIDDEN_METHOD);
}
}
@Override
public void endVisit(TypeDeclaration type, BlockScope scope) {
- checkType(type);
+ popIsJso();
}
@Override
public void endVisit(TypeDeclaration type, ClassScope scope) {
- checkType(type);
+ popIsJso();
}
@Override
public void endVisit(TypeDeclaration type, CompilationUnitScope scope) {
- checkType(type);
+ popIsJso();
}
- private void checkType(TypeDeclaration type) {
- if (isJSOSubclass(type)) {
- if (type.enclosingType != null && !type.binding.isStatic()) {
- errorOn(type, ERR_IS_NONSTATIC_NESTED);
- }
+ @Override
+ public boolean visit(TypeDeclaration type, BlockScope scope) {
+ pushIsJso(checkType(type));
+ return true;
+ }
- ReferenceBinding[] interfaces = type.binding.superInterfaces();
- if (interfaces != null) {
- for (ReferenceBinding interf : interfaces) {
- if (interf.methods() != null && interf.methods().length > 0) {
- String intfName = String.copyValueOf(interf.shortReadableName());
- errorOn(type, errInterfaceWithMethods(intfName));
- }
+ @Override
+ public boolean visit(TypeDeclaration type, ClassScope scope) {
+ pushIsJso(checkType(type));
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration type, CompilationUnitScope scope) {
+ pushIsJso(checkType(type));
+ return true;
+ }
+
+ private boolean checkType(TypeDeclaration type) {
+ if (!isJsoSubclass(type.binding)) {
+ return false;
+ }
+ if (type.enclosingType != null && !type.binding.isStatic()) {
+ errorOn(type, ERR_IS_NONSTATIC_NESTED);
+ }
+
+ ReferenceBinding[] interfaces = type.binding.superInterfaces();
+ if (interfaces != null) {
+ for (ReferenceBinding interf : interfaces) {
+ if (interf.methods() != null && interf.methods().length > 0) {
+ String intfName = String.copyValueOf(interf.shortReadableName());
+ errorOn(type, errInterfaceWithMethods(intfName));
}
}
}
+ return true;
+ }
+
+ private boolean isJso() {
+ return isJsoStack.peek();
+ }
+
+ private void popIsJso() {
+ isJsoStack.pop();
+ }
+
+ private void pushIsJso(boolean isJso) {
+ isJsoStack.push(isJso);
}
}
- protected static final char[][] JSO_CLASS_CHARS = CharOperation.splitOn('.',
- JsValueGlue.JSO_CLASS.toCharArray());
-
static final String ERR_CONSTRUCTOR_WITH_PARAMETERS = "Constructors must not have parameters in subclasses of JavaScriptObject";
static final String ERR_INSTANCE_FIELD = "Instance fields cannot be used in subclasses of JavaScriptObject";
static final String ERR_INSTANCE_METHOD_NONFINAL = "Instance methods must be 'final' in non-final subclasses of JavaScriptObject";
@@ -160,6 +193,7 @@
static final String ERR_NONEMPTY_CONSTRUCTOR = "Constructors must be totally empty in subclasses of JavaScriptObject";
static final String ERR_NONPROTECTED_CONSTRUCTOR = "Constructors must be 'protected' in subclasses of JavaScriptObject";
static final String ERR_OVERRIDDEN_METHOD = "Methods cannot be overridden in JavaScriptObject subclasses";
+ static final String JSO_CLASS = "com/google/gwt/core/client/JavaScriptObject";
/**
* Checks an entire
@@ -167,13 +201,7 @@
*
*/
public static void check(CompilationUnitDeclaration cud) {
- TypeBinding jsoType = cud.scope.environment().getType(JSO_CLASS_CHARS);
- if (jsoType == null) {
- // JavaScriptObject not available; do nothing
- return;
- }
-
- JSORestrictionsChecker checker = new JSORestrictionsChecker(cud, jsoType);
+ JSORestrictionsChecker checker = new JSORestrictionsChecker(cud);
checker.check();
}
@@ -184,40 +212,30 @@
private final CompilationUnitDeclaration cud;
- /**
- * The type of the GWT JavaScriptObject class. Cannot be null.
- */
- private final TypeBinding jsoType;
-
- private JSORestrictionsChecker(CompilationUnitDeclaration cud,
- TypeBinding jsoType) {
- assert jsoType != null;
+ private JSORestrictionsChecker(CompilationUnitDeclaration cud) {
this.cud = cud;
- this.jsoType = jsoType;
}
private void check() {
cud.traverse(new JSORestrictionsVisitor(), cud.scope);
}
- private TypeBinding classType(Scope scope) {
- return scope.classScope().referenceType().binding;
- }
-
private void errorOn(ASTNode node, String error) {
GWTProblem.recordInCud(node, cud, error, new InstalledHelpInfo(
"jsoRestrictions.html"));
}
- private boolean isForJSOSubclass(Scope scope) {
- return isJSOSubclass(classType(scope));
- }
-
- private boolean isJSOSubclass(TypeBinding typeBinding) {
- return typeBinding.isCompatibleWith(jsoType) && typeBinding != jsoType;
- }
-
- private boolean isJSOSubclass(TypeDeclaration typeDecl) {
- return isJSOSubclass(typeDecl.binding);
+ private boolean isJsoSubclass(TypeBinding typeBinding) {
+ if (!(typeBinding instanceof ReferenceBinding)) {
+ return false;
+ }
+ ReferenceBinding binding = (ReferenceBinding) typeBinding;
+ while (binding.superclass() != null) {
+ if (JSO_CLASS.equals(String.valueOf(binding.superclass().constantPoolName()))) {
+ return true;
+ }
+ binding = binding.superclass();
+ }
+ return false;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java b/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java
new file mode 100644
index 0000000..f73c2da
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+/**
+ * Provides information about a single Java source file.
+ */
+public abstract class JavaSourceFile {
+
+ /**
+ * Overridden to finalize; always returns object identity.
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns the user-relevant location of the source file. No programmatic
+ * assumptions should be made about the return value.
+ */
+ public abstract String getLocation();
+
+ /**
+ * Returns the name of the package.
+ */
+ public abstract String getPackageName();
+
+ /**
+ * Returns the unqualified name of the top level public type.
+ */
+ public abstract String getShortName();
+
+ /**
+ * Returns the fully-qualified name of the top level public type.
+ */
+ public abstract String getTypeName();
+
+ /**
+ * Overridden to finalize; always returns identity hash code.
+ */
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Returns the Java code contained in this source file. May return
+ * <code>null</code> if this {@link JavaSourceFile} has been invalidated by
+ * its containing {@link JavaSourceOracle}. This method may be expensive as
+ * the implementor is generally not required to cache the results.
+ */
+ public abstract String readSource();
+
+ /**
+ * Overridden to finalize; always returns {@link #getLocation()}.
+ */
+ public final String toString() {
+ return getLocation();
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JavaSourceOracle.java b/dev/core/src/com/google/gwt/dev/javac/JavaSourceOracle.java
new file mode 100644
index 0000000..12d5841
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/JavaSourceOracle.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2006 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 java.util.Map;
+import java.util.Set;
+
+/**
+ * An unmodifiable view of a module's Java source tree.
+ *
+ * <p>
+ * The identity of the returned sets and maps will change exactly when the
+ * underlying module is refreshed.
+ * </p>
+ *
+ * <p>
+ * Even when the identity of a returned set changes, the identity of any
+ * contained {@link JavaSourceFile} values is guaranteed to differ from a
+ * previous result exactly when that particular source file becomes invalid.
+ * </p>
+ *
+ * <p>
+ * A source file could become invalid for various reasons, including:
+ * <ul>
+ * <li>the underlying file was deleted or modified</li>
+ * <li>another file with the same logical name superceded it on the classpath</li>
+ * <li>the underlying module changed to exclude this file or supercede it with
+ * another file</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * After a refresh, a client can reliably detect changes by checking which of
+ * its cached source files is still contained in the new result of
+ * {@link #getSourceFiles()}.
+ * </p>
+ */
+public interface JavaSourceOracle {
+
+ /**
+ * Returns an unmodifiable set of fully-qualified class names with constant
+ * lookup time.
+ */
+ Set<String> getClassNames();
+
+ /**
+ * Returns an unmodifiable set of unique source files with constant lookup
+ * time.
+ */
+ Set<JavaSourceFile> getSourceFiles();
+
+ /**
+ * Returns an unmodifiable map of fully-qualified class name to source file.
+ */
+ Map<String, JavaSourceFile> getSourceMap();
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
new file mode 100644
index 0000000..831b46a
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -0,0 +1,279 @@
+/*
+ * 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.dev.javac.impl.Shared;
+import com.google.gwt.dev.util.PerfLogger;
+import com.google.gwt.util.tools.Utility;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manages the process of compiling {@link CompilationUnit}s.
+ */
+public class JdtCompiler {
+
+ /**
+ * Adapts a {@link CompilationUnit} for a JDT compile.
+ */
+ public static class CompilationUnitAdapter implements ICompilationUnit {
+
+ private final CompilationUnit unit;
+
+ public CompilationUnitAdapter(CompilationUnit unit) {
+ this.unit = unit;
+ }
+
+ public char[] getContents() {
+ return unit.getSource().toString().toCharArray();
+ }
+
+ public char[] getFileName() {
+ return unit.getDisplayLocation().toCharArray();
+ }
+
+ public char[] getMainTypeName() {
+ return Shared.getShortName(unit.getTypeName()).toCharArray();
+ }
+
+ public char[][] getPackageName() {
+ String packageName = Shared.getPackageName(unit.getTypeName());
+ return CharOperation.splitOn('.', packageName.toCharArray());
+ }
+
+ public CompilationUnit getUnit() {
+ return unit;
+ }
+
+ @Override
+ public String toString() {
+ return unit.toString();
+ }
+ }
+ private class CompilerImpl extends Compiler {
+
+ public CompilerImpl() {
+ super(new INameEnvironmentImpl(),
+ DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ getCompilerOptions(), new ICompilerRequestorImpl(),
+ new DefaultProblemFactory(Locale.getDefault()));
+ }
+
+ @Override
+ public void process(CompilationUnitDeclaration cud, int i) {
+ // TODO: not always generate bytecode eagerly?
+ super.process(cud, i);
+ ICompilationUnit icu = cud.compilationResult().compilationUnit;
+ CompilationUnitAdapter adapter = (CompilationUnitAdapter) icu;
+ adapter.getUnit().setJdtCud(cud);
+ }
+ }
+
+ /**
+ * Hook point to accept results.
+ */
+ private class ICompilerRequestorImpl implements ICompilerRequestor {
+ public void acceptResult(CompilationResult result) {
+ }
+ }
+
+ /**
+ * How JDT receives files from the environment.
+ */
+ private class INameEnvironmentImpl implements INameEnvironment {
+ public void cleanup() {
+ }
+
+ public NameEnvironmentAnswer findType(char[] type, char[][] pkg) {
+ return findType(CharOperation.arrayConcat(pkg, type));
+ }
+
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ char[] binaryNameChars = CharOperation.concatWith(compoundTypeName, '.');
+ String binaryName = String.valueOf(binaryNameChars);
+ CompiledClass compiledClass = binaryTypes.get(binaryName);
+ if (compiledClass != null) {
+ return compiledClass.getNameEnvironmentAnswer();
+ }
+ if (isPackage(binaryName)) {
+ return null;
+ }
+ try {
+ // Check for binary-only annotations.
+ Class.forName(binaryName, false, getClassLoader());
+ String resourcePath = binaryName.replace('.', '/') + ".class";
+ URL resource = getClassLoader().getResource(resourcePath);
+ InputStream openStream = resource.openStream();
+ try {
+ ClassFileReader cfr = ClassFileReader.read(openStream,
+ resource.toExternalForm(), true);
+ return new NameEnvironmentAnswer(cfr, null);
+ } finally {
+ Utility.close(openStream);
+ }
+ } catch (NoClassDefFoundError e) {
+ } catch (ClassNotFoundException e) {
+ } catch (ClassFormatException e) {
+ } catch (IOException e) {
+ }
+ return null;
+ }
+
+ public boolean isPackage(char[][] parentPkg, char[] pkg) {
+ final char[] pathChars = CharOperation.concatWith(parentPkg, pkg, '.');
+ String packageName = String.valueOf(pathChars);
+ return isPackage(packageName);
+ }
+
+ private ClassLoader getClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ private boolean isPackage(String packageName) {
+ // Include class loader check for binary-only annotations.
+ if (packages.contains(packageName)) {
+ return true;
+ }
+ if (notPackages.contains(packageName)) {
+ return false;
+ }
+ String resourceName = packageName.replace('.', '/') + '/';
+ if (getClassLoader().getResource(resourceName) != null) {
+ addPackages(packageName);
+ return true;
+ } else {
+ notPackages.add(packageName);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Compiles the given set of units. The units will be internally modified to
+ * reflect the results of compilation.
+ */
+ public static void compile(Collection<CompilationUnit> units) {
+ PerfLogger.start("JdtCompiler.compile");
+ new JdtCompiler().doCompile(units);
+ PerfLogger.end();
+ }
+
+ private static CompilerOptions getCompilerOptions() {
+ Map<String, String> settings = new HashMap<String, String>();
+ settings.put(CompilerOptions.OPTION_LineNumberAttribute,
+ CompilerOptions.GENERATE);
+ settings.put(CompilerOptions.OPTION_SourceFileAttribute,
+ CompilerOptions.GENERATE);
+ /*
+ * Tricks like "boolean stopHere = true;" depend on this setting to work in
+ * hosted mode. In web mode, our compiler should optimize them out once we
+ * do real data flow.
+ */
+ settings.put(CompilerOptions.OPTION_PreserveUnusedLocal,
+ CompilerOptions.PRESERVE);
+ settings.put(CompilerOptions.OPTION_ReportDeprecation,
+ CompilerOptions.IGNORE);
+ settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
+ CompilerOptions.GENERATE);
+ settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
+ settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
+ settings.put(CompilerOptions.OPTION_TargetPlatform,
+ CompilerOptions.VERSION_1_5);
+
+ // This is needed by TypeOracleBuilder to parse metadata.
+ settings.put(CompilerOptions.OPTION_DocCommentSupport,
+ CompilerOptions.ENABLED);
+ return new CompilerOptions(settings);
+ }
+
+ private final List<CompilationUnit> activeUnits = new ArrayList<CompilationUnit>();
+
+ /**
+ * Maps dotted binary names to compiled classes.
+ */
+ private final Map<String, CompiledClass> binaryTypes = new HashMap<String, CompiledClass>();
+
+ private final CompilerImpl compiler = new CompilerImpl();
+
+ private final Set<String> notPackages = new HashSet<String>();
+
+ private final Set<String> packages = new HashSet<String>();
+
+ /**
+ * Not externally instantiable.
+ */
+ private JdtCompiler() {
+ }
+
+ private void addPackages(String packageName) {
+ while (true) {
+ packages.add(String.valueOf(packageName));
+ int pos = packageName.lastIndexOf('.');
+ if (pos > 0) {
+ packageName = packageName.substring(0, pos);
+ } else {
+ packages.add("");
+ break;
+ }
+ }
+ }
+
+ private void doCompile(Collection<CompilationUnit> units) {
+ List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>();
+ for (CompilationUnit unit : units) {
+ String packageName = Shared.getPackageName(unit.getTypeName());
+ addPackages(packageName);
+ Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
+ if (compiledClasses == null) {
+ icus.add(new CompilationUnitAdapter(unit));
+ activeUnits.add(unit);
+ } else {
+ for (CompiledClass compiledClass : compiledClasses) {
+ binaryTypes.put(compiledClass.getBinaryName().replace('/', '.'),
+ compiledClass);
+ }
+ }
+ }
+ if (!icus.isEmpty()) {
+ compiler.compile(icus.toArray(new ICompilationUnit[icus.size()]));
+ }
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
new file mode 100644
index 0000000..6acae2c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
@@ -0,0 +1,300 @@
+/*
+ * 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.dev.javac.CompilationUnit.State;
+import com.google.gwt.dev.js.JsParser;
+import com.google.gwt.dev.js.JsParserException;
+import com.google.gwt.dev.js.JsParserException.SourceDetail;
+import com.google.gwt.dev.js.ast.JsExprStmt;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsStatement;
+import com.google.gwt.dev.util.Empty;
+import com.google.gwt.dev.util.Jsni;
+
+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;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Adapts compilation units containing JSNI-accessible code by rewriting the
+ * source.
+ */
+public class JsniCollector {
+
+ /**
+ * Represents a logical interval of text.
+ */
+ public static class Interval {
+ public final int end;
+ public final int start;
+
+ public Interval(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+ }
+
+ private static final class JsniMethodImpl extends JsniMethod {
+ private JsFunction func;
+ private final int line;
+ private final String location;
+ private final String name;
+ private final String[] paramNames;
+ private final String source;
+ private final JsProgram program;
+
+ private JsniMethodImpl(String name, String source, String[] paramNames,
+ int line, String location, JsProgram program) {
+ this.name = name;
+ this.source = source;
+ this.paramNames = paramNames;
+ this.line = line;
+ this.location = location;
+ this.program = program;
+ }
+
+ @Override
+ public JsFunction function(TreeLogger logger) {
+ if (func == null) {
+ func = parseAsAnonymousFunction(logger, program, source, paramNames,
+ location, line);
+ }
+ return func;
+ }
+
+ public int line() {
+ return line;
+ }
+
+ public String location() {
+ return location;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String[] paramNames() {
+ return paramNames;
+ }
+
+ public String source() {
+ return source;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("function ");
+ sb.append(name);
+ sb.append('(');
+ boolean first = true;
+ for (String paramName : paramNames) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(paramName);
+ }
+ sb.append("} {\n");
+ sb.append(source);
+ sb.append("}\n");
+ return sb.toString();
+ }
+ }
+
+ public static void collectJsniMethods(TreeLogger logger,
+ Set<CompilationUnit> units, JsProgram program) {
+ for (CompilationUnit unit : units) {
+ if (unit.getState() == State.COMPILED) {
+ String loc = unit.getDisplayLocation();
+ String source = unit.getSource();
+ for (CompiledClass compiledClass : unit.getCompiledClasses()) {
+ assert compiledClass.getJsniMethods() == null;
+ collectJsniMethods(logger, loc, source, compiledClass, program);
+ }
+ }
+ }
+ }
+
+ /**
+ * TODO: log real errors, replacing GenerateJavaScriptAST?
+ */
+ private static void collectJsniMethods(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));
+ }
+ }
+ compiledClass.setJsniMethods(jsniMethods);
+ }
+
+ private static Interval findJsniSource(String source,
+ AbstractMethodDeclaration method) {
+ assert (method.isNative());
+ int bodyStart = method.bodyStart;
+ int bodyEnd = method.bodyEnd;
+ String js = source.substring(bodyStart, bodyEnd + 1);
+
+ int jsniStart = js.indexOf(Jsni.JSNI_BLOCK_START);
+ if (jsniStart == -1) {
+ return null;
+ }
+
+ int jsniEnd = js.indexOf(Jsni.JSNI_BLOCK_END, jsniStart);
+ if (jsniEnd == -1) {
+ // Suspicious, but maybe this is just a weird comment, so let it slide.
+ //
+ return null;
+ }
+
+ int srcStart = bodyStart + jsniStart + Jsni.JSNI_BLOCK_START.length();
+ int srcEnd = bodyStart + jsniEnd;
+ return new Interval(srcStart, srcEnd);
+ }
+
+ /**
+ * 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,
+ AbstractMethodDeclaration method) {
+ return '@' + enclosingType + "::" + getMemberSignature(method);
+ }
+
+ /**
+ * Gets a unique name for this method and its signature (this is used to
+ * determine whether one method overrides another).
+ */
+ private static String getMemberSignature(AbstractMethodDeclaration method) {
+ String name = String.valueOf(method.selector);
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ sb.append("(");
+ if (method.arguments != null) {
+ for (Argument param : method.arguments) {
+ sb.append(param.binding.type.signature());
+ }
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ private static String[] getParamNames(AbstractMethodDeclaration method) {
+ if (method.arguments != null) {
+ String[] paramNames = new String[method.arguments.length];
+ for (int i = 0; i < paramNames.length; ++i) {
+ paramNames[i] = String.valueOf(method.arguments[i].name);
+ }
+ return paramNames;
+ }
+ return Empty.STRINGS;
+ }
+
+ /**
+ * TODO: rip out problem reporting code from BuildTypeMap and attach errors to
+ * the compilation units.
+ */
+ private static JsFunction parseAsAnonymousFunction(TreeLogger logger,
+ JsProgram program, String js, String[] paramNames, String location,
+ int startLine) {
+
+ // Wrap the code in an anonymous function and parse it.
+ StringReader r;
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("function (");
+ boolean first = true;
+ for (String paramName : paramNames) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(paramName);
+ }
+ sb.append(") {");
+ sb.append(js);
+ sb.append('}');
+ r = new StringReader(sb.toString());
+ }
+
+ try {
+ List<JsStatement> stmts = new JsParser().parse(program.getScope(), r,
+ startLine);
+
+ return (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression();
+ } catch (IOException e) {
+ // Should never happen.
+ throw new RuntimeException(e);
+ } catch (JsParserException e) {
+ SourceDetail dtl = e.getSourceDetail();
+ if (dtl != null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(location);
+ sb.append("(");
+ sb.append(dtl.getLine());
+ sb.append(", ");
+ sb.append(dtl.getLineOffset());
+ sb.append("): ");
+ sb.append(e.getMessage());
+ logger.log(TreeLogger.ERROR, sb.toString(), e);
+ return null;
+ } else {
+ logger.log(TreeLogger.ERROR, "Error parsing JSNI source", e);
+ return null;
+ }
+ }
+ }
+
+ private JsniCollector() {
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
new file mode 100644
index 0000000..d45a460
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
@@ -0,0 +1,55 @@
+/*
+ * 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.dev.js.ast.JsFunction;
+
+/**
+ * Represents a single JsniMethod in a compiled class file.
+ */
+public abstract class JsniMethod {
+ /**
+ * If non-null, an anonymous function containing the parameters and body of
+ * this JSNI method.
+ */
+ public abstract JsFunction function(TreeLogger logger);
+
+ /**
+ * Starting line number of the method.
+ */
+ public abstract int line();
+
+ /**
+ * Location of the containing compilation unit.
+ */
+ public abstract String location();
+
+ /**
+ * The mangled method name (a jsni signature).
+ */
+ public abstract String name();
+
+ /**
+ * The parameter names.
+ */
+ public abstract String[] paramNames();
+
+ /**
+ * The script body.
+ */
+ public abstract String source();
+}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java b/dev/core/src/com/google/gwt/dev/javac/LongFromJSNIChecker.java
similarity index 98%
rename from dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
rename to dev/core/src/com/google/gwt/dev/javac/LongFromJSNIChecker.java
index e404c8c..fa49fd6 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/LongFromJSNIChecker.java
@@ -13,9 +13,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.client.UnsafeNativeLong;
+import com.google.gwt.dev.jdt.FindJsniRefVisitor;
import com.google.gwt.dev.util.InstalledHelpInfo;
import com.google.gwt.dev.util.JsniRef;
diff --git a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
similarity index 69%
rename from dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
rename to dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
index 0af0fac..a58513c 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
@@ -13,11 +13,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.HasMetaData;
import com.google.gwt.core.ext.typeinfo.HasTypeParameters;
import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
@@ -38,17 +37,14 @@
import com.google.gwt.core.ext.typeinfo.JRealClassType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.JTypeParameter;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.JWildcardType.BoundType;
-import com.google.gwt.dev.jdt.CacheManager.Mapper;
+import com.google.gwt.dev.javac.impl.Shared;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.PerfLogger;
-import com.google.gwt.dev.util.Util;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -57,7 +53,6 @@
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.Clinit;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
@@ -69,13 +64,10 @@
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
-import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -89,40 +81,26 @@
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
import java.io.BufferedReader;
-import java.io.CharArrayReader;
-import java.io.File;
import java.io.IOException;
+import java.io.StringReader;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Array;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeMap;
import java.util.regex.Pattern;
/**
- * Builds a {@link com.google.gwt.core.ext.typeinfo.TypeOracle} from a set of
- * compilation units.
- * <p>
- * For example,
- *
- * <pre>
- * TypeOracleBuilder b = new TypeOracleBuilder();
- * b.addCompilationUnit(unit1);
- * b.addCompilationUnit(unit2);
- * b.addCompilationUnit(unit3);
- * b.excludePackage("example.pkg");
- * TypeOracle oracle = b.build(logger);
- * JClassType[] allTypes = oracle.getTypes();
- * </pre>
+ * Builds or rebuilds a {@link com.google.gwt.core.ext.typeinfo.TypeOracle} from
+ * a set of compilation units.
*/
-public class TypeOracleBuilder {
+public class TypeOracleMediator {
+
private static final JClassType[] NO_JCLASSES = new JClassType[0];
private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\s");
@@ -160,22 +138,23 @@
return classType.getQualifiedSourceName();
}
- static boolean parseMetaDataTags(char[] unitSource, HasMetaData hasMetaData,
+ static boolean parseMetaDataTags(String unitSource, HasMetaData hasMetaData,
Javadoc javadoc) {
int start = javadoc.sourceStart;
int end = javadoc.sourceEnd;
- char[] comment = CharOperation.subarray(unitSource, start, end + 1);
- if (comment == null) {
- comment = new char[0];
+ if (start < 0 || end > unitSource.length() || start > end) {
+ // Invalid.
+ return false;
}
- BufferedReader reader = new BufferedReader(new CharArrayReader(comment));
+ String comment = unitSource.substring(start, end + 1);
+ BufferedReader reader = new BufferedReader(new StringReader(
+ comment.toString()));
String activeTag = null;
final List<String> tagValues = new ArrayList<String>();
try {
- String line = reader.readLine();
boolean firstLine = true;
- while (line != null) {
+ for (String line = reader.readLine(); line != null; line = reader.readLine()) {
if (firstLine) {
firstLine = false;
int commentStart = line.indexOf("/**");
@@ -186,26 +165,27 @@
line = line.substring(commentStart + 3);
}
+ if (activeTag == null && line.indexOf('@') < 0) {
+ continue;
+ }
+
String[] tokens = PATTERN_WHITESPACE.split(line);
boolean canIgnoreStar = true;
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i];
// Check for the end.
- //
if (token.endsWith("*/")) {
token = token.substring(0, token.length() - 2);
}
// Check for an ignored leading star.
- //
if (canIgnoreStar && token.startsWith("*")) {
token = token.substring(1);
canIgnoreStar = false;
}
// Decide what to do with whatever is left.
- //
if (token.length() > 0) {
canIgnoreStar = false;
if (token.startsWith("@")) {
@@ -227,8 +207,6 @@
}
}
}
-
- line = reader.readLine();
}
} catch (IOException e) {
return false;
@@ -304,14 +282,6 @@
return retentionPolicy;
}
- private static boolean isAnnotation(TypeDeclaration typeDecl) {
- if (TypeDeclaration.kind(typeDecl.modifiers) == TypeDeclaration.ANNOTATION_TYPE_DECL) {
- return true;
- } else {
- return false;
- }
- }
-
/**
* Returns <code>true</code> if this name is the special package-info type
* name.
@@ -326,6 +296,11 @@
private static boolean maybeGeneric(TypeDeclaration typeDecl,
JClassType enclosingType) {
+ if (typeDecl.typeParameters != null) {
+ // Definitely generic since it has type parameters.
+ return true;
+ }
+
if (enclosingType != null && enclosingType.isGenericType() != null) {
if (!typeDecl.binding.isStatic()) {
/*
@@ -351,11 +326,6 @@
}
}
- if (typeDecl.typeParameters != null) {
- // Definitely generic since it has type parameters.
- return true;
- }
-
return false;
}
@@ -364,309 +334,72 @@
return new HashMap<Class<? extends java.lang.annotation.Annotation>, java.lang.annotation.Annotation>();
}
- private static void removeInfectedUnits(final TreeLogger logger,
- final Map<String, CompilationUnitDeclaration> changedCudsByFileName,
- final Map<String, CompilationUnitDeclaration> unchangedCudsByFileName) {
+ private final Map<String, JRealClassType> binaryMapper = new HashMap<String, JRealClassType>();
+ private final Map<SourceTypeBinding, JRealClassType> sourceMapper = new IdentityHashMap<SourceTypeBinding, JRealClassType>();
+ private final Map<TypeVariableBinding, JTypeParameter> tvMapper = new IdentityHashMap<TypeVariableBinding, JTypeParameter>();
+ private final TypeOracle typeOracle = new TypeOracle();
+ private final Set<JRealClassType> unresolvedTypes = new HashSet<JRealClassType>();
- final Set<String> pendingRemovals = new HashSet<String>();
- TypeRefVisitor trv = new TypeRefVisitor() {
- @Override
- protected void onTypeRef(SourceTypeBinding referencedType,
- CompilationUnitDeclaration unitOfReferrer) {
- // If the referenced type belongs to a compilation unit that is
- // not in the list of valid units, then the unit in which it
- // is referenced must also be removed.
- //
- String referencedFn = String.valueOf(referencedType.getFileName());
- if (!unchangedCudsByFileName.containsKey(referencedFn)
- && !changedCudsByFileName.containsKey(referencedFn)) {
- // This is a referenced to a bad or non-existent unit.
- // So, remove the referrer's unit if it hasn't been already.
- //
- String referrerFn = String.valueOf(unitOfReferrer.getFileName());
- if (changedCudsByFileName.containsKey(referrerFn)
- && !pendingRemovals.contains(referrerFn)) {
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "Cascaded removal of compilation unit '" + referrerFn + "'",
- null);
- final String badTypeName = CharOperation.toString(referencedType.compoundName);
- branch.branch(TreeLogger.TRACE,
- "Due to reference to unavailable type: " + badTypeName, null);
- pendingRemovals.add(referrerFn);
- }
- }
- }
- };
-
- do {
- // Perform any pending removals.
- //
- for (Iterator<String> iter = pendingRemovals.iterator(); iter.hasNext();) {
- String fnToRemove = iter.next();
- Object removed = changedCudsByFileName.remove(fnToRemove);
- assert (removed != null);
- }
-
- // Start fresh for this iteration.
- //
- pendingRemovals.clear();
-
- // Find references to type in units that aren't valid.
- //
- for (Iterator<CompilationUnitDeclaration> iter = changedCudsByFileName.values().iterator(); iter.hasNext();) {
- CompilationUnitDeclaration cud = iter.next();
- cud.traverse(trv, cud.scope);
- }
- } while (!pendingRemovals.isEmpty());
+ public TypeOracle getTypeOracle() {
+ return typeOracle;
}
- private static void removeUnitsWithErrors(TreeLogger logger,
- Map<String, CompilationUnitDeclaration> changedCudsByFileName,
- Map<String, CompilationUnitDeclaration> unchangedCudsByFileName) {
- // Start by removing units with a known problem.
- //
- boolean anyRemoved = false;
- for (Iterator<CompilationUnitDeclaration> iter = changedCudsByFileName.values().iterator(); iter.hasNext();) {
- CompilationUnitDeclaration cud = iter.next();
- CompilationResult result = cud.compilationResult;
- IProblem[] errors = result.getErrors();
- if (errors != null && errors.length > 0) {
- anyRemoved = true;
- iter.remove();
-
- String fileName = CharOperation.charToString(cud.getFileName());
- char[] source = cud.compilationResult.compilationUnit.getContents();
- Util.maybeDumpSource(logger, fileName, source,
- String.valueOf(cud.getMainTypeName()));
- logger.log(TreeLogger.TRACE, "Removing problematic compilation unit '"
- + fileName + "'", null);
- }
- }
-
- if (anyRemoved) {
- // Then removing anything else that won't compile as a result.
- //
- removeInfectedUnits(logger, changedCudsByFileName,
- unchangedCudsByFileName);
- }
- }
-
- private final CacheManager cacheManager;
-
- /**
- * Constructs a default instance, with a default cacheManager. This is not to
- * be used in Hosted Mode, as caching will then not work.
- */
- public TypeOracleBuilder() {
- cacheManager = new CacheManager();
- }
-
- /**
- * Constructs an instance from the supplied cacheManager, using the
- * <code>TypeOracle</code> contained therein. This is to be used in Hosted
- * Mode, so that caching will work, assuming the cacheManager has a cache
- * directory.
- */
- public TypeOracleBuilder(CacheManager cacheManager) {
- this.cacheManager = cacheManager;
- }
-
- /**
- * Constructs an instance from the supplied typeOracle, with a cacheManager
- * using the same typeOracle. This is not to be used in Hosted Mode, as
- * caching will then not work.
- */
- public TypeOracleBuilder(TypeOracle typeOracle) {
- cacheManager = new CacheManager(typeOracle);
- }
-
- /**
- * Includes the specified logical compilation unit into the set of units this
- * builder will parse and analyze. If a previous compilation unit was
- * specified in the same location, it will be replaced if it is older.
- */
- public void addCompilationUnit(CompilationUnitProvider cup)
+ public void refresh(TreeLogger logger, Set<CompilationUnit> units)
throws UnableToCompleteException {
- cacheManager.addCompilationUnit(cup);
- }
+ PerfLogger.start("TypeOracleMediator.refresh");
+ typeOracle.removeInvalidatedTypes();
+ binaryMapper.clear();
+ sourceMapper.clear();
+ tvMapper.clear();
+ unresolvedTypes.clear();
- public TypeOracle build(final TreeLogger logger)
- throws UnableToCompleteException {
- PerfLogger.start("TypeOracleBuilder.build");
-
- Set<CompilationUnitProvider> addedCups = cacheManager.getAddedCups();
- TypeOracle oracle = cacheManager.getTypeOracle();
- // Make a copy that we can sort.
- //
- for (Iterator<CompilationUnitProvider> iter = addedCups.iterator(); iter.hasNext();) {
- CompilationUnitProvider cup = iter.next();
- String location = cup.getLocation();
- // TODO: Delegate to cup in order to check for deletification.
- if (!((location.indexOf("http://") != -1) || (location.indexOf("ftp://") != -1))) {
- location = Util.findFileName(location);
- if (!(new File(location).exists() || cup.isTransient())) {
- iter.remove();
- logger.log(
- TreeLogger.TRACE,
- "The file "
- + location
- + " was removed by the user. All types therein are now unavailable.",
- null);
+ // Perform a shallow pass to establish identity for new and old types.
+ PerfLogger.start("TypeOracleMediator.refresh (shallow)");
+ for (CompilationUnit unit : units) {
+ if (!unit.isCompiled()) {
+ continue;
+ }
+ Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
+ for (CompiledClass compiledClass : compiledClasses) {
+ JRealClassType type = compiledClass.getRealClassType();
+ if (type == null) {
+ type = createType(compiledClass);
}
+ binaryMapper.put(compiledClass.getBinaryName(), type);
}
}
- CompilationUnitProvider[] cups = Util.toArray(
- CompilationUnitProvider.class, addedCups);
- Arrays.sort(cups, CompilationUnitProvider.LOCATION_COMPARATOR);
-
- // Make sure we can find the java.lang.Object compilation unit.
- //
- boolean foundJavaLangPackage = oracle.findPackage("java.lang") != null;
-
- // Adapt to JDT idioms.
- //
- ICompilationUnit[] units = new ICompilationUnit[cups.length];
- for (int i = 0; i < cups.length; i++) {
- if (!foundJavaLangPackage && cups[i].getPackageName().equals("java.lang")) {
- foundJavaLangPackage = true;
- }
- units[i] = cacheManager.findUnitForCup(cups[i]);
- }
-
- // Error if no java.lang.
- if (!foundJavaLangPackage) {
- Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
- throw new UnableToCompleteException();
- }
-
- PerfLogger.start("TypeOracleBuilder.build (compile)");
- /*
- * The assumption is that getting the changed CUDs will include anything
- * that transitively depends on the changed CUDs.
- */
- CompilationUnitDeclaration[] cuds = cacheManager.getAstCompiler().getChangedCompilationUnitDeclarations(
- logger, units);
PerfLogger.end();
- // Build a list that makes it easy to remove problems.
- //
- final Map<String, CompilationUnitDeclaration> unchangedCudsByFileName = new TreeMap<String, CompilationUnitDeclaration>();
- unchangedCudsByFileName.putAll(cacheManager.getCudsByFileName());
- final Map<String, CompilationUnitDeclaration> changedCudsByFileName = new TreeMap<String, CompilationUnitDeclaration>();
- for (int i = 0; i < cuds.length; i++) {
- CompilationUnitDeclaration cud = cuds[i];
- String fileName = String.valueOf(cud.getFileName());
- changedCudsByFileName.put(fileName, cud);
- /*
- * The CacheManager's cuds by file name may include the changed CUDs from
- * a previous refresh. So we remove them here to ensure that our sets do
- * not overlap.
- */
- unchangedCudsByFileName.remove(fileName);
- }
-
- /*
- * Note that the CacheManager can easily end up with bad CUDs if the newly
- * compiled files have errors. However, this does not impact the TypeOracle.
- */
- cacheManager.getCudsByFileName().putAll(changedCudsByFileName);
-
- /*
- * At this point changedCudsByFileName contains only the CUDs which needed
- * to be recompiled and unchangedCudsByFileName contains only the CUDs which
- * were not recompiled. Now we can scan changedCudsByFileName an remove any
- * CUDs which have errors and any CUDs that are infected by those errors.
- */
- removeUnitsWithErrors(logger, changedCudsByFileName,
- unchangedCudsByFileName);
-
- // Perform a shallow pass to establish identity for new types.
- //
- final CacheManager.Mapper identityMapper = cacheManager.getIdentityMapper();
- for (Iterator<CompilationUnitDeclaration> iter = changedCudsByFileName.values().iterator(); iter.hasNext();) {
- CompilationUnitDeclaration cud = iter.next();
-
- cud.traverse(new ASTVisitor() {
- @Override
- public boolean visit(TypeDeclaration typeDecl, BlockScope scope) {
- JClassType enclosingType = identityMapper.get(typeDecl.binding.enclosingType());
- processType(typeDecl, enclosingType, true);
- return true;
- }
-
- @Override
- public boolean visit(TypeDeclaration typeDecl, ClassScope scope) {
- JClassType enclosingType = identityMapper.get(typeDecl.binding.enclosingType());
- processType(typeDecl, enclosingType, false);
- return true;
- }
-
- @Override
- public boolean visit(TypeDeclaration typeDecl,
- CompilationUnitScope scope) {
- processType(typeDecl, null, false);
- return true;
- }
-
- }, cud.scope);
- }
-
- // Perform a deep pass to resolve all types in terms of our types.
- //
- for (Iterator<CompilationUnitDeclaration> iter = changedCudsByFileName.values().iterator(); iter.hasNext();) {
- CompilationUnitDeclaration cud = iter.next();
- String loc = String.valueOf(cud.getFileName());
- String processing = "Processing types in compilation unit: " + loc;
- final TreeLogger cudLogger = logger.branch(TreeLogger.SPAM, processing,
- null);
- final char[] source = cud.compilationResult.compilationUnit.getContents();
-
- cud.traverse(new ASTVisitor() {
- @Override
- public boolean visit(TypeDeclaration typeDecl, BlockScope scope) {
- if (!resolveTypeDeclaration(cudLogger, source, typeDecl)) {
- String name = String.valueOf(typeDecl.binding.readableName());
- String msg = "Unexpectedly unable to fully resolve type " + name;
- logger.log(TreeLogger.WARN, msg, null);
+ // Perform a deep pass to resolve all new types in terms of our types.
+ PerfLogger.start("TypeOracleMediator.refresh (deep)");
+ for (CompilationUnit unit : units) {
+ if (!unit.isCompiled()) {
+ continue;
+ }
+ TreeLogger cudLogger = logger.branch(TreeLogger.SPAM,
+ "Processing types in compilation unit: " + unit.getDisplayLocation());
+ Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
+ for (CompiledClass compiledClass : compiledClasses) {
+ if (unresolvedTypes.contains(compiledClass.getRealClassType())) {
+ TypeDeclaration typeDeclaration = compiledClass.getTypeDeclaration();
+ if (!resolveTypeDeclaration(cudLogger, unit.getSource(), typeDeclaration)) {
+ logger.log(TreeLogger.WARN,
+ "Unexpectedly unable to fully resolve type "
+ + compiledClass.getSourceName());
}
- return true;
}
-
- @Override
- public boolean visit(TypeDeclaration typeDecl, ClassScope scope) {
- if (!resolveTypeDeclaration(cudLogger, source, typeDecl)) {
- String name = String.valueOf(typeDecl.binding.readableName());
- String msg = "Unexpectedly unable to fully resolve type " + name;
- logger.log(TreeLogger.WARN, msg, null);
- }
- return true;
- }
-
- @Override
- public boolean visit(TypeDeclaration typeDecl,
- CompilationUnitScope scope) {
- if (!resolveTypeDeclaration(cudLogger, source, typeDecl)) {
- String name = String.valueOf(typeDecl.binding.readableName());
- String msg = "Unexpectedly unable to fully resolve type " + name;
- logger.log(TreeLogger.WARN, msg, null);
- }
- return true;
- }
- }, cud.scope);
+ }
}
- Util.invokeInaccessableMethod(TypeOracle.class, "refresh",
- new Class[] {TreeLogger.class}, oracle, new Object[] {logger});
-
PerfLogger.end();
- return oracle;
- }
+ try {
+ typeOracle.refresh(logger);
+ } catch (NotFoundException e) {
+ // TODO
+ e.printStackTrace();
+ }
- /**
- * Used for testing purposes only.
- */
- final CacheManager getCacheManager() {
- return cacheManager;
+ PerfLogger.end();
}
private Object createAnnotationInstance(TreeLogger logger,
@@ -710,6 +443,86 @@
return AnnotationProxyFactory.create(clazz, identifierToValue);
}
+ private JRealClassType createType(CompiledClass compiledClass) {
+ JRealClassType realClassType = compiledClass.getRealClassType();
+ if (realClassType == null) {
+ JRealClassType enclosingType = null;
+ CompiledClass enclosingClass = compiledClass.getEnclosingClass();
+ if (enclosingClass != null) {
+ enclosingType = enclosingClass.getRealClassType();
+ if (enclosingType == null) {
+ enclosingType = createType(enclosingClass);
+ }
+ }
+ realClassType = createType(compiledClass, enclosingType);
+ if (realClassType != null) {
+ unresolvedTypes.add(realClassType);
+ sourceMapper.put(compiledClass.getTypeDeclaration().binding,
+ realClassType);
+ compiledClass.setRealClassType(realClassType);
+ }
+ }
+ return realClassType;
+ }
+
+ /**
+ * 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 createType(CompiledClass compiledClass,
+ JRealClassType enclosingType) {
+ TypeDeclaration typeDecl = compiledClass.getTypeDeclaration();
+ SourceTypeBinding binding = typeDecl.binding;
+ assert (binding.constantPoolName() != null);
+
+ String qname = compiledClass.getSourceName();
+ String className = Shared.getShortName(qname);
+ String jpkgName = compiledClass.getPackageName();
+ JPackage pkg = typeOracle.getOrCreatePackage(jpkgName);
+ boolean isLocalType = binding instanceof LocalTypeBinding;
+ boolean isIntf = TypeDeclaration.kind(typeDecl.modifiers) == TypeDeclaration.INTERFACE_DECL;
+ boolean isAnnotation = TypeDeclaration.kind(typeDecl.modifiers) == TypeDeclaration.ANNOTATION_TYPE_DECL;
+
+ JRealClassType resultType;
+ if (isAnnotation) {
+ resultType = new JAnnotationType(typeOracle, pkg, enclosingType,
+ isLocalType, className, isIntf);
+ } else if (maybeGeneric(typeDecl, enclosingType)) {
+ // Go through and create declarations for each of the type parameters on
+ // the generic class or method
+ JTypeParameter[] jtypeParameters = declareTypeParameters(typeDecl.typeParameters);
+
+ JGenericType jgenericType = new JGenericType(typeOracle, pkg,
+ enclosingType, isLocalType, className, isIntf, jtypeParameters);
+
+ resultType = jgenericType;
+ } else if (binding.isEnum()) {
+ resultType = new JEnumType(typeOracle, pkg, enclosingType, isLocalType,
+ className, isIntf);
+ } else {
+ resultType = new JRealClassType(typeOracle, pkg, enclosingType,
+ isLocalType, className, isIntf);
+ }
+
+ /*
+ * Declare type parameters for all methods; we must do this during the first
+ * pass.
+ */
+ if (typeDecl.methods != null) {
+ for (AbstractMethodDeclaration method : typeDecl.methods) {
+ declareTypeParameters(method.typeParameters());
+ }
+ }
+
+ /*
+ * Add modifiers since these are needed for
+ * TypeOracle.getParameterizedType's error checking code.
+ */
+ resultType.addModifierBits(Shared.bindingToModifierBits(binding));
+ return resultType;
+ }
+
private JClassType[] createTypeParameterBounds(TreeLogger logger,
TypeVariableBinding tvBinding) {
TypeBinding firstBound = tvBinding.firstBound;
@@ -782,12 +595,10 @@
}
JTypeParameter[] jtypeParamArray = new JTypeParameter[typeParameters.length];
- Mapper identityMapper = cacheManager.getIdentityMapper();
-
- for (int i = 0; i < typeParameters.length; i++) {
+ for (int i = 0; i < typeParameters.length; ++i) {
TypeParameter typeParam = typeParameters[i];
jtypeParamArray[i] = new JTypeParameter(String.valueOf(typeParam.name), i);
- identityMapper.put(typeParam.binding, jtypeParamArray[i]);
+ tvMapper.put(typeParam.binding, jtypeParamArray[i]);
}
return jtypeParamArray;
@@ -935,7 +746,7 @@
String className = String.valueOf(resolvedType.constantPoolName());
className = className.replace('/', '.');
return Class.forName(className, false,
- TypeOracleBuilder.class.getClassLoader());
+ Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
logger.log(TreeLogger.ERROR, "", e);
return null;
@@ -969,17 +780,6 @@
}
}
- private CompilationUnitProvider getCup(TypeDeclaration typeDecl) {
- ICompilationUnit icu = typeDecl.compilationResult.compilationUnit;
- ICompilationUnitAdapter icua = (ICompilationUnitAdapter) icu;
- return icua.getCompilationUnitProvider();
- }
-
- private String getPackage(TypeDeclaration typeDecl) {
- final char[][] pkgParts = typeDecl.compilationResult.compilationUnit.getPackageName();
- return String.valueOf(CharOperation.concatWith(pkgParts, '.'));
- }
-
/**
* Returns the qualified name of the binding, excluding any type parameter
* information.
@@ -999,101 +799,9 @@
}
qualifiedName = qualifiedName.replace('$', '.');
-
return qualifiedName;
}
- private String getSimpleName(TypeDeclaration typeDecl) {
- return String.valueOf(typeDecl.name);
- }
-
- private boolean isInterface(TypeDeclaration typeDecl) {
- if (TypeDeclaration.kind(typeDecl.modifiers) == TypeDeclaration.INTERFACE_DECL) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Maps a TypeDeclaration into a JClassType. If the TypeDeclaration has
- * TypeParameters (i.e, it is a generic type or method), then the
- * TypeParameters are mapped into JTypeParameters by
- * {@link TypeOracleBuilder#declareTypeParameters(org.eclipse.jdt.internal.compiler.ast.TypeParameter[])}
- */
- private void processType(TypeDeclaration typeDecl, JClassType jenclosingType,
- boolean isLocalType) {
- TypeOracle oracle = cacheManager.getTypeOracle();
-
- // Create our version of the type structure unless it already exists in the
- // type oracle.
- //
- SourceTypeBinding binding = typeDecl.binding;
- if (binding.constantPoolName() == null) {
- /*
- * Weird case: if JDT determines that this local class is totally
- * uninstantiable, it won't bother allocating a local name.
- */
- return;
- }
-
- String qname = getQualifiedName(binding);
- String className;
- if (binding instanceof LocalTypeBinding) {
- className = qname.substring(qname.lastIndexOf('.') + 1);
- } else {
- className = getSimpleName(typeDecl);
- }
-
- if (oracle.findType(qname) != null) {
- return;
- }
-
- String jpkgName = getPackage(typeDecl);
- JPackage pkg = oracle.getOrCreatePackage(jpkgName);
- final boolean jclassIsIntf = isInterface(typeDecl);
- boolean jclassIsAnnonation = isAnnotation(typeDecl);
- CompilationUnitProvider cup = getCup(typeDecl);
-
- int declStart = typeDecl.declarationSourceStart;
- int declEnd = typeDecl.declarationSourceEnd;
- int bodyStart = typeDecl.bodyStart;
- int bodyEnd = typeDecl.bodyEnd;
-
- JRealClassType jrealClassType;
- if (jclassIsAnnonation) {
- jrealClassType = new JAnnotationType(oracle, cup, pkg, jenclosingType,
- isLocalType, className, declStart, declEnd, bodyStart, bodyEnd,
- jclassIsIntf);
- } else if (maybeGeneric(typeDecl, jenclosingType)) {
- // Go through and create declarations for each of the type parameters on
- // the generic class or method
- JTypeParameter[] jtypeParameters = declareTypeParameters(typeDecl.typeParameters);
-
- JGenericType jgenericType = new JGenericType(oracle, cup, pkg,
- jenclosingType, isLocalType, className, declStart, declEnd,
- bodyStart, bodyEnd, jclassIsIntf, jtypeParameters);
-
- jrealClassType = jgenericType;
- } else if (binding.isEnum()) {
- jrealClassType = new JEnumType(oracle, cup, pkg, jenclosingType,
- isLocalType, className, declStart, declEnd, bodyStart, bodyEnd,
- jclassIsIntf);
- } else {
- jrealClassType = new JRealClassType(oracle, cup, pkg, jenclosingType,
- isLocalType, className, declStart, declEnd, bodyStart, bodyEnd,
- jclassIsIntf);
- }
-
- /*
- * Add modifiers since these are needed for
- * TypeOracle.getParameterizedType's error checking code.
- */
- jrealClassType.addModifierBits(Shared.bindingToModifierBits(binding));
-
- cacheManager.setTypeForBinding(binding, jrealClassType);
- }
-
private boolean resolveAnnotation(
TreeLogger logger,
Annotation jannotation,
@@ -1146,7 +854,6 @@
}
genericElement.getTypeParameters()[ordinal].setBounds(jbounds);
-
return true;
}
@@ -1163,7 +870,7 @@
return true;
}
- private boolean resolveField(TreeLogger logger, char[] unitSource,
+ private boolean resolveField(TreeLogger logger, String unitSource,
JClassType enclosingType, FieldDeclaration jfield) {
if (jfield instanceof Initializer) {
@@ -1213,7 +920,7 @@
return true;
}
- private boolean resolveFields(TreeLogger logger, char[] unitSource,
+ private boolean resolveFields(TreeLogger logger, String unitSource,
JClassType type, FieldDeclaration[] jfields) {
if (jfields != null) {
for (int i = 0; i < jfields.length; i++) {
@@ -1226,7 +933,7 @@
return true;
}
- private boolean resolveMethod(TreeLogger logger, char[] unitSource,
+ private boolean resolveMethod(TreeLogger logger, String unitSource,
JClassType enclosingType, AbstractMethodDeclaration jmethod) {
if (jmethod instanceof Clinit) {
@@ -1235,10 +942,6 @@
return true;
}
- int declStart = jmethod.declarationSourceStart;
- int declEnd = jmethod.declarationSourceEnd;
- int bodyStart = jmethod.bodyStart;
- int bodyEnd = jmethod.bodyEnd;
String name = getMethodName(enclosingType, jmethod);
// Try to resolve annotations, ignore any that fail.
@@ -1250,11 +953,11 @@
// Declare the type parameters. We will pass them into the constructors for
// JConstructor/JMethod/JAnnotatedMethod. Then, we'll do a second pass to
// resolve the bounds on each JTypeParameter object.
- JTypeParameter[] jtypeParameters = declareTypeParameters(jmethod.typeParameters());
+ JTypeParameter[] jtypeParameters = resolveTypeParameters(jmethod.typeParameters());
if (jmethod.isConstructor()) {
- method = new JConstructor(enclosingType, name, declStart, declEnd,
- bodyStart, bodyEnd, declaredAnnotations, jtypeParameters);
+ method = new JConstructor(enclosingType, name, declaredAnnotations,
+ jtypeParameters);
// Do a second pass to resolve the bounds on each JTypeParameter.
if (!resolveBoundsForTypeParameters(logger, method,
jmethod.typeParameters())) {
@@ -1269,11 +972,11 @@
annotationMethod.returnType.resolvedType,
annotationMethod.defaultValue);
}
- method = new JAnnotationMethod(enclosingType, name, declStart, declEnd,
- bodyStart, bodyEnd, defaultValue, declaredAnnotations);
+ method = new JAnnotationMethod(enclosingType, name, defaultValue,
+ declaredAnnotations);
} else {
- method = new JMethod(enclosingType, name, declStart, declEnd,
- bodyStart, bodyEnd, declaredAnnotations, jtypeParameters);
+ method = new JMethod(enclosingType, name, declaredAnnotations,
+ jtypeParameters);
}
// Do a second pass to resolve the bounds on each JTypeParameter.
@@ -1328,7 +1031,7 @@
return true;
}
- private boolean resolveMethods(TreeLogger logger, char[] unitSource,
+ private boolean resolveMethods(TreeLogger logger, String unitSource,
JClassType type, AbstractMethodDeclaration[] jmethods) {
if (jmethods != null) {
for (int i = 0; i < jmethods.length; i++) {
@@ -1344,9 +1047,8 @@
private boolean resolvePackage(TreeLogger logger, TypeDeclaration jclass) {
SourceTypeBinding binding = jclass.binding;
- TypeOracle oracle = cacheManager.getTypeOracle();
String packageName = String.valueOf(binding.fPackage.readableName());
- JPackage pkg = oracle.getOrCreatePackage(packageName);
+ JPackage pkg = typeOracle.getOrCreatePackage(packageName);
assert (pkg != null);
CompilationUnitScope cus = (CompilationUnitScope) jclass.scope.parent;
@@ -1358,7 +1060,6 @@
declaredAnnotations);
pkg.addAnnotations(declaredAnnotations);
-
return true;
}
@@ -1426,9 +1127,7 @@
}
private JType resolveType(TreeLogger logger, TypeBinding binding) {
- TypeOracle oracle = cacheManager.getTypeOracle();
// Check for primitives.
- //
if (binding instanceof BaseTypeBinding) {
switch (binding.id) {
case TypeIds.T_boolean:
@@ -1470,10 +1169,10 @@
// oracle we're assimilating into.
//
String typeName = getQualifiedName(referenceBinding);
- JType resolvedType = oracle.findType(typeName);
+ JType resolvedType = typeOracle.findType(typeName);
if (resolvedType == null) {
// Otherwise, it should be something we've mapped during this build.
- resolvedType = cacheManager.getTypeForBinding(referenceBinding);
+ resolvedType = sourceMapper.get(referenceBinding);
}
if (resolvedType != null) {
@@ -1486,6 +1185,15 @@
}
}
+ if (binding instanceof BinaryTypeBinding) {
+ // Try a binary lookup.
+ String binaryName = String.valueOf(binding.constantPoolName());
+ JRealClassType realClassType = binaryMapper.get(binaryName);
+ if (realClassType != null) {
+ return realClassType;
+ }
+ }
+
// Check for an array.
//
if (binding instanceof ArrayBinding) {
@@ -1501,7 +1209,7 @@
// By using the oracle to intern, we guarantee correct identity
// mapping of lazily-created array types.
//
- resolvedType = oracle.getArrayType(resolvedType);
+ resolvedType = typeOracle.getArrayType(resolvedType);
}
return resolvedType;
} else {
@@ -1552,7 +1260,7 @@
if (!failed) {
if (resolveType.isGenericType() != null) {
- return oracle.getParameterizedType(resolveType.isGenericType(),
+ return typeOracle.getParameterizedType(resolveType.isGenericType(),
enclosingType, typeArguments);
} else {
/*
@@ -1570,7 +1278,7 @@
if (binding instanceof TypeVariableBinding) {
TypeVariableBinding tvBinding = (TypeVariableBinding) binding;
- JTypeParameter typeParameter = (JTypeParameter) cacheManager.getTypeForBinding(tvBinding);
+ JTypeParameter typeParameter = tvMapper.get(tvBinding);
if (typeParameter != null) {
return typeParameter;
}
@@ -1610,7 +1318,7 @@
}
if (boundType != null) {
- return oracle.getWildcardType(boundType, typeBound);
+ return typeOracle.getWildcardType(boundType, typeBound);
}
// Fall-through to failure
@@ -1630,16 +1338,10 @@
return null;
}
- private boolean resolveTypeDeclaration(TreeLogger logger, char[] unitSource,
+ private boolean resolveTypeDeclaration(TreeLogger logger, String unitSource,
TypeDeclaration clazz) {
SourceTypeBinding binding = clazz.binding;
- if (binding.constantPoolName() == null) {
- /*
- * Weird case: if JDT determines that this local class is totally
- * uninstantiable, it won't bother allocating a local name.
- */
- return true;
- }
+ assert (binding.constantPoolName() != null);
String qname = String.valueOf(binding.qualifiedSourceName());
logger = logger.branch(TreeLogger.SPAM, "Found type '" + qname + "'", null);
@@ -1682,11 +1384,11 @@
//
if (jtype.isInterface() == null) {
ReferenceBinding superclassRef = binding.superclass;
+ assert superclassRef != null
+ || "java.lang.Object".equals(jtype.getQualifiedSourceName());
if (superclassRef != null) {
JClassType jsuperClass = (JClassType) resolveType(logger, superclassRef);
- if (jsuperClass == null) {
- return false;
- }
+ assert jsuperClass != null;
jtype.setSuperclass(jsuperClass);
}
}
@@ -1738,4 +1440,29 @@
return true;
}
+
+ /**
+ * Declares TypeParameters declared on a JGenericType or a JAbstractMethod by
+ * mapping the TypeParameters into JTypeParameters. <p/> This mapping has to
+ * be done on the first pass through the AST in order to handle declarations
+ * of the form: <<C exends GenericClass<T>, T extends SimpleClass> <p/> JDT
+ * already knows that GenericClass<T> is a parameterized type with a type
+ * argument of <T extends SimpleClass>. Therefore, in order to resolve
+ * GenericClass<T>, we must have knowledge of <T extends SimpleClass>. <p/>
+ * By calling this method on the first pass through the AST, a JTypeParameter
+ * for <T extends SimpleClass> will be created.
+ */
+ private JTypeParameter[] resolveTypeParameters(TypeParameter[] typeParameters) {
+ if (typeParameters == null || typeParameters.length == 0) {
+ return null;
+ }
+
+ JTypeParameter[] jtypeParamArray = new JTypeParameter[typeParameters.length];
+ for (int i = 0; i < typeParameters.length; ++i) {
+ jtypeParamArray[i] = tvMapper.get(typeParameters[i].binding);
+ assert jtypeParamArray[i] != null;
+ }
+
+ return jtypeParamArray;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java
new file mode 100644
index 0000000..3194633
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java
@@ -0,0 +1,61 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.util.Util;
+
+import java.io.File;
+
+/**
+ * A compilation unit based on a file.
+ */
+public final class FileCompilationUnit extends CompilationUnit {
+ private final File file;
+ private final String typeName;
+
+ public FileCompilationUnit(File file, String packageName) {
+ this.file = file;
+ String fileName = file.getName();
+ assert fileName.endsWith(".java");
+ fileName = fileName.substring(0, fileName.length() - 5);
+ if (packageName.length() == 0) {
+ this.typeName = fileName;
+ } else {
+ this.typeName = packageName + '.' + fileName;
+ }
+ }
+
+ @Override
+ public String getDisplayLocation() {
+ return file.getAbsolutePath();
+ }
+
+ @Override
+ public String getSource() {
+ return Util.readFileAsString(file);
+ }
+
+ @Override
+ public String getTypeName() {
+ return typeName;
+ }
+
+ @Override
+ public boolean isGenerated() {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java
new file mode 100644
index 0000000..820c214
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java
@@ -0,0 +1,191 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.javac.JavaSourceFile;
+import com.google.gwt.dev.javac.JavaSourceOracle;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+import com.google.gwt.dev.util.Util;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Implements {@link JavaSourceOracle} on top of a {@link ResourceOracle}.
+ */
+public class JavaSourceOracleImpl implements JavaSourceOracle {
+
+ private static class JavaSourceFileImpl extends JavaSourceFile {
+
+ private final String location;
+ private final String name;
+ private final String packageName;
+ private Resource resource;
+ private final String shortName;
+
+ public JavaSourceFileImpl(Resource resource) {
+ this.resource = resource;
+ location = resource.getLocation();
+ String path = resource.getPath();
+ assert (path.endsWith(".java"));
+ path = path.substring(0, path.lastIndexOf('.'));
+ name = path.replace('/', '.');
+ int pos = name.lastIndexOf('.');
+ if (pos < 0) {
+ shortName = name;
+ packageName = "";
+ } else {
+ shortName = name.substring(pos + 1);
+ packageName = name.substring(0, pos);
+ }
+ }
+
+ @Override
+ public String getLocation() {
+ return location;
+ }
+
+ @Override
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @Override
+ public String getShortName() {
+ return shortName;
+ }
+
+ @Override
+ public String getTypeName() {
+ return name;
+ }
+
+ @Override
+ public String readSource() {
+ if (resource != null) {
+ InputStream contents = resource.openContents();
+ return Util.readStreamAsString(contents);
+ }
+ return null;
+ }
+
+ Resource getResource() {
+ return resource;
+ }
+
+ void invalidate() {
+ resource = null;
+ }
+ }
+
+ /**
+ * The last resource set returned by my oracle.
+ */
+ private Set<Resource> cachedResources = Collections.emptySet();
+
+ /**
+ * An unmodifiable set of exposedClassNames to return to a client.
+ */
+ private Set<String> exposedClassNames = Collections.emptySet();
+
+ /**
+ * An unmodifiable set of exposedSourceFiles to return to a client.
+ */
+ private Set<JavaSourceFile> exposedSourceFiles = Collections.emptySet();
+
+ /**
+ * An unmodifiable source map to return to a client.
+ */
+ private Map<String, JavaSourceFile> exposedSourceMap = Collections.emptyMap();
+
+ /**
+ * My resource oracle.
+ */
+ private final ResourceOracle oracle;
+
+ /**
+ * My internal set of source files.
+ */
+ private final Set<JavaSourceFileImpl> sourceFiles = new HashSet<JavaSourceFileImpl>();
+
+ public JavaSourceOracleImpl(ResourceOracle oracle) {
+ this.oracle = oracle;
+ }
+
+ public Set<String> getClassNames() {
+ refresh();
+ return exposedClassNames;
+ }
+
+ public Set<JavaSourceFile> getSourceFiles() {
+ refresh();
+ return exposedSourceFiles;
+ }
+
+ public Map<String, JavaSourceFile> getSourceMap() {
+ refresh();
+ return exposedSourceMap;
+ }
+
+ private void refresh() {
+ Set<Resource> newResources = oracle.getResources();
+ if (newResources == cachedResources) {
+ // We're up to date.
+ return;
+ }
+
+ // Divide resources into changed and unchanged.
+ Set<Resource> unchanged = new HashSet<Resource>(cachedResources);
+ unchanged.retainAll(newResources);
+
+ Set<Resource> changed = new HashSet<Resource>(newResources);
+ changed.removeAll(unchanged);
+
+ // First remove any stale source files.
+ for (Iterator<JavaSourceFileImpl> it = sourceFiles.iterator(); it.hasNext();) {
+ JavaSourceFileImpl sourceFile = it.next();
+ if (!unchanged.contains(sourceFile.getResource())) {
+ sourceFile.invalidate();
+ it.remove();
+ }
+ }
+
+ // Then add any new source files.
+ for (Resource newResource : changed) {
+ sourceFiles.add(new JavaSourceFileImpl(newResource));
+ }
+
+ // Finally rebuild the unmodifiable views.
+ Map<String, JavaSourceFile> sourceMap = new HashMap<String, JavaSourceFile>();
+ for (JavaSourceFileImpl sourceFile : sourceFiles) {
+ sourceMap.put(sourceFile.getTypeName(), sourceFile);
+ }
+ exposedSourceMap = Collections.unmodifiableMap(sourceMap);
+ exposedClassNames = Collections.unmodifiableSet(sourceMap.keySet());
+ HashSet<JavaSourceFile> sourceFilesConstantLookup = new HashSet<JavaSourceFile>(
+ sourceMap.values());
+ exposedSourceFiles = Collections.unmodifiableSet(sourceFilesConstantLookup);
+
+ // Record the update.
+ cachedResources = newResources;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/Shared.java b/dev/core/src/com/google/gwt/dev/javac/impl/Shared.java
new file mode 100644
index 0000000..3cf1613
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/Shared.java
@@ -0,0 +1,188 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JConstructor;
+import com.google.gwt.core.ext.typeinfo.JField;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JPackage;
+import com.google.gwt.core.ext.typeinfo.JParameter;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.util.tools.Utility;
+
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A grab bag of utility functions useful for dealing with java files.
+ */
+public class Shared {
+
+ public static final int MOD_ABSTRACT = 0x00000001;
+ public static final int MOD_FINAL = 0x00000002;
+ public static final int MOD_NATIVE = 0x00000004;
+ public static final int MOD_PRIVATE = 0x00000008;
+ public static final int MOD_PROTECTED = 0x00000010;
+ public static final int MOD_PUBLIC = 0x00000020;
+ public static final int MOD_STATIC = 0x00000040;
+ public static final int MOD_TRANSIENT = 0x00000080;
+ public static final int MOD_VOLATILE = 0x00000100;
+ public static final JClassType[] NO_JCLASSES = new JClassType[0];
+ public static final JConstructor[] NO_JCTORS = new JConstructor[0];
+ public static final JField[] NO_JFIELDS = new JField[0];
+ public static final JMethod[] NO_JMETHODS = new JMethod[0];
+ public static final JPackage[] NO_JPACKAGES = new JPackage[0];
+ public static final JParameter[] NO_JPARAMS = new JParameter[0];
+ public static final JType[] NO_JTYPES = new JType[0];
+ public static final String[][] NO_STRING_ARR_ARR = new String[0][];
+ public static final String[] NO_STRINGS = new String[0];
+
+ public static int bindingToModifierBits(FieldBinding binding) {
+ int bits = 0;
+ bits |= (binding.isPublic() ? MOD_PUBLIC : 0);
+ bits |= (binding.isPrivate() ? MOD_PRIVATE : 0);
+ bits |= (binding.isProtected() ? MOD_PROTECTED : 0);
+ bits |= (binding.isStatic() ? MOD_STATIC : 0);
+ bits |= (binding.isTransient() ? MOD_TRANSIENT : 0);
+ bits |= (binding.isFinal() ? MOD_FINAL : 0);
+ bits |= (binding.isVolatile() ? MOD_VOLATILE : 0);
+ return bits;
+ }
+
+ public static int bindingToModifierBits(MethodBinding binding) {
+ int bits = 0;
+ bits |= (binding.isPublic() ? MOD_PUBLIC : 0);
+ bits |= (binding.isPrivate() ? MOD_PRIVATE : 0);
+ bits |= (binding.isProtected() ? MOD_PROTECTED : 0);
+ bits |= (binding.isStatic() ? MOD_STATIC : 0);
+ bits |= (binding.isFinal() ? MOD_FINAL : 0);
+ bits |= (binding.isNative() ? MOD_NATIVE : 0);
+ bits |= (binding.isAbstract() ? MOD_ABSTRACT : 0);
+ return bits;
+ }
+
+ public static int bindingToModifierBits(ReferenceBinding binding) {
+ int bits = 0;
+ bits |= (binding.isPublic() ? MOD_PUBLIC : 0);
+ bits |= (binding.isPrivate() ? MOD_PRIVATE : 0);
+ bits |= (binding.isProtected() ? MOD_PROTECTED : 0);
+ bits |= (binding.isStatic() ? MOD_STATIC : 0);
+ bits |= (binding.isFinal() ? MOD_FINAL : 0);
+ bits |= (binding.isAbstract() ? MOD_ABSTRACT : 0);
+ return bits;
+ }
+
+ public static String getPackageName(String qualifiedTypeName) {
+ int pos = qualifiedTypeName.lastIndexOf('.');
+ return (pos < 0) ? "" : qualifiedTypeName.substring(0, pos);
+ }
+
+ public static String getPackageNameFromBinary(String binaryName) {
+ int pos = binaryName.lastIndexOf('/');
+ return (pos < 0) ? "" : binaryName.substring(0, pos).replace('/', '.');
+ }
+
+ public static String getShortName(String qualifiedTypeName) {
+ int pos = qualifiedTypeName.lastIndexOf('.');
+ return (pos < 0) ? qualifiedTypeName : qualifiedTypeName.substring(pos + 1);
+ }
+
+ public static String makeTypeName(String packageName, String shortName) {
+ if (packageName.length() == 0) {
+ return shortName;
+ } else {
+ return packageName + '.' + shortName;
+ }
+ }
+
+ public static String readContent(InputStream content) {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ for (int readCount = content.read(buf); readCount > 0; readCount = content.read(buf)) {
+ out.write(buf, 0, readCount);
+ }
+ return Util.toString(out.toByteArray());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ Utility.close(content);
+ }
+ }
+
+ public static String toPath(String qualifiedTypeName) {
+ return qualifiedTypeName.replace('.', '/') + ".java";
+ }
+
+ public static String toTypeName(String path) {
+ assert (path.endsWith(".java"));
+ path = path.substring(0, path.lastIndexOf('.'));
+ return path.replace('/', '.');
+ }
+
+ static String[] modifierBitsToNames(int bits) {
+ List<String> strings = new ArrayList<String>();
+
+ // The order is based on the order in which we want them to appear.
+ //
+ if (0 != (bits & MOD_PUBLIC)) {
+ strings.add("public");
+ }
+
+ if (0 != (bits & MOD_PRIVATE)) {
+ strings.add("private");
+ }
+
+ if (0 != (bits & MOD_PROTECTED)) {
+ strings.add("protected");
+ }
+
+ if (0 != (bits & MOD_STATIC)) {
+ strings.add("static");
+ }
+
+ if (0 != (bits & MOD_ABSTRACT)) {
+ strings.add("abstract");
+ }
+
+ if (0 != (bits & MOD_FINAL)) {
+ strings.add("final");
+ }
+
+ if (0 != (bits & MOD_NATIVE)) {
+ strings.add("native");
+ }
+
+ if (0 != (bits & MOD_TRANSIENT)) {
+ strings.add("transient");
+ }
+
+ if (0 != (bits & MOD_VOLATILE)) {
+ strings.add("volatile");
+ }
+
+ return strings.toArray(NO_STRINGS);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java
new file mode 100644
index 0000000..4ad2541
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java
@@ -0,0 +1,65 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.JavaSourceFile;
+
+/**
+ * A compilation unit that was generated.
+ */
+public class SourceFileCompilationUnit extends CompilationUnit {
+
+ private String sourceCode;
+ private JavaSourceFile sourceFile;
+
+ public SourceFileCompilationUnit(JavaSourceFile sourceFile) {
+ this.sourceFile = sourceFile;
+ }
+
+ @Override
+ public String getDisplayLocation() {
+ return sourceFile.getLocation();
+ }
+
+ @Override
+ public String getSource() {
+ if (sourceCode == null) {
+ sourceCode = sourceFile.readSource();
+ }
+ return sourceCode;
+ }
+
+ public JavaSourceFile getSourceFile() {
+ return sourceFile;
+ }
+
+ @Override
+ public String getTypeName() {
+ return sourceFile.getTypeName();
+ }
+
+ @Override
+ public boolean isGenerated() {
+ return false;
+ }
+
+ @Override
+ protected void dumpSource() {
+ sourceCode = null;
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
index b575d62..885ef4b 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
@@ -16,9 +16,12 @@
package com.google.gwt.dev.jdt;
import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.TreeLogger.HelpInfo;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.GWTProblem;
+import com.google.gwt.dev.javac.JdtCompiler.CompilationUnitAdapter;
+import com.google.gwt.dev.javac.impl.Shared;
import com.google.gwt.dev.util.CharArrayComparator;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.PerfLogger;
@@ -59,22 +62,6 @@
public abstract class AbstractCompiler {
/**
- * A policy that can be set to affect which
- * {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration
- * CompilationUnitDeclarations} the compiler processes.
- */
- public interface CachePolicy {
-
- /**
- * Return true if <code>cud</code> should be processed, otherwise false.
- *
- * @param cud a not <code>null</code> unit
- * @return true iff <code>cud</code> should be fully processed
- */
- boolean shouldProcess(CompilationUnitDeclaration cud);
- }
-
- /**
* Adapted to hook the processing of compilation unit declarations so as to be
* able to add additional compilation units based on the results of
* previously-compiled ones. Examples of cases where this is useful include
@@ -105,11 +92,6 @@
long processBeginNanos = System.nanoTime();
- if (!cachePolicy.shouldProcess(cud)) {
- jdtProcessNanos += System.nanoTime() - processBeginNanos;
- return;
- }
-
// The following block of code is a copy of super.process(cud, index),
// with the modification that cud.generateCode is conditionally called
// based on doGenerateBytes
@@ -313,34 +295,11 @@
TreeLogger logger = threadLogger.branch(TreeLogger.SPAM,
"Compiler is asking about '" + qname + "'", null);
- if (sourceOracle.isPackage(qname)) {
+ if (isPackage(qname)) {
logger.log(TreeLogger.SPAM, "Found to be a package", null);
return null;
}
- // Try to find the compiled type in the cache.
- //
- ByteCode byteCode = doGetByteCodeFromCache(logger, qname);
- if (byteCode != null) {
- // Return it as a binary type to JDT.
- //
- byte[] classBytes = byteCode.getBytes();
- char[] loc = byteCode.getLocation().toCharArray();
- try {
- logger.log(TreeLogger.SPAM, "Found cached bytes", null);
- ClassFileReader cfr = new ClassFileReader(classBytes, loc);
- NameEnvironmentAnswer out = new NameEnvironmentAnswer(cfr, null);
- nameEnvironmentAnswerForTypeName.put(qname, out);
- return out;
- } catch (ClassFormatException e) {
- // Bad bytecode in the cache. Remove it from the cache.
- //
- String msg = "Bad bytecode for '" + qname + "'";
- compiler.problemReporter.abortDueToInternalError(msg);
- return null;
- }
- }
-
// Didn't find it in the cache, so let's compile from source.
// Strip off the inner types, if any
//
@@ -353,49 +312,40 @@
return (nameEnvironmentAnswerForTypeName.get(qname));
}
}
- CompilationUnitProvider cup;
- try {
- cup = sourceOracle.findCompilationUnit(logger, qname);
- if (cup != null) {
- logger.log(TreeLogger.SPAM, "Found type in compilation unit: "
- + cup.getLocation(), null);
- ICompilationUnitAdapter unit = new ICompilationUnitAdapter(cup);
- NameEnvironmentAnswer out = new NameEnvironmentAnswer(unit, null);
- nameEnvironmentAnswerForTypeName.put(qname, out);
- return out;
- } else {
- ClassLoader classLoader = getClassLoader();
- URL resourceURL = classLoader.getResource(className.replace('.', '/')
- + ".class");
- if (resourceURL != null) {
- /*
- * We know that there is a .class file that matches the name that we
- * are looking for. However, at least on OSX, this lookup is case
- * insensitive so we need to use Class.forName to effectively verify
- * the case.
- */
- if (isBinaryType(classLoader, className)) {
- byte[] classBytes = Util.readURLAsBytes(resourceURL);
- ClassFileReader cfr;
- try {
- cfr = new ClassFileReader(classBytes, null);
- NameEnvironmentAnswer out = new NameEnvironmentAnswer(cfr, null);
- nameEnvironmentAnswerForTypeName.put(qname, out);
- return out;
- } catch (ClassFormatException e) {
- // Ignored.
- }
+ CompilationUnit unit = findCompilationUnit(qname);
+ if (unit != null) {
+ logger.log(TreeLogger.SPAM, "Found type in compilation unit: "
+ + unit.getDisplayLocation());
+ ICompilationUnit icu = new CompilationUnitAdapter(unit);
+ NameEnvironmentAnswer out = new NameEnvironmentAnswer(icu, null);
+ nameEnvironmentAnswerForTypeName.put(qname, out);
+ return out;
+ } else {
+ ClassLoader classLoader = getClassLoader();
+ URL resourceURL = classLoader.getResource(className.replace('.', '/')
+ + ".class");
+ if (resourceURL != null) {
+ /*
+ * We know that there is a .class file that matches the name that we
+ * are looking for. However, at least on OSX, this lookup is case
+ * insensitive so we need to use Class.forName to effectively verify
+ * the case.
+ */
+ if (isBinaryType(classLoader, className)) {
+ byte[] classBytes = Util.readURLAsBytes(resourceURL);
+ ClassFileReader cfr;
+ try {
+ cfr = new ClassFileReader(classBytes, null);
+ NameEnvironmentAnswer out = new NameEnvironmentAnswer(cfr, null);
+ nameEnvironmentAnswerForTypeName.put(qname, out);
+ return out;
+ } catch (ClassFormatException e) {
+ // Ignored.
}
}
-
- logger.log(TreeLogger.SPAM, "Not a known type", null);
- return null;
}
- } catch (UnableToCompleteException e) {
- // It was found, but something went really wrong trying to get it.
- //
- String msg = "Error acquiring source for '" + qname + "'";
- compiler.problemReporter.abortDueToInternalError(msg);
+
+ logger.log(TreeLogger.SPAM, "Not a known type", null);
return null;
}
}
@@ -409,7 +359,7 @@
String packageName = String.valueOf(pathChars);
if (knownPackages.contains(packageName)) {
return true;
- } else if (sourceOracle.isPackage(packageName)
+ } else if (isPackage(packageName)
|| isPackage(getClassLoader(), packageName)) {
// Grow our own list to spare calls into the host.
//
@@ -442,6 +392,10 @@
String packageAsPath = packageName.replace('.', '/');
return classLoader.getResource(packageAsPath) != null;
}
+
+ private boolean isPackage(String packageName) {
+ return packages.contains(packageName);
+ }
}
private static final Comparator<CompilationUnitDeclaration> CUD_COMPARATOR = new Comparator<CompilationUnitDeclaration>() {
@@ -468,16 +422,10 @@
}
};
- private static final CachePolicy DEFAULT_POLICY = new CachePolicy() {
- public boolean shouldProcess(CompilationUnitDeclaration cud) {
- return true;
- }
- };
+ protected final CompilationState compilationState;
protected final ThreadLocalTreeLoggerProxy threadLogger = new ThreadLocalTreeLoggerProxy();
- private CachePolicy cachePolicy = DEFAULT_POLICY;
-
private final CompilerImpl compiler;
private final boolean doGenerateBytes;
@@ -486,12 +434,11 @@
private final Map<String, NameEnvironmentAnswer> nameEnvironmentAnswerForTypeName = new HashMap<String, NameEnvironmentAnswer>();
- private final SourceOracle sourceOracle;
+ private final Set<String> packages = new HashSet<String>();
- private final Map<String, ICompilationUnit> unitsByTypeName = new HashMap<String, ICompilationUnit>();
-
- protected AbstractCompiler(SourceOracle sourceOracle, boolean doGenerateBytes) {
- this.sourceOracle = sourceOracle;
+ protected AbstractCompiler(CompilationState compilationState,
+ boolean doGenerateBytes) {
+ this.compilationState = compilationState;
this.doGenerateBytes = doGenerateBytes;
rememberPackage("");
@@ -528,30 +475,14 @@
probFact);
}
- public CachePolicy getCachePolicy() {
- return cachePolicy;
- }
-
- public final void invalidateUnitsInFiles(Set<String> typeNames) {
- // StandardSourceOracle has its own cache that needs to be cleared
- // out. Short of modifying the interface SourceOracle to have an
- // invalidateCups, this check is needed.
- if (sourceOracle instanceof StandardSourceOracle) {
- StandardSourceOracle sso = (StandardSourceOracle) sourceOracle;
- sso.invalidateCups(typeNames);
- }
- for (String qname : typeNames) {
- unitsByTypeName.remove(qname);
- nameEnvironmentAnswerForTypeName.remove(qname);
- }
- }
-
- public void setCachePolicy(CachePolicy policy) {
- this.cachePolicy = policy;
- }
-
protected final CompilationUnitDeclaration[] compile(TreeLogger logger,
ICompilationUnit[] units) {
+ // Initialize the packages list.
+ for (CompilationUnit unit : compilationState.getCompilationUnits()) {
+ String packageName = Shared.getPackageName(unit.getTypeName());
+ addPackages(packageName);
+ }
+
// Any additional compilation units that are found to be needed will be
// pulled in while procssing compilation units. See CompilerImpl.process().
//
@@ -596,53 +527,18 @@
return Empty.STRINGS;
}
- /**
- * Checks to see if we already have the bytecode definition of the requested
- * type. By default we compile everything from source, so we never have it
- * unless a subclass overrides this method.
- */
- @SuppressWarnings("unused")
- // overrider may use unused parameter
- protected ByteCode doGetByteCodeFromCache(TreeLogger logger,
- String binaryTypeName) {
- return null;
- }
-
- /**
- * Finds a compilation unit for the given type. This is often used to
- * bootstrap compiles since during compiles, the compiler will directly ask
- * the name environment internally, bypassing this call.
- */
- protected ICompilationUnit getCompilationUnitForType(TreeLogger logger,
- String binaryTypeName) throws UnableToCompleteException {
-
- // We really look for the topmost type rather than a nested type.
- //
- String top = stripNestedTypeNames(binaryTypeName);
-
- // Check the cache.
- //
- ICompilationUnit unit = unitsByTypeName.get(top);
- if (unit != null) {
- return unit;
+ protected CompilationUnit findCompilationUnit(String qname) {
+ // Build the initial set of compilation units.
+ Map<String, CompilationUnit> unitMap = compilationState.getCompilationUnitMap();
+ CompilationUnit unit = unitMap.get(qname);
+ while (unit == null) {
+ int pos = qname.lastIndexOf('.');
+ if (pos < 0) {
+ return null;
+ }
+ qname = qname.substring(0, pos);
+ unit = unitMap.get(qname);
}
-
- // Not cached, so actually look for it.
- //
- CompilationUnitProvider cup = sourceOracle.findCompilationUnit(logger, top);
- if (cup == null) {
- // Could not find the starting type.
- //
- String s = "Unable to find compilation unit for type '" + top + "'";
- logger.log(TreeLogger.WARN, s, null);
- throw new UnableToCompleteException();
- }
-
- // Create a cup adapter and cache it.
- //
- unit = new ICompilationUnitAdapter(cup);
- unitsByTypeName.put(top, unit);
-
return unit;
}
@@ -673,20 +569,19 @@
return compiler.resolvePossiblyNestedType(typeName);
}
- SourceOracle getSourceOracle() {
- return sourceOracle;
- }
-
- private String stripNestedTypeNames(String binaryTypeName) {
- int i = binaryTypeName.lastIndexOf('.');
- if (i == -1) {
- i = 0;
+ private void addPackages(String packageName) {
+ if (packages.contains(packageName)) {
+ return;
}
- int j = binaryTypeName.indexOf('$', i);
- if (j != -1) {
- return binaryTypeName.substring(0, j);
- } else {
- return binaryTypeName;
+ while (true) {
+ packages.add(String.valueOf(packageName));
+ int pos = packageName.lastIndexOf('.');
+ if (pos > 0) {
+ packageName = packageName.substring(0, pos);
+ } else {
+ packages.add("");
+ break;
+ }
}
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
deleted file mode 100644
index 5ae0c7e..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A facade around the JDT compiler to make many repeated compiles as fast as
- * possible, where the result of each compile is a fully-resolved abstract
- * syntax tree that can be walked for detailed analysis.
- */
-public class AstCompiler extends AbstractCompiler {
-
- /**
- * Manages the caching of <code>CompilationUnitDeclaration</code>.
- */
- private class CompilationUnitDeclarationCache {
-
- private final Map<String, Long> lastModified = new HashMap<String, Long>();
-
- private final Map<String, ArrayList<CompilationUnitDeclaration>> map = new HashMap<String, ArrayList<CompilationUnitDeclaration>>();
-
- public void remove(String newLoc) {
- map.remove(newLoc);
- }
-
- private void add(String location, CompilationUnitDeclaration item) {
- File file = new File(location);
- if (file.exists()) {
- lastModified.put(location, new Long(file.lastModified()));
- }
- if (!map.containsKey(location)) {
- map.put(location, new ArrayList<CompilationUnitDeclaration>());
- }
- get(location).add(item);
- }
-
- private boolean containsKey(String location) {
- return map.containsKey(location);
- }
-
- private List<CompilationUnitDeclaration> get(Object key) {
- return map.get(key);
- }
-
- private void removeAll(Collection<String> c) {
- map.keySet().removeAll(c);
- }
- }
-
- private final CompilationUnitDeclarationCache cachedResults = new CompilationUnitDeclarationCache();
- private final boolean disableChecks;
-
- public AstCompiler(SourceOracle sourceOracle) {
- super(sourceOracle, false);
- this.disableChecks = false;
- }
-
- public AstCompiler(SourceOracle sourceOracle, boolean disableChecks) {
- super(sourceOracle, false);
- this.disableChecks = disableChecks;
- }
-
- public CompilationUnitDeclaration[] getChangedCompilationUnitDeclarations(
- TreeLogger logger, ICompilationUnit[] units) {
- List<ICompilationUnit> allUnits = Arrays.asList(units);
- List<ICompilationUnitAdapter> newUnits = new ArrayList<ICompilationUnitAdapter>();
-
- // Check for newer units that need to be processed.
- for (Iterator<ICompilationUnit> iter = allUnits.iterator(); iter.hasNext();) {
- ICompilationUnitAdapter adapter = (ICompilationUnitAdapter) iter.next();
- CompilationUnitProvider cup = adapter.getCompilationUnitProvider();
- String location = cup.getLocation();
- if (!(cachedResults.containsKey(location))) {
- newUnits.add(adapter);
- }
- }
- ICompilationUnit[] toBeProcessed = new ICompilationUnit[newUnits.size()];
- newUnits.toArray(toBeProcessed);
- CompilationUnitDeclaration[] newCuds = compile(logger, toBeProcessed);
-
- // Put new cuds into cache.
- List<CompilationUnitDeclaration> cudResults = new ArrayList<CompilationUnitDeclaration>();
- for (int i = 0; i < newCuds.length; i++) {
- CompilationUnitDeclaration newCud = newCuds[i];
- String newLoc = String.valueOf(newCud.getFileName());
- cachedResults.remove(newLoc);
- cachedResults.add(newLoc, newCud);
- cudResults.add(newCud);
- }
-
- return cudResults.toArray(new CompilationUnitDeclaration[] {});
- }
-
- public void invalidateChangedFiles(Set<String> changedFiles,
- Set<String> typeNames) {
- cachedResults.removeAll(changedFiles);
- invalidateUnitsInFiles(typeNames);
- }
-
- @Override
- protected void doCompilationUnitDeclarationValidation(
- CompilationUnitDeclaration cud, TreeLogger logger) {
- if (!disableChecks) {
- JSORestrictionsChecker.check(cud);
- LongFromJSNIChecker.check(cud);
- BinaryTypeReferenceRestrictionsChecker.check(cud);
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/ByteCode.java b/dev/core/src/com/google/gwt/dev/jdt/ByteCode.java
deleted file mode 100644
index d44dcf3..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/ByteCode.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.dev.About;
-
-import java.io.Serializable;
-
-/**
- * Represents bytecode for a cached class.
- */
-public class ByteCode implements Serializable {
-
- private static final String systemString = System.getProperty(
- "java.class.path", ".");
-
- private static final String systemStringAsIdentifier = About.GWT_VERSION
- + "_" + systemString.hashCode() + "_jsniMethods";
-
- /**
- * This method returns the current system identifier, used to detect changes
- * in the environment that would make cached data unusable.
- *
- * @return the current system identifier, which is sensitive to classpath and
- * os changes as well as GWT version changes
- */
- public static String getCurrentSystemIdentifier() {
- return systemStringAsIdentifier;
- }
-
- private final String binaryTypeName;
-
- private final byte[] bytes;
-
- private final String location;
-
- private final String version;
-
- private final boolean isTransient;
-
- /**
- * Specifies the bytecode for a given type.
- */
- public ByteCode(String binaryTypeName, byte[] bytes, String location,
- boolean isTransient) {
- this.binaryTypeName = binaryTypeName;
- this.bytes = bytes;
- this.location = location;
- this.version = systemStringAsIdentifier;
- this.isTransient = isTransient;
- }
-
- public String getBinaryTypeName() {
- return binaryTypeName;
- }
-
- public byte[] getBytes() {
- return bytes;
- }
-
- public String getLocation() {
- return location;
- }
-
- public String getSystemIdentifier() {
- return version;
- }
-
- public boolean isTransient() {
- return isTransient;
- }
-
- // We explicitly do not set serialVersionUID, as it is generated
- // automatically, and is more sensitive to class file changes than if
- // it were generated manually.
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/ByteCodeCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/ByteCodeCompiler.java
deleted file mode 100644
index f1d9c54..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/ByteCodeCompiler.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2007 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.ClassFile;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
-import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-
-/**
- * A facade around the JDT compiler to manage on-demand Java source to bytecode
- * compilation, caching compiled bytecode where possible.
- */
-public class ByteCodeCompiler extends AbstractCompiler {
-
- private final CacheManager cacheManager;
-
- /**
- * Creates a bytecode compiler for use not in hosted mode. All bytecode will
- * be thrown away after reload.
- *
- * @param sourceOracle used to find the source
- */
- public ByteCodeCompiler(SourceOracle sourceOracle) {
- super(sourceOracle, true);
- this.cacheManager = new CacheManager();
- }
-
- /**
- * Creates a byte code compiler given the supplied sourceOracle (to find the
- * source) and the supplied cacheManager (to keep the bytecode and other
- * info). If the cacheManager has a cacheDir, it will keep bytecode across
- * reload, and load them from the cacheDir on startup. Otherwise, each reload
- * will clear the cache. In hosted mode, the cacheManager used to create this
- * object should be the same one used to create the typeOracleBuilder.
- *
- * @param sourceOracle used to find the source
- * @param cacheManager used to keep the cached information
- */
- public ByteCodeCompiler(SourceOracle sourceOracle, CacheManager cacheManager) {
- super(sourceOracle, true);
- this.cacheManager = cacheManager;
- }
-
- /**
- * Get the bytecode for the specified type.
- *
- * @param binaryTypeName the binary type name to look up or compile
- */
- public byte[] getClassBytes(TreeLogger logger, String binaryTypeName)
- throws UnableToCompleteException {
-
- // We use a thread logger proxy because we can't wind the logger through
- // JDT directly.
- //
- String msg = "Getting bytecode for '" + binaryTypeName + "'";
- logger = logger.branch(TreeLogger.SPAM, msg, null);
-
- TreeLogger oldLogger = threadLogger.push(logger);
- try {
-
- // Check the bytecode cache in case we've already compiled it.
- //
- ByteCode byteCode = doGetByteCodeFromCache(logger, binaryTypeName);
- if (byteCode != null) {
- // We have it already.
- //
- return byteCode.getBytes();
- }
-
- // Need to compile it. It could be the case that we have tried before and
- // failed, but on the off chance that it's been fixed since then, we adopt
- // a policy of always trying to recompile if we don't have it cached.
- //
- ICompilationUnit start = getCompilationUnitForType(logger, binaryTypeName);
- compile(logger, new ICompilationUnit[] {start});
-
- // Check the cache again. If it's there now, we succeeded.
- // If it isn't there now, we've already logged the error.
- //
- byteCode = doGetByteCodeFromCache(logger, binaryTypeName);
- if (byteCode != null) {
- return byteCode.getBytes();
- } else {
- throw new UnableToCompleteException();
- }
- } finally {
- threadLogger.pop(oldLogger);
- }
- }
-
- /**
- * Prevents the compile process from ever trying to compile these types from
- * source. This is used for special types that would not compile correctly
- * from source.
- *
- * @param binaryTypeName the binary name of the specified type
- */
- public void putClassBytes(TreeLogger logger, String binaryTypeName,
- byte[] bytes, String location) {
-
- // We must remember the package name independently in case this is a type
- // the host doesn't actually know about.
- //
- String pkgName = "";
- int lastDot = binaryTypeName.lastIndexOf('.');
- if (lastDot != -1) {
- pkgName = binaryTypeName.substring(0, lastDot);
- }
- rememberPackage(pkgName);
-
- // Cache the bytes.
- //
- ByteCode byteCode = new ByteCode(binaryTypeName, bytes, location, true);
- cacheManager.acceptIntoCache(logger, binaryTypeName, byteCode);
- }
-
- /**
- * This method removes the bytecode which is no longer current, or if the
- * cacheManager does not have a cacheDir, all the bytecode.
- *
- * @param logger used to describe the results to the user
- */
- public void removeStaleByteCode(TreeLogger logger) {
- cacheManager.removeStaleByteCode(logger, this);
- }
-
- @Override
- protected void doAcceptResult(CompilationResult result) {
- // Take all compiled class files and put them in the byte cache.
- //
- TreeLogger logger = getLogger();
- ClassFile[] classFiles = result.getClassFiles();
- for (int i = 0; i < classFiles.length; i++) {
- ClassFile classFile = classFiles[i];
- char[][] compoundName = classFile.getCompoundName();
- char[] classNameChars = CharOperation.concatWith(compoundName, '.');
- String className = String.valueOf(classNameChars);
- byte bytes[] = classFile.getBytes();
- String loc = String.valueOf(result.compilationUnit.getFileName());
- boolean isTransient = true;
- if (result.compilationUnit instanceof ICompilationUnitAdapter) {
- ICompilationUnitAdapter unit = (ICompilationUnitAdapter) result.compilationUnit;
- isTransient = unit.getCompilationUnitProvider().isTransient();
- }
- ByteCode byteCode = new ByteCode(className, bytes, loc, isTransient);
- if (cacheManager.acceptIntoCache(logger, className, byteCode)) {
- logger.log(TreeLogger.SPAM, "Successfully compiled and cached '"
- + className + "'", null);
- }
- }
- }
-
- /**
- * Checks the cache for bytecode for the specified binary type name. Silently
- * removes and pretends it didn't see any bytecode that is out-of-date with
- * respect to the compilation unit that provides it.
- */
- @Override
- protected ByteCode doGetByteCodeFromCache(TreeLogger logger,
- String binaryTypeName) {
- return cacheManager.getByteCode(binaryTypeName);
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java b/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java
deleted file mode 100644
index c6895db..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.core.ext.typeinfo.HasMetaData;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.shell.JavaScriptHost;
-import com.google.gwt.dev.shell.JsniMethods;
-import com.google.gwt.dev.shell.ShellGWT;
-import com.google.gwt.dev.shell.ShellJavaScriptHost;
-import com.google.gwt.dev.shell.JsniMethods.JsniMethod;
-import com.google.gwt.dev.util.PerfLogger;
-import com.google.gwt.dev.util.Util;
-
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.Javadoc;
-import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
-import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
-import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
-import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
-import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.AbstractMap;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * CacheManager manages all the caching used to speed up hosted mode startup and
- * refresh, and manages the invalidations required to ensure that changes are
- * reflected correctly on reload.
- */
-public class CacheManager {
-
- /**
- * Maps SourceTypeBindings to their associated types.
- */
- static class Mapper {
- private final Map<ReferenceBinding, JClassType> map = new IdentityHashMap<ReferenceBinding, JClassType>();
-
- public JClassType get(ReferenceBinding referenceBinding) {
- JClassType type = map.get(referenceBinding);
- return type;
- }
-
- public void put(ReferenceBinding binding, JClassType type) {
- boolean firstPut = (null == map.put(binding, type));
- assert (firstPut);
- }
-
- public void reset() {
- map.clear();
- }
- }
-
- /**
- * This class is a very simple multi-valued map.
- */
- private static class Dependencies {
- private Map<String, HashSet<String>> map = new HashMap<String, HashSet<String>>();
-
- /**
- * This method adds <code>item</code> to the list stored under
- * <code>key</code>.
- *
- * @param key the key used to access the list
- * @param item the item to be added to the list
- */
- private void add(String dependerFilename, String dependeeFilename) {
- if (!map.containsKey(dependeeFilename)) {
- map.put(dependeeFilename, new HashSet<String>());
- }
-
- get(dependeeFilename).add(dependerFilename);
- }
-
- /**
- * This method gets the list stored under <code>key</code>.
- *
- * @param key the key used to access the list.
- * @return the list stored under <code>key</code>
- */
- private Set<String> get(String filename) {
- return map.get(filename);
- }
-
- private Set<String> transitiveClosure(final String filename) {
- String current = filename;
- TreeSet<String> queue = new TreeSet<String>();
- Set<String> finished = new HashSet<String>();
- queue.add(filename);
- while (true) {
- finished.add(current);
- Set<String> children = get(current);
- if (children != null) {
- for (Iterator<String> iter = children.iterator(); iter.hasNext();) {
- String child = iter.next();
- if (!finished.contains(child)) {
- queue.add(child);
- }
- }
- }
- if (queue.size() == 0) {
- return finished;
- } else {
- current = queue.first();
- queue.remove(current);
- }
- }
- }
- }
-
- /**
- * Visit all of the CUDs and extract dependencies. This visitor handles
- * explicit TypeRefs via the onTypeRef method AND it also deals with the
- * gwt.typeArgs annotation.
- *
- * <ol>
- * <li>Extract the list of type names from the gwt.typeArgs annotation</li>
- * <li>For each type name, locate the CUD that defines it</li>
- * <li>Add the referenced CUD as a dependency</li>
- * </ol>
- */
- private final class DependencyVisitor extends TypeRefVisitor {
- private final Dependencies dependencies;
-
- private DependencyVisitor(Dependencies dependencies) {
- this.dependencies = dependencies;
- }
-
- @Override
- public void endVisit(FieldDeclaration fieldDeclaration,
- final MethodScope scope) {
- extractDependenciesFromTypeArgs(fieldDeclaration.javadoc,
- scope.referenceContext());
- }
-
- @Override
- public void endVisit(MethodDeclaration methodDeclaration, ClassScope scope) {
- extractDependenciesFromTypeArgs(methodDeclaration.javadoc,
- scope.referenceContext());
- }
-
- @Override
- protected void onTypeRef(SourceTypeBinding referencedType,
- CompilationUnitDeclaration unitOfReferrer) {
- // If the referenced type belongs to a compilation unit that
- // was changed, then the unit in which it
- // is referenced must also be treated as changed.
- //
- String dependeeFilename = String.valueOf(referencedType.getFileName());
- String dependerFilename = String.valueOf(unitOfReferrer.getFileName());
-
- dependencies.add(dependerFilename, dependeeFilename);
- }
-
- private String combine(String[] strings, int startIndex) {
- StringBuffer sb = new StringBuffer();
- for (int i = startIndex; i < strings.length; i++) {
- String s = strings[i];
- sb.append(s);
- }
- return sb.toString();
- }
-
- /**
- * Extracts additional dependencies based on the gwt.typeArgs annotation.
- * This is not detected by JDT so we need to do it here. We do not perform
- * as strict a parse as the TypeOracle would do.
- *
- * @param javadoc javadoc text
- * @param scope scope that contains the definition
- * @param isField true if the javadoc is associated with a field
- */
- private void extractDependenciesFromTypeArgs(Javadoc javadoc,
- final ReferenceContext scope) {
- if (javadoc == null) {
- return;
- }
- final char[] source = scope.compilationResult().compilationUnit.getContents();
-
- TypeOracleBuilder.parseMetaDataTags(source, new HasMetaData() {
- public void addMetaData(String tagName, String[] values) {
- assert (values != null);
-
- if (!TypeOracle.TAG_TYPEARGS.equals(tagName)) {
- // don't care about non gwt.typeArgs
- return;
- }
-
- if (values.length == 0) {
- return;
- }
-
- Set<String> typeNames = new HashSet<String>();
-
- /*
- * if the first element starts with a "<" then we assume that no
- * parameter name was specified
- */
- int startIndex = 1;
- if (values[0].trim().startsWith("<")) {
- startIndex = 0;
- }
-
- extractTypeNamesFromTypeArg(combine(values, startIndex), typeNames);
-
- Iterator<String> it = typeNames.iterator();
- while (it.hasNext()) {
- String typeName = it.next();
-
- try {
- ICompilationUnit compilationUnit = astCompiler.getCompilationUnitForType(
- TreeLogger.NULL, typeName);
-
- String dependeeFilename = String.valueOf(compilationUnit.getFileName());
- String dependerFilename = String.valueOf(scope.compilationResult().compilationUnit.getFileName());
-
- dependencies.add(dependerFilename, dependeeFilename);
-
- } catch (UnableToCompleteException e) {
- // Purposely ignored
- }
- }
- }
-
- public String[][] getMetaData(String tagName) {
- return null;
- }
-
- public String[] getMetaDataTags() {
- return null;
- }
- }, javadoc);
- }
-
- /**
- * Extracts the type names referenced from a gwt.typeArgs annotation and
- * adds them to the set of type names.
- *
- * @param typeArg a string containing the type args as the user entered them
- * @param typeNames the set of type names referenced in the typeArgs string
- */
- private void extractTypeNamesFromTypeArg(String typeArg,
- Set<String> typeNames) {
- // Remove all whitespace
- typeArg = typeArg.replaceAll("\\\\s", "");
-
- // Remove anything that is not a raw type name
- String[] typeArgs = typeArg.split("[\\[\\]<>,]");
-
- for (int i = 0; i < typeArgs.length; ++i) {
- if (typeArgs[i].length() > 0) {
- typeNames.add(typeArgs[i]);
- }
- }
- }
- }
-
- /**
- * Caches information using a directory, with an in memory cache to prevent
- * unneeded disk access.
- */
- private static class DiskCache extends AbstractMap<String, Object> {
-
- private class FileEntry implements Map.Entry<String, Object> {
-
- private File file;
-
- private FileEntry(File file) {
- this.file = file;
- }
-
- private FileEntry(String className) {
- this(new File(directory, possiblyAddTmpExtension(className)));
- }
-
- private FileEntry(String className, Object o) {
- this(new File(directory, possiblyAddTmpExtension(className)));
- setValue(o);
- }
-
- public String getKey() {
- return possiblyRemoveTmpExtension(file.getName());
- }
-
- public Object getValue() {
- if (!file.exists()) {
- return null;
- }
- try {
- FileInputStream fis = new FileInputStream(file);
- ObjectInputStream ois = new ObjectInputStream(fis);
- Object out = ois.readObject();
- ois.close();
- fis.close();
- return out;
- } catch (IOException e) {
- return null;
- // If we can't read the file, we can't get the item from the cache.
- } catch (ClassNotFoundException e) {
- return null;
- // The class does not match because the serialUID is not correct
- // so we don't want this item anyway.
- }
- }
-
- public void remove() {
- file.delete();
- }
-
- public Object setValue(Object value) {
- Object o = getValue();
- FileOutputStream fos;
- try {
- fos = new FileOutputStream(file);
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- oos.writeObject(value);
- oos.close();
- fos.close();
- } catch (IOException e) {
- markCacheDirectoryUnusable();
- }
- return o;
- }
-
- private long lastModified() {
- return file.lastModified();
- }
- }
-
- private final Map<String, Object> cache = new HashMap<String, Object>();
-
- // May be set to null after the fact if the cache directory becomes
- // unusable.
- private File directory;
-
- public DiskCache(File dirName) {
- if (dirName != null) {
- directory = dirName;
- possiblyCreateCacheDirectory();
- } else {
- directory = null;
- }
- }
-
- @Override
- public void clear() {
- cache.clear();
- if (directory != null) {
- for (Iterator<String> iter = keySet().iterator(); iter.hasNext();) {
- iter.remove();
- }
- }
- }
-
- @Override
- public Set<Entry<String, Object>> entrySet() {
- Set<Entry<String, Object>> out = new HashSet<Entry<String, Object>>() {
- @Override
- public boolean remove(Object o) {
- if (o instanceof Entry) {
- Entry<?, ?> entry = (Entry<?, ?>) o;
- boolean removed = (DiskCache.this.remove(entry.getKey())) != null;
- super.remove(o);
- return removed;
- }
- return false;
- }
- };
- out.addAll(cache.entrySet());
- // No directory means no persistence.
- if (directory != null) {
- possiblyCreateCacheDirectory();
- // Add files not yet loaded into this cache.
- File[] entries = directory.listFiles();
- for (int i = 0; i < entries.length; i++) {
- if (!cache.containsKey(new FileEntry(entries[i]).getKey())) {
- out.add(new FileEntry(entries[i]));
- }
- }
- }
- return out;
- }
-
- public Object get(String key) {
- if (cache.containsKey(key)) {
- return cache.get(key);
- }
- Object value = null;
- if (directory != null) {
- value = new FileEntry(key).getValue();
- cache.put(key, value);
- }
- return value;
- }
-
- @Override
- public Set<String> keySet() {
- Set<String> out = new HashSet<String>() {
- @Override
- public boolean remove(Object o) {
- boolean removed = (DiskCache.this.remove(o)) != null;
- super.remove(o);
- return removed;
- }
- };
- out.addAll(cache.keySet());
- // No directory means no persistence.
- if (directory != null) {
- possiblyCreateCacheDirectory();
- // Add files not yet loaded into this cache.
- File[] entries = directory.listFiles();
- for (int i = 0; i < entries.length; i++) {
- out.add(new FileEntry(entries[i].getName()).getKey());
- }
- }
- return out;
- }
-
- @Override
- public Object put(String key, Object value) {
- return put(key, value, true);
- }
-
- @Override
- public Object remove(Object key) {
- String fileName = (String) key;
- Object out = get(fileName);
- // No directory means no persistence.
- if (directory != null) {
- possiblyCreateCacheDirectory();
- FileEntry e = new FileEntry(fileName);
- e.remove();
- }
- cache.remove(key);
- return out;
- }
-
- private long lastModified(String className) {
- if (directory == null) {
- // we have no file on disk to refer to, so should return the same result
- // as if the file did not exist -- namely 0.
- return 0;
- }
- return new FileEntry(className).lastModified();
- }
-
- /**
- * This method marks the cache directory as being invalid, so we do not try
- * to use it.
- */
- private void markCacheDirectoryUnusable() {
- System.err.println("The directory " + directory.getAbsolutePath()
- + " is not usable as a cache directory");
- directory = null;
- }
-
- /**
- * This is used to ensure that if something wicked happens to the cache
- * directory while we are running, we do not crash.
- */
- private void possiblyCreateCacheDirectory() {
- directory.mkdirs();
- if (!(directory.exists() && directory.canWrite())) {
- markCacheDirectoryUnusable();
- }
- }
-
- private Object put(String key, Object value, boolean persist) {
- Object out = get(key);
-
- // We use toString to match the string value in FileEntry.
- cache.remove(key.toString());
-
- // Writes the file.
- if (persist && directory != null) {
- // This writes the file to the disk and is all that is needed.
- new FileEntry(key, value);
- }
- cache.put(key, value);
- return out;
- }
- }
-
- /**
- * The set of all classes whose bytecode needs to exist as bootstrap bytecode
- * to be taken as given by the bytecode compiler.
- */
- public static final Class<?>[] BOOTSTRAP_CLASSES = new Class<?>[] {
- JavaScriptHost.class, ShellJavaScriptHost.class, ShellGWT.class,
- JsniMethods.class, JsniMethod.class};
-
- /**
- * The set of bootstrap classes, which are marked transient, but are
- * nevertheless not recompiled each time, as they are bootstrap classes.
- */
- private static final Set<String> TRANSIENT_CLASS_NAMES = new HashSet<String>();
-
- static {
- for (Class<?> c : BOOTSTRAP_CLASSES) {
- TRANSIENT_CLASS_NAMES.add(c.getName());
- }
- }
-
- // This method must be outside of DiskCache because of the restriction against
- // defining static methods in inner classes.
- private static String possiblyAddTmpExtension(Object className) {
- String fileName = className.toString();
- if (fileName.indexOf("-") == -1) {
- int hashCode = fileName.hashCode();
- String hashCodeStr = Integer.toHexString(hashCode);
- while (hashCodeStr.length() < 8) {
- hashCodeStr = '0' + hashCodeStr;
- }
- fileName = fileName + "-" + hashCodeStr + ".tmp";
- }
- return fileName;
- }
-
- // This method must be outside of DiskCache because of the restriction against
- // defining static methods in inner classes.
- private static String possiblyRemoveTmpExtension(Object fileName) {
- String className = fileName.toString();
- if (className.indexOf("-") != -1) {
- className = className.split("-")[0];
- }
- return className;
- }
-
- private final Set<CompilationUnitProvider> addedCups = new HashSet<CompilationUnitProvider>();
-
- private final AstCompiler astCompiler;
-
- private final DiskCache byteCodeCache;
-
- private final File cacheDir;
-
- private final Set<String> changedFiles;
-
- private final Map<String, CompilationUnitDeclaration> cudsByFileName;
-
- private final Map<String, CompilationUnitProvider> cupsByLocation = new HashMap<String, CompilationUnitProvider>();
-
- private boolean firstTime = true;
-
- /**
- * Set of {@link CompilationUnitProvider} locations for all of the compilation
- * units generated by {@link com.google.gwt.core.ext.Generator Generator}s.
- *
- * TODO: This seems like it should be a Set of CUPs rather than a set of CUP
- * locations.
- */
- private final Set<String> generatedCupLocations = new HashSet<String>();
-
- private final Set<String> generatedResources = new HashSet<String>();
-
- private final Mapper identityMapper = new Mapper();
-
- private final Set<String> invalidatedTypes = new HashSet<String>();
-
- private final TypeOracle oracle;
-
- private final Map<String, Long> timesByLocation = new HashMap<String, Long>();
-
- private final Map<String, ICompilationUnitAdapter> unitsByCup = new HashMap<String, ICompilationUnitAdapter>();
-
- /**
- * Creates a new <code>CacheManager</code>, creating a new
- * <code>TypeOracle</code>. This constructor does not specify a cache
- * directory, and therefore is to be used in unit tests and executables that
- * do not need caching.
- */
- public CacheManager() {
- this(null, null);
- }
-
- /**
- * Creates a new <code>CacheManager</code>, creating a new
- * <code>TypeOracle</code>. This constructor uses the specified cacheDir,
- * and does cache information across reloads. If the specified cacheDir is
- * null, caching across reloads will be disabled.
- */
- public CacheManager(String cacheDir, TypeOracle oracle) {
- this(cacheDir, oracle, false);
- }
-
- public CacheManager(String cacheDir, TypeOracle oracle, boolean disableChecks) {
- if (oracle == null) {
- this.oracle = new TypeOracle();
- } else {
- this.oracle = oracle;
- }
- changedFiles = new HashSet<String>();
- cudsByFileName = new HashMap<String, CompilationUnitDeclaration>();
- if (cacheDir != null) {
- this.cacheDir = new File(cacheDir);
- this.cacheDir.mkdirs();
- byteCodeCache = new DiskCache(new File(cacheDir, "bytecode"));
- } else {
- this.cacheDir = null;
- byteCodeCache = new DiskCache(null);
- }
- SourceOracleOnTypeOracle sooto = new SourceOracleOnTypeOracle(this.oracle);
- astCompiler = new AstCompiler(sooto, disableChecks);
-
- astCompiler.setCachePolicy(new AstCompiler.CachePolicy() {
- public boolean shouldProcess(CompilationUnitDeclaration cud) {
- ICompilationUnit unit = cud.compilationResult.compilationUnit;
- ICompilationUnitAdapter adapter = ((ICompilationUnitAdapter) unit);
- CompilationUnitProvider cup = adapter.getCompilationUnitProvider();
- return getTypeOracle().findType(cup.getPackageName(),
- cup.getMainTypeName()) == null;
- }
- });
- }
-
- /**
- * Creates a new <code>CacheManager</code>, using the supplied
- * <code>TypeOracle</code>. This constructor does not specify a cache
- * directory, and therefore is to be used in unit tests and executables that
- * do not need caching.
- */
- public CacheManager(TypeOracle typeOracle) {
- this(null, typeOracle);
- }
-
- /**
- * Adds the specified {@link CompilationUnitProvider} to the set of CUPs
- * generated by {@link com.google.gwt.core.ext.Generator Generator}s.
- * Generated <code>CompilationUnitProviders</code> are not cached across
- * reloads.
- */
- public void addGeneratedCup(CompilationUnitProvider generatedCup) {
- assert (generatedCup != null);
-
- generatedCupLocations.add(generatedCup.getLocation());
- }
-
- public void addGeneratedResource(String partialPath) {
- generatedResources.add(partialPath);
- }
-
- /**
- * This method returns the <code>TypeOracle</code> associated with this
- * <code>CacheManager</code>.
- */
- public TypeOracle getTypeOracle() {
- return oracle;
- }
-
- public boolean hasGeneratedResource(String partialPath) {
- return generatedResources.contains(partialPath);
- }
-
- /**
- * This removes all state changed since the last time the typeOracle was run.
- *
- * @param typeOracle
- */
- public void invalidateOnRefresh(TypeOracle typeOracle) {
-
- // If a class is changed, the set of classes in the transitive closure
- // of "refers to" must be marked changed as well.
- // The initial change set is computed in addCompilationUnit.
-
- changedFiles.addAll(generatedCupLocations);
- addDependentsToChangedFiles();
-
- for (Iterator<String> iter = changedFiles.iterator(); iter.hasNext();) {
- String location = iter.next();
- CompilationUnitProvider cup = getCupsByLocation().get(location);
- unitsByCup.remove(location);
- Util.invokeInaccessableMethod(TypeOracle.class,
- "invalidateTypesInCompilationUnit",
- new Class[] {CompilationUnitProvider.class}, typeOracle,
- new Object[] {cup});
- }
-
- /*
- * NOTE: It appears that invalidatedTypes is always empty. Therefore the
- * AstCompiler may not be properly removing types from the changed files.
- */
- astCompiler.invalidateChangedFiles(changedFiles, invalidatedTypes);
- }
-
- /**
- * Ensures that all compilation units generated via generators are removed
- * from the system so that they will be generated again, and thereby take into
- * account input that may have changed since the last reload.
- */
- public void invalidateVolatileFiles() {
- for (Iterator<CompilationUnitProvider> iter = addedCups.iterator(); iter.hasNext();) {
- CompilationUnitProvider cup = iter.next();
- if (isGeneratedCup(cup)) {
- iter.remove();
- }
- }
- generatedResources.clear();
- }
-
- /**
- * This method adds byte.
- *
- * @param logger
- * @param binaryTypeName
- * @param byteCode
- * @return
- */
- boolean acceptIntoCache(TreeLogger logger, String binaryTypeName,
- ByteCode byteCode) {
- synchronized (byteCodeCache) {
- if (getByteCode(binaryTypeName) == null) {
- byteCodeCache.put(binaryTypeName, byteCode, (!byteCode.isTransient()));
- logger.log(TreeLogger.SPAM, "Cached bytecode for " + binaryTypeName,
- null);
- return true;
- } else {
- logger.log(TreeLogger.SPAM, "Bytecode not re-cached for "
- + binaryTypeName, null);
- return false;
- }
- }
- }
-
- /**
- * Adds this compilation unit if it is not present, or is older. Otherwise
- * does nothing.
- *
- * @throws UnableToCompleteException thrown if we cannot figure out when this
- * cup was modified
- */
- void addCompilationUnit(CompilationUnitProvider cup)
- throws UnableToCompleteException {
- Long lastModified = new Long(cup.getLastModified());
- if (isCupUnchanged(cup, lastModified)) {
- return;
- }
- CompilationUnitProvider oldCup = getCup(cup);
- if (oldCup != null) {
- addedCups.remove(oldCup);
- markCupChanged(cup);
- }
- timesByLocation.put(cup.getLocation(), lastModified);
- cupsByLocation.put(cup.getLocation(), cup);
- addedCups.add(cup);
- }
-
- /**
- * This method modifies the field <code>changedFiles</code> to contain all
- * of the additional files that are capable of reaching any of the files
- * currently contained within <code>changedFiles</code>.
- */
- void addDependentsToChangedFiles() {
- final Dependencies dependencies = new Dependencies();
-
- DependencyVisitor trv = new DependencyVisitor(dependencies);
-
- // Find references to type in units that aren't any longer valid.
- //
- for (CompilationUnitDeclaration cud : cudsByFileName.values()) {
- cud.traverse(trv, cud.scope);
- }
-
- Set<String> toTraverse = new HashSet<String>(changedFiles);
- for (Iterator<String> iter = toTraverse.iterator(); iter.hasNext();) {
- String fileName = iter.next();
- changedFiles.addAll(dependencies.transitiveClosure(fileName));
- }
- }
-
- ICompilationUnit findUnitForCup(CompilationUnitProvider cup) {
- if (!unitsByCup.containsKey(cup.getLocation())) {
- unitsByCup.put(cup.getLocation(), new ICompilationUnitAdapter(cup));
- }
- return unitsByCup.get(cup.getLocation());
- }
-
- Set<CompilationUnitProvider> getAddedCups() {
- return addedCups;
- }
-
- AstCompiler getAstCompiler() {
- return astCompiler;
- }
-
- /**
- * Gets the bytecode from the cache, rejecting it if an incompatible change
- * occurred since it was cached.
- */
- ByteCode getByteCode(String binaryTypeName) {
- synchronized (byteCodeCache) {
- ByteCode byteCode = (ByteCode) byteCodeCache.get(binaryTypeName);
- // we do not want bytecode created with a different classpath or os or
- // version of GWT.
- if ((byteCode != null)
- && byteCode.getSystemIdentifier() != null
- && (!(byteCode.getSystemIdentifier().equals(ByteCode.getCurrentSystemIdentifier())))) {
- byteCodeCache.remove(binaryTypeName);
- byteCode = null;
- }
- if (byteCode != null) {
- // Found it.
- //
- return byteCode;
- } else {
- // This type has not been compiled before, or we tried but failed.
- //
- return null;
- }
- }
- }
-
- Set<String> getChangedFiles() {
- return changedFiles;
- }
-
- Map<String, CompilationUnitDeclaration> getCudsByFileName() {
- return cudsByFileName;
- }
-
- CompilationUnitProvider getCup(CompilationUnitProvider cup) {
- return getCupsByLocation().get(cup.getLocation());
- }
-
- Object getCupLastUpdateTime(CompilationUnitProvider cup) {
- return getTimesByLocation().get(cup.getLocation());
- }
-
- Map<String, CompilationUnitProvider> getCupsByLocation() {
- return cupsByLocation;
- }
-
- Mapper getIdentityMapper() {
- return identityMapper;
- }
-
- Map<String, Long> getTimesByLocation() {
- return timesByLocation;
- }
-
- JType getTypeForBinding(ReferenceBinding referenceBinding) {
- return identityMapper.get(referenceBinding);
- }
-
- /**
- * Was this cup, last modified at time lastModified modified since it was last
- * processed by the system?
- */
- boolean isCupUnchanged(CompilationUnitProvider cup, Long lastModified) {
- Long oldTime = (Long) getCupLastUpdateTime(cup);
- if (oldTime != null) {
- if (oldTime.longValue() >= lastModified.longValue()
- && (!cup.isTransient())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * This method is called when a cup is known to have changed. This will ensure
- * that all the types defined in this cup are invalidated.
- *
- * @param cup the cup modified
- */
- void markCupChanged(CompilationUnitProvider cup) {
- changedFiles.add(String.valueOf(cup.getLocation()));
- }
-
- boolean removeFromCache(TreeLogger logger, String binaryTypeName) {
- synchronized (byteCodeCache) {
- if (getByteCode(binaryTypeName) == null) {
- logger.log(TreeLogger.SPAM, "Bytecode for " + binaryTypeName
- + " was not cached, so not removing", null);
- return false;
- } else {
- byteCodeCache.remove(binaryTypeName);
- logger.log(TreeLogger.SPAM, "Bytecode not re-cached for "
- + binaryTypeName, null);
- return false;
- }
- }
- }
-
- /**
- * This method removes all of the bytecode which is out of date from the
- * bytecode cache. The set of files needing to be changed are going to be the
- * set already known to be changed plus those that are out of date in the
- * bytecode cache.
- */
- void removeStaleByteCode(TreeLogger logger, AbstractCompiler compiler) {
- PerfLogger.start("CacheManager.removeStaleByteCode");
-
- if (cacheDir == null) {
- byteCodeCache.clear();
- return;
- }
- if (isFirstTime()) {
- Set<String> classNames = byteCodeCache.keySet();
- for (Iterator<String> iter = classNames.iterator(); iter.hasNext();) {
- String className = iter.next();
- ByteCode byteCode = ((ByteCode) (byteCodeCache.get(className)));
- if (byteCode == null) {
- iter.remove();
- continue;
- }
- String qname = byteCode.getBinaryTypeName();
- if (TRANSIENT_CLASS_NAMES.contains(qname)) {
- continue;
- }
- String location = byteCode.getLocation();
- if (byteCode.isTransient()) {
- // GWT transient classes; no need to test.
- // Either standardGeneratorContext created it
- // in which case we already know it is invalid
- // or its something like GWT and it lives.
- continue;
- }
- String fileName = Util.findFileName(location);
- CompilationUnitDeclaration compilationUnitDeclaration = cudsByFileName.get(location);
- if (compilationUnitDeclaration == null) {
- changedFiles.add(location);
- continue;
- }
- long srcLastModified = Long.MAX_VALUE;
- File srcLocation = new File(fileName);
- if (srcLocation.exists()) {
- srcLastModified = srcLocation.lastModified();
- }
- long byteCodeLastModified = byteCodeCache.lastModified(className);
- if (srcLastModified >= byteCodeLastModified) {
- changedFiles.add(location);
- }
- }
- addDependentsToChangedFiles();
- }
- becomeNotFirstTime();
- invalidateChangedFiles(logger, compiler);
- PerfLogger.end();
- }
-
- void setTypeForBinding(ReferenceBinding binding, JClassType type) {
- identityMapper.put(binding, type);
- }
-
- private void becomeNotFirstTime() {
- firstTime = false;
- }
-
- /**
- * Actually performs the work of removing the invalidated data from the
- * system. At this point, changedFiles should be complete. After this method
- * is called, changedFiles should now be empty, since all invalidation that is
- * needed to be done.
- *
- * @param logger logs the process
- * @param compiler the compiler caches data, so must be invalidated
- */
- private void invalidateChangedFiles(TreeLogger logger,
- AbstractCompiler compiler) {
- Set<String> invalidTypes = new HashSet<String>();
- if (logger.isLoggable(TreeLogger.TRACE)) {
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "The following compilation units have changed since "
- + "the last compilation to bytecode", null);
- for (Iterator<String> iter = changedFiles.iterator(); iter.hasNext();) {
- String filename = iter.next();
- branch.log(TreeLogger.TRACE, filename, null);
- }
- }
- for (String key : byteCodeCache.keySet()) {
- ByteCode byteCode = ((ByteCode) (byteCodeCache.get(key)));
- if (byteCode != null) {
- String location = byteCode.getLocation();
- if (changedFiles.contains(location)) {
- String binaryTypeName = byteCode.getBinaryTypeName();
- invalidTypes.add(binaryTypeName);
- removeFromCache(logger, binaryTypeName);
- }
- }
- }
- compiler.invalidateUnitsInFiles(invalidTypes);
- changedFiles.clear();
- }
-
- private boolean isFirstTime() {
- return firstTime;
- }
-
- private boolean isGeneratedCup(CompilationUnitProvider cup) {
- return generatedCupLocations.contains(cup.getLocation());
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/CompilationUnitProviderWithAlternateSource.java b/dev/core/src/com/google/gwt/dev/jdt/CompilationUnitProviderWithAlternateSource.java
deleted file mode 100644
index adb8005..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/CompilationUnitProviderWithAlternateSource.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-
-/**
- * Wraps an existing compilation unit, retaining the metadata of the original
- * unit but providing modified source.
- */
-public class CompilationUnitProviderWithAlternateSource implements
- CompilationUnitProvider {
- private final CompilationUnitProvider cup;
-
- private final char[] source;
-
- public CompilationUnitProviderWithAlternateSource(
- CompilationUnitProvider cup, char[] source) {
- this.cup = cup;
- this.source = source;
- }
-
- public long getLastModified() throws UnableToCompleteException {
- return cup.getLastModified();
- }
-
- public String getLocation() {
- return cup.getLocation();
- }
-
- public String getMainTypeName() {
- return cup.getMainTypeName();
- }
-
- public String getPackageName() {
- return cup.getPackageName();
- }
-
- public char[] getSource() throws UnableToCompleteException {
- return source;
- }
-
- public boolean isTransient() {
- return cup.isTransient();
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
index 33e6eca..e9e1eab 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jdt;
+import com.google.gwt.dev.javac.GWTProblem;
+
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
diff --git a/dev/core/src/com/google/gwt/dev/jdt/ICompilationUnitAdapter.java b/dev/core/src/com/google/gwt/dev/jdt/ICompilationUnitAdapter.java
deleted file mode 100644
index e483c59..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/ICompilationUnitAdapter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.jdt;
-
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-
-/**
- * Implements <code>ICompilationUnit</code> in terms of a
- * {@link CompilationUnitProvider}.
- */
-public class ICompilationUnitAdapter implements ICompilationUnit {
-
- private final CompilationUnitProvider cup;
-
- public ICompilationUnitAdapter(CompilationUnitProvider cup) {
- assert (cup != null);
- this.cup = cup;
- }
-
- public CompilationUnitProvider getCompilationUnitProvider() {
- return cup;
- }
-
- public char[] getContents() {
- try {
- return cup.getSource();
- } catch (UnableToCompleteException e) {
- return null;
- }
- }
-
- public char[] getFileName() {
- return cup.getLocation().toCharArray();
- }
-
- /**
- * This method is supposed to return the simple class name for this
- * compilation unit. Examples of simple class names would be "String", or
- * "ArrayList".
- *
- * <p>Although JDT allows this method to return null in the cases
- * where this compilation unit is not a package-info class, JDT never
- * constructs a CUP with a null main type, and we should never do so
- * either.</p>
- */
- public char[] getMainTypeName() {
- String typeName = cup.getMainTypeName();
- return typeName.toCharArray();
- }
-
- public char[][] getPackageName() {
- final char[] pkg = cup.getPackageName().toCharArray();
- final char[][] pkgParts = CharOperation.splitOn('.', pkg);
- return pkgParts;
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/SourceOracle.java b/dev/core/src/com/google/gwt/dev/jdt/SourceOracle.java
deleted file mode 100644
index 9853ec2..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/SourceOracle.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-
-/**
- * Abstracts the process of determining which source file contains a given Java
- * type and specifying whether or not a given name is a package.
- */
-public interface SourceOracle {
-
- /**
- * Attempts to find a compilation unit for the specified source type name.
- *
- * @return <code>null</code> if a compilation unit for the specified type
- * was not found or an error prevented the compilation unit from being
- * provided
- */
- CompilationUnitProvider findCompilationUnit(TreeLogger logger,
- String sourceTypeName) throws UnableToCompleteException;
-
- /**
- * Determines whether or not a string is the name of a package. Remember that
- * every part of a package name is also a package. For example, the fact that
- * <code>java.lang</code> is a package implies that <code>java</code> is
- * also a package.
- */
- boolean isPackage(String possiblePackageName);
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/SourceOracleOnTypeOracle.java b/dev/core/src/com/google/gwt/dev/jdt/SourceOracleOnTypeOracle.java
deleted file mode 100644
index 28a7eba..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/SourceOracleOnTypeOracle.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-
-/**
- * Implements a {@link SourceOracle} in terms of a {@link TypeOracle}.
- */
-public class SourceOracleOnTypeOracle implements SourceOracle {
-
- private final TypeOracle typeOracle;
-
- public SourceOracleOnTypeOracle(TypeOracle typeOracle) {
- this.typeOracle = typeOracle;
- }
-
- public CompilationUnitProvider findCompilationUnit(TreeLogger logger,
- String sourceTypeName) {
- JClassType type = typeOracle.findType(sourceTypeName);
- if (type != null) {
- return type.getCompilationUnit();
- }
- return null;
- }
-
- public boolean isPackage(String possiblePackageName) {
- if (typeOracle.findPackage(possiblePackageName) != null) {
- return true;
- } else {
- return false;
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/StandardSourceOracle.java b/dev/core/src/com/google/gwt/dev/jdt/StandardSourceOracle.java
deleted file mode 100644
index e9c923e..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/StandardSourceOracle.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.util.Util;
-
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Provides a mutable compilation service host on top of a
- * {@link com.google.gwt.dev.typeinfo.TypeOracle} as well as providing
- * subclasses an opportunity to substitute their own source to implement
- * special-handling, such as rewriting JSNI source.
- */
-public class StandardSourceOracle implements SourceOracle {
-
- private final Map cupsByTypeName = new HashMap();
-
- private final Set knownPackages = new HashSet();
-
- private final TypeOracle typeOracle;
-
- /**
- * @param typeOracle answers questions about compilation unit locations
- * @param genDir for compilation units whose location does not correspond to a
- * URL that can be opened, their source will be written to this
- * directory to support debugging, or <code>null</code> if the
- * source need not be written to disk
- */
- public StandardSourceOracle(TypeOracle typeOracle) {
- this.typeOracle = typeOracle;
- }
-
- /**
- * Attempts to find the compilation unit for the requested type. Often
- * legitimately returns <code>null</code> because the compilation service
- * does tests to help determine whether a particular symbol refers to a
- * package or a type.
- */
- public final CompilationUnitProvider findCompilationUnit(TreeLogger logger,
- String typeName) throws UnableToCompleteException {
-
- // Check the cache first.
- //
- CompilationUnitProvider cup = (CompilationUnitProvider) cupsByTypeName.get(typeName);
-
- if (cup != null) {
- // Found in cache.
- //
- return cup;
- }
-
- // See if the type oracle can find it.
- //
- JClassType type = typeOracle.findType(typeName);
- if (type != null) {
- // All type oracle types are supposed to know their compilation unit.
- //
- cup = type.getCompilationUnit();
- assert (cup != null);
- }
-
- // Give the subclass a chance to replace the source. This used for JSNI in
- // hosted mode at present but could be used for any source rewriting trick.
- //
- if (cup != null) {
- try {
- CompilationUnitProvider specialCup = doFilterCompilationUnit(logger,
- typeName, cup);
-
- if (specialCup != null) {
- // Use the cup that the subclass returned instead. Note that even
- // though this file may not exist on disk, it is special so we don't
- // want users to have to debug into it unless they specifically ask
- // to.
- //
- cup = specialCup;
- }
- } catch (UnableToCompleteException e) {
- String location = cup.getLocation();
- char[] source = cup.getSource();
- Util.maybeDumpSource(logger, location, source, typeName);
- throw e;
- }
- }
-
- if (cup == null) {
- // Did not find a cup for the type.
- // This happens commonly and is not a cause for alarm.
- //
- return null;
- }
-
- // Remember its package and cache it.
- //
- cupsByTypeName.put(typeName, cup);
- return cup;
- }
-
- public TypeOracle getTypeOracle() {
- return typeOracle;
- }
-
- /**
- * Determines whether or not a particular name is a package name.
- */
- public final boolean isPackage(String possiblePackageName) {
- if (knownPackages.contains(possiblePackageName)) {
- // The quick route -- we've already answered yes to this question.
- // OPTIMIZE: cache NOs as well
- return true;
- }
-
- if (typeOracle.findPackage(possiblePackageName) != null) {
- // Was a package know on the source path.
- //
- rememberPackage(possiblePackageName);
- return true;
- } else {
- // Not a package.
- //
- return false;
- }
- }
-
- /**
- * Subclasses can override this method if they use a special mechanism to find
- * the compilation unit for a type. For example, rewriting source code (as
- * with JSNI) or preempting the source for a given type (as with
- * <code>GWT.create</code>).
- * <p>
- * Note that subclasses should <em>not</em> call
- * <code>super.{@link #findCompilationUnit(TreeLogger, String)}</code> in
- * their implementation.
- *
- * @return <code>null</code> if you want the superclass to use its normal
- * mechanism for finding types
- */
- protected CompilationUnitProvider doFilterCompilationUnit(TreeLogger logger,
- String typeName, CompilationUnitProvider existing)
- throws UnableToCompleteException {
- return null;
- }
-
- /**
- * Subclasses can override this method if they use additional mechanisms to
- * find types magically.
- * <p>
- * Note that subclasses should <em>not</em> call
- * <code>super.{@link #findAdditionalTypesUsingMagic(TreeLogger, CompilationUnitDeclaration)}</code>
- * in their implementation.
- *
- * @return <code>null</code> to indicate that no additional types should be
- * added
- */
- protected String[] doFindAdditionalTypesUsingMagic(TreeLogger logger,
- CompilationUnitDeclaration unit) throws UnableToCompleteException {
- return null;
- }
-
- void invalidateCups(Set typeNames) {
- cupsByTypeName.keySet().removeAll(typeNames);
- }
-
- /**
- * Remember that this package was added. Used for generated packages.
- */
- private void rememberPackage(String packageName) {
- int i = packageName.lastIndexOf('.');
- if (i != -1) {
- // Ensure the parent package is also created.
- //
- rememberPackage(packageName.substring(0, i));
- }
- knownPackages.add(packageName);
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java b/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java
deleted file mode 100644
index 1b314a8..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-
-/**
- * Implements a {@link CompilationUnitProvider} as transient (in-memory) source.
- */
-public class StaticCompilationUnitProvider implements CompilationUnitProvider {
-
- private final String packageName;
-
- private final String simpleTypeName;
-
- private final char[] source;
-
- /**
- * @param source if <code>null</code>, override this class and return
- * source from {@link #getSource()}
- */
- public StaticCompilationUnitProvider(String packageName,
- String simpleTypeName, char[] source) {
- this.packageName = packageName;
- this.simpleTypeName = simpleTypeName;
- this.source = source;
- }
-
- /**
- * Stubbed to return the same value every time.
- */
- public long getLastModified() {
- return 0;
- }
-
- /**
- * Creates a stable name for this compilation unit.
- */
- public final String getLocation() {
- String prefix = (packageName.length() > 0) ? packageName + "." : "";
- return "transient source for " + prefix + simpleTypeName;
- }
-
- public String getMainTypeName() {
- return getTypeName();
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public char[] getSource() {
- return source;
- }
-
- public String getTypeName() {
- return simpleTypeName;
- }
-
- public boolean isTransient() {
- return true;
- }
-
- public String toString() {
- return getLocation();
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/URLCompilationUnitProvider.java b/dev/core/src/com/google/gwt/dev/jdt/URLCompilationUnitProvider.java
deleted file mode 100644
index 0277dc1..0000000
--- a/dev/core/src/com/google/gwt/dev/jdt/URLCompilationUnitProvider.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2006 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.jdt;
-
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.dev.util.Util;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLConnection;
-
-/**
- * Implements {@link CompilationUnitProvider} in terms of a URL.
- */
-public class URLCompilationUnitProvider implements CompilationUnitProvider {
-
- private static File trySimplify(URL url) {
- String s = url.toExternalForm();
- File f = null;
- if (s.startsWith("file:")) {
- // Strip the file: off, and use the result. If the result
- // does not start with file, we cannot simplify. Using URI
- // to do the simplification fails for paths with spaces.
- // Any number of slashes at the beginning cause no problem for Java, so
- // if c:/windows exists so will ///////c:/windows.
- f = new File(s.substring(5));
- if (!f.exists()) {
- f = null;
- }
- }
- return f;
- }
-
- private final File file;
-
- private final String location;
-
- private final String packageName;
-
- private char[] source;
-
- private long sourceCurrentTime = Long.MIN_VALUE;
-
- private final URL url;
-
- private final String mainTypeName;
-
- public URLCompilationUnitProvider(URL url, String packageName) {
- assert (url != null);
- assert (packageName != null);
- this.url = url;
-
- // Files are faster to work with, so use file if available.
- this.file = trySimplify(url);
- String simpleTypeName;
- if (file == null) {
- this.location = url.toExternalForm();
- simpleTypeName = new File(url.getPath()).getName();
- } else {
- this.location = this.file.getAbsolutePath();
- simpleTypeName = this.file.getName();
- }
-
- int i = simpleTypeName.lastIndexOf(".java");
- if (i != -1) {
- simpleTypeName = simpleTypeName.substring(0, i);
- }
- mainTypeName = simpleTypeName;
-
- this.packageName = packageName;
- }
-
- public long getLastModified() throws UnableToCompleteException {
- try {
- if (file != null) {
- return file.lastModified();
- } else {
- String converted = Util.findFileName(location);
- if (converted != location) {
- return new File(converted).lastModified();
- }
- URLConnection conn = url.openConnection();
- return conn.getLastModified();
- }
- } catch (IOException e) {
- throw new UnableToCompleteException();
- }
- }
-
- public String getLocation() {
- return location;
- }
-
- public String getMainTypeName() {
- return mainTypeName;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public char[] getSource() throws UnableToCompleteException {
- long lastModified = getLastModified();
- if (sourceCurrentTime >= lastModified && source != null) {
- return source;
- } else {
- sourceCurrentTime = lastModified;
- }
- if (file == null) {
- // Pre-read source.
- source = Util.readURLAsChars(url);
- } else {
- source = Util.readFileAsChars(file);
- }
- if (source == null) {
- throw new UnableToCompleteException();
- }
- return source;
- }
-
- public boolean isTransient() {
- return false;
- }
-
- @Override
- public String toString() {
- return location;
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
index d7efced..689ed08 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
@@ -17,6 +17,9 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.JdtCompiler.CompilationUnitAdapter;
import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor.DeferredBindingSite;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.JsniRef;
@@ -36,13 +39,13 @@
* Provides a reusable front-end based on the JDT compiler that incorporates
* GWT-specific concepts such as JSNI and deferred binding.
*/
-public class WebModeCompilerFrontEnd extends AstCompiler {
+public class WebModeCompilerFrontEnd extends AbstractCompiler {
private final RebindPermutationOracle rebindPermOracle;
- public WebModeCompilerFrontEnd(SourceOracle sourceOracle,
+ public WebModeCompilerFrontEnd(CompilationState compilationState,
RebindPermutationOracle rebindPermOracle) {
- super(sourceOracle);
+ super(compilationState, false);
this.rebindPermOracle = rebindPermOracle;
}
@@ -51,17 +54,29 @@
throws UnableToCompleteException {
// Build the initial set of compilation units.
- //
- ICompilationUnit[] units = new ICompilationUnit[seedTypeNames.length];
+ Map<String, CompilationUnit> unitMap = compilationState.getCompilationUnitMap();
+ ICompilationUnit[] icus = new ICompilationUnit[seedTypeNames.length];
for (int i = 0; i < seedTypeNames.length; i++) {
String seedTypeName = seedTypeNames[i];
- units[i] = getCompilationUnitForType(logger, seedTypeName);
+ CompilationUnit unit = unitMap.get(seedTypeName);
+ while (unit == null) {
+ int pos = seedTypeName.lastIndexOf('.');
+ if (pos < 0) {
+ logger.log(TreeLogger.ERROR,
+ "Unable to find compilation unit for type '" + seedTypeNames[i]
+ + "'");
+ throw new UnableToCompleteException();
+ }
+ seedTypeName = seedTypeName.substring(0, pos);
+ unit = unitMap.get(seedTypeName);
+ }
+ icus[i] = new CompilationUnitAdapter(unit);
}
// Compile, which will pull in everything else via
// doFindAdditionalTypesUsingMagic()
//
- CompilationUnitDeclaration[] cuds = compile(logger, units);
+ CompilationUnitDeclaration[] cuds = compile(logger, icus);
return cuds;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 99546d5..00590f6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -17,8 +17,6 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.dev.jdt.ICompilationUnitAdapter;
import com.google.gwt.dev.jdt.RebindOracle;
import com.google.gwt.dev.jdt.RebindPermutationOracle;
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
@@ -254,7 +252,6 @@
private final String[] declEntryPoints;
private final CompilationUnitDeclaration[] goldenCuds;
- private long lastModified;
private final JJSOptions options;
private final Set<IProblem> problemSet = new HashSet<IProblem>();
@@ -302,25 +299,6 @@
// found here will have already been logged by AbstractCompiler.
//
checkForErrors(logger, false);
-
- // Find the newest of all these.
- //
- lastModified = 0;
- CompilationUnitProvider newestCup = null;
- for (CompilationUnitDeclaration cud : goldenCuds) {
- ICompilationUnitAdapter icua = (ICompilationUnitAdapter) cud.compilationResult.compilationUnit;
- CompilationUnitProvider cup = icua.getCompilationUnitProvider();
- long cupLastModified = cup.getLastModified();
- if (cupLastModified > lastModified) {
- newestCup = cup;
- lastModified = cupLastModified;
- }
- }
- if (newestCup != null) {
- String loc = newestCup.getLocation();
- String msg = "Newest compilation unit is '" + loc + "'";
- logger.log(TreeLogger.DEBUG, msg, null);
- }
}
/**
@@ -535,10 +513,6 @@
}
}
- public long getLastModifiedTimeOfNewestCompilationUnit() {
- return lastModified;
- }
-
private void checkForErrors(final TreeLogger logger, boolean itemizeErrors)
throws UnableToCompleteException {
boolean compilationFailed = false;
diff --git a/dev/core/src/com/google/gwt/dev/resource/Resource.java b/dev/core/src/com/google/gwt/dev/resource/Resource.java
new file mode 100644
index 0000000..b5310df
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/Resource.java
@@ -0,0 +1,75 @@
+/*
+ * 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.resource;
+
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * Provides information about a file-like resource.
+ */
+public abstract class Resource {
+
+ /**
+ * Overridden to finalize; always returns object identity.
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns the user-relevant location of the resource. No programmatic
+ * assumptions should be made about the return value.
+ */
+ public abstract String getLocation();
+
+ /**
+ * Returns the full abstract path of the resource.
+ */
+ public abstract String getPath();
+
+ /**
+ * Returns a URL for this resource; this URL will only be valid for resources
+ * based off the file system.
+ *
+ * TODO: get rid of this method?
+ */
+ public abstract URL getURL();
+
+ /**
+ * Overridden to finalize; always returns identity hash code.
+ */
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Returns the contents of the resource. May return <code>null</code> if
+ * this {@link Resource} has been invalidated by its containing
+ * {@link ResourceOracle}. The caller is responsible for closing the stream.
+ */
+ public abstract InputStream openContents();
+
+ /**
+ * Overridden to finalize; always returns {@link #getLocation()}.
+ */
+ @Override
+ public final String toString() {
+ return getLocation();
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/ResourceOracle.java b/dev/core/src/com/google/gwt/dev/resource/ResourceOracle.java
new file mode 100644
index 0000000..de67ad5
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/ResourceOracle.java
@@ -0,0 +1,73 @@
+/*
+ * 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.resource;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An abstraction for finding and retrieving {@link Resource}s by abstract path
+ * name. Intuitively, it works like a jar in that each URL is uniquely located
+ * somewhere in an abstract namespace. The abstract names must be constructed
+ * from a series of zero or more valid Java identifiers followed by the '/'
+ * character and finally ending in a valid filename, for example,
+ * <code>com/google/gwt/blah.txt</code>.
+ *
+ * <p>
+ * The identity of the returned sets and maps will change exactly when the
+ * underlying module is refreshed.
+ * </p>
+ *
+ * <p>
+ * Even when the identity of a returned set changes, the identity of any
+ * contained {@link Resource} values is guaranteed to differ from a previous
+ * result exactly when that particular resource becomes invalid.
+ * </p>
+ *
+ * <p>
+ * A resource could become invalid for various reasons, including:
+ * <ul>
+ * <li>the underlying file was deleted or modified</li>
+ * <li>another file with the same logical name superceded it on the classpath</li>
+ * <li>the underlying module changed to exclude this file or supercede it with
+ * another file</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * After a refresh, a client can reliably detect changes by checking which of
+ * its cached resource is still contained in the new result of
+ * {@link #getResources()}.
+ * </p>
+ */
+public interface ResourceOracle {
+
+ /**
+ * Returns an unmodifiable set of unique abstract path names with constant
+ * lookup time.
+ */
+ Set<String> getPathNames();
+
+ /**
+ * Returns an unmodifiable map of abstract path name to resource.
+ */
+ Map<String, Resource> getResourceMap();
+
+ /**
+ * Returns an unmodifiable set of unique resources with constant lookup time.
+ */
+ Set<Resource> getResources();
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/AbstractResource.java b/dev/core/src/com/google/gwt/dev/resource/impl/AbstractResource.java
new file mode 100644
index 0000000..99c9fd9
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/AbstractResource.java
@@ -0,0 +1,33 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.dev.resource.Resource;
+
+/**
+ * TODO(bruce): write me.
+ */
+public abstract class AbstractResource extends Resource {
+
+ /**
+ * Accesses the path root under which this resource was found. Only available
+ * within this package.
+ */
+ public abstract ClassPathEntry getClassPathEntry();
+
+ public abstract boolean isStale();
+}
+
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
new file mode 100644
index 0000000..aaa46f9
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
@@ -0,0 +1,49 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+
+import java.util.Set;
+
+/**
+ * A location that acts as a starting point for finding resources
+ * {@link ResourceOracleImpl}.
+ */
+public abstract class ClassPathEntry {
+
+ /**
+ * Finds every resource at abstract path P within this classpath such that P
+ * begins with a prefix X from the path prefix set and P is allowed by the
+ * filter associated with X.
+ *
+ * @return a set of zero or more resources; note no guarantees are made
+ * regarding the identities of the returned resource objects, and the
+ * same object may be returned across multiple calls
+ */
+ public abstract Set<AbstractResource> findApplicableResources(
+ TreeLogger logger, PathPrefixSet pathPrefixSet);
+
+ /**
+ * Gets a URL string that describes this class path entry.
+ */
+ public abstract String getLocation();
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": " + getLocation();
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
new file mode 100644
index 0000000..7d29ca6
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
@@ -0,0 +1,102 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.util.msg.Message1String;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * TODO(bruce): write me.
+ */
+public class DirectoryClassPathEntry extends ClassPathEntry {
+
+ private static class Messages {
+ static final Message1String NOT_DESCENDING_INTO_DIR = new Message1String(
+ TreeLogger.SPAM, "Prefix set does not include dir: $0");
+
+ static final Message1String DESCENDING_INTO_DIR = new Message1String(
+ TreeLogger.SPAM, "Descending into dir: $0");
+
+ static final Message1String EXCLUDING_FILE = new Message1String(
+ TreeLogger.DEBUG, "Filter excludes file: $0");
+
+ static final Message1String INCLUDING_FILE = new Message1String(
+ TreeLogger.DEBUG, "Including file: $0");
+ }
+
+ private final File dir;
+
+ public DirectoryClassPathEntry(File dir) {
+ this.dir = dir;
+ }
+
+ @Override
+ public Set<AbstractResource> findApplicableResources(TreeLogger logger,
+ PathPrefixSet pathPrefixSet) {
+ Set<AbstractResource> results = new HashSet<AbstractResource>();
+ descendToFindResources(logger, pathPrefixSet, results, dir, "");
+ return results;
+ }
+
+ @Override
+ public String getLocation() {
+ return dir.getAbsoluteFile().toURI().toString();
+ }
+
+ /**
+ * @param logger logs progress
+ * @param resources the accumulating set of resources found
+ * @param dir the file or directory to consider
+ * @param dirPath the abstract path name associated with 'parent', which
+ * explicitly does not include the classpath entry in its path
+ */
+ private void descendToFindResources(TreeLogger logger,
+ PathPrefixSet pathPrefixSet, Set<AbstractResource> resources, File dir,
+ String dirPath) {
+ assert (dir.isDirectory());
+
+ // Assert: this directory is included in the path prefix set.
+
+ File[] children = dir.listFiles();
+ for (File child : children) {
+ String childPath = dirPath + child.getName();
+ if (child.isDirectory()) {
+ String childDirPath = childPath + "/";
+ if (pathPrefixSet.includesDirectory(childDirPath)) {
+ Messages.DESCENDING_INTO_DIR.log(logger, child.getAbsolutePath(),
+ null);
+ descendToFindResources(logger, pathPrefixSet, resources, child,
+ childDirPath);
+ } else {
+ Messages.NOT_DESCENDING_INTO_DIR.log(logger, child.getAbsolutePath(),
+ null);
+ }
+ } else {
+ if (pathPrefixSet.includesResource(childPath)) {
+ Messages.INCLUDING_FILE.log(logger, childPath, null);
+ FileResource r = new FileResource(this, childPath, child);
+ resources.add(r);
+ } else {
+ Messages.EXCLUDING_FILE.log(logger, childPath, null);
+ }
+ }
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java b/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java
new file mode 100644
index 0000000..74ba79f
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java
@@ -0,0 +1,96 @@
+/*
+ * 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.resource.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Represents a resource contained in directory on a file system.
+ */
+public class FileResource extends AbstractResource {
+
+ private final String abstractPathName;
+ private final DirectoryClassPathEntry classPathEntry;
+ private final File file;
+ private final long modificationSeconds;
+
+ public FileResource(DirectoryClassPathEntry classPathEntry,
+ String abstractPathName, File file) {
+ assert (file.isFile());
+ this.classPathEntry = classPathEntry;
+ this.abstractPathName = abstractPathName;
+ this.file = file;
+ this.modificationSeconds = lastModifiedSeconds(file);
+ }
+
+ @Override
+ public DirectoryClassPathEntry getClassPathEntry() {
+ return classPathEntry;
+ }
+
+ @Override
+ public String getLocation() {
+ return file.getAbsoluteFile().toURI().toString();
+ }
+
+ @Override
+ public String getPath() {
+ return abstractPathName;
+ }
+
+ @Override
+ public URL getURL() {
+ try {
+ return new URL(getLocation());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean isStale() {
+ if (!file.exists()) {
+ // File was deleted. Always stale.
+ return true;
+ }
+
+ long currentModificationSeconds = lastModifiedSeconds(file);
+ /*
+ * We use != instead of > because the point is to reflect what's actually on
+ * the file system, not to worry about freshness per se.
+ */
+ return (currentModificationSeconds != modificationSeconds);
+ }
+
+ @Override
+ public InputStream openContents() {
+ try {
+ return new FileInputStream(file);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ private long lastModifiedSeconds(File file) {
+ return file.lastModified() / 1000;
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/JarFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/JarFileClassPathEntry.java
new file mode 100644
index 0000000..7e7de4b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/JarFileClassPathEntry.java
@@ -0,0 +1,129 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.util.msg.Message1String;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * A classpath entry that is a jar file.
+ */
+public class JarFileClassPathEntry extends ClassPathEntry {
+
+ /**
+ * Logger messages related to this class.
+ */
+ private static class Messages {
+ static final Message1String BUILDING_INDEX = new Message1String(
+ TreeLogger.TRACE, "Indexing jar file: $0");
+
+ static final Message1String EXCLUDING_RESOURCE = new Message1String(
+ TreeLogger.DEBUG, "Excluding $0");
+
+ static final Message1String FINDING_INCLUDED_RESOURCES = new Message1String(
+ TreeLogger.DEBUG, "Searching for included resources in $0");
+
+ static final Message1String INCLUDING_RESOURCE = new Message1String(
+ TreeLogger.DEBUG, "Including $0");
+
+ static final Message1String READ_JAR_ENTRY = new Message1String(
+ TreeLogger.DEBUG, "$0");
+ }
+
+ private Set<JarFileResource> allJarFileResources;
+ private Set<AbstractResource> cachedAnswers;
+ private final JarFile jarFile;
+ private PathPrefixSet lastPrefixSet;
+
+ public JarFileClassPathEntry(JarFile jarFile) {
+ this.jarFile = jarFile;
+ }
+
+ /**
+ * Indexes the jar file on-demand, and only once over the life of the process.
+ */
+ @Override
+ public Set<AbstractResource> findApplicableResources(TreeLogger logger,
+ PathPrefixSet pathPrefixSet) {
+ // Never re-index.
+ if (allJarFileResources == null) {
+ allJarFileResources = buildIndex(logger);
+ }
+
+ if (cachedAnswers == null || lastPrefixSet != pathPrefixSet
+ || lastPrefixSet.getModCount() != pathPrefixSet.getModCount()) {
+ cachedAnswers = computeApplicableResources(logger, pathPrefixSet);
+ }
+
+ return cachedAnswers;
+ }
+
+ public JarFile getJarFile() {
+ return jarFile;
+ }
+
+ @Override
+ public String getLocation() {
+ return new File(jarFile.getName()).toURI().toString();
+ }
+
+ private Set<JarFileResource> buildIndex(TreeLogger logger) {
+ logger = Messages.BUILDING_INDEX.branch(logger, jarFile.getName(), null);
+
+ HashSet<JarFileResource> results = new HashSet<JarFileResource>();
+ Enumeration<JarEntry> e = jarFile.entries();
+ while (e.hasMoreElements()) {
+ JarEntry jarEntry = e.nextElement();
+ if (jarEntry.isDirectory()) {
+ // Skip directories.
+ continue;
+ }
+ if (jarEntry.getName().startsWith("META-INF/")) {
+ // Skip META-INF since classloaders normally make this invisible.
+ continue;
+ }
+ JarFileResource jarResource = new JarFileResource(this, jarEntry);
+ results.add(jarResource);
+ Messages.READ_JAR_ENTRY.log(logger, jarEntry.getName(), null);
+ }
+ return results;
+ }
+
+ private Set<AbstractResource> computeApplicableResources(TreeLogger logger,
+ PathPrefixSet pathPrefixSet) {
+ logger = Messages.FINDING_INCLUDED_RESOURCES.branch(logger,
+ jarFile.getName(), null);
+
+ Set<AbstractResource> results = new HashSet<AbstractResource>();
+ for (JarFileResource r : allJarFileResources) {
+ String path = r.getPath();
+ if (pathPrefixSet.includesResource(path)) {
+ Messages.INCLUDING_RESOURCE.log(logger, path, null);
+ results.add(r);
+ } else {
+ Messages.EXCLUDING_RESOURCE.log(logger, path, null);
+ }
+ }
+ return results;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/JarFileResource.java b/dev/core/src/com/google/gwt/dev/resource/impl/JarFileResource.java
new file mode 100644
index 0000000..650d053
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/JarFileResource.java
@@ -0,0 +1,83 @@
+/*
+ * 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.resource.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.jar.JarEntry;
+
+/**
+ * Represents a resource contained in a jar file.
+ */
+public class JarFileResource extends AbstractResource {
+
+ private final JarFileClassPathEntry classPathEntry;
+ private final JarEntry jarEntry;
+
+ public JarFileResource(JarFileClassPathEntry classPathEntry, JarEntry jarEntry) {
+ this.classPathEntry = classPathEntry;
+ this.jarEntry = jarEntry;
+ }
+
+ @Override
+ public JarFileClassPathEntry getClassPathEntry() {
+ return classPathEntry;
+ }
+
+ public JarEntry getJarEntry() {
+ return jarEntry;
+ }
+
+ @Override
+ public String getLocation() {
+ return "jar:" + classPathEntry.getLocation() + "!/" + getPath();
+ }
+
+ @Override
+ public String getPath() {
+ return jarEntry.getName();
+ }
+
+ @Override
+ public URL getURL() {
+ try {
+ return new URL(getLocation());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Since we don't dynamically reload jars during a run, jar-based resources
+ * cannot become stale.
+ */
+ @Override
+ public boolean isStale() {
+ return false;
+ }
+
+ @Override
+ public InputStream openContents() {
+ try {
+ return classPathEntry.getJarFile().getInputStream(jarEntry);
+ } catch (IOException e) {
+ // The spec for this method says it can return null.
+ return null;
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
new file mode 100644
index 0000000..25537bb
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
@@ -0,0 +1,142 @@
+/*
+ * 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.resource.impl;
+
+/**
+ * Represents the abstract path prefix that goes between the
+ * {@link ClassPathEntry} and the rest of resource's abstract path. This concept
+ * allows us to specify subsets of path hierarchies orthogonally from path
+ * roots. For example, a path root might be <code>/home/gwt/src/</code> and an
+ * abstract path prefix might be <code>module/client/</code>. Importantly,
+ * you can apply the same abstract path prefix to multiple path roots and find
+ * more than one set of resources residing in disjoint locations yet occupying
+ * the same logical hierarchy. Sorry this explanation is so abstract; it's how
+ * we model things like the GWT module's client source path, public path, and
+ * super source path.
+ */
+public final class PathPrefix {
+
+ public static final PathPrefix ALL = new PathPrefix("", null);
+
+ private final ResourceFilter filter;
+ private final String prefix;
+ private final boolean shouldReroot;
+
+ /**
+ * Construct a non-rerooting prefix.
+ *
+ * @param prefix a string prefix that (1) is the empty string or (2) begins
+ * with something other than a slash and ends with a slash
+ * @param filter the resource filter to use, or <code>null</code> for no
+ * filter; note that the filter must always return the same answer
+ * for the same candidate path (doing otherwise will produce
+ * inconsistent behavior in identifying available resources)
+ */
+ public PathPrefix(String prefix, ResourceFilter filter) {
+ this(prefix, filter, false);
+ }
+
+ /**
+ * Construct a prefix.
+ *
+ * @param prefix a string prefix that (1) is the empty string or (2) begins
+ * with something other than a slash and ends with a slash
+ * @param filter the resource filter to use, or <code>null</code> for no
+ * filter; note that the filter must always return the same answer
+ * for the same candidate path (doing otherwise will produce
+ * inconsistent behavior in identifying available resources)
+ * @param shouldReroot if <code>true</code>, any matching {@link Resource}
+ * for this prefix will be rerooted to not include the initial prefix
+ * path; if <code>false</code>, the prefix will be included in a
+ * matching resource's path.
+ *
+ */
+ public PathPrefix(String prefix, ResourceFilter filter, boolean shouldReroot) {
+ assertValidPrefix(prefix);
+ this.prefix = prefix;
+ this.filter = filter;
+ this.shouldReroot = shouldReroot;
+ }
+
+ /**
+ * Determines whether or not a given path is allowed by this path prefix by
+ * checking both the prefix string and the filter.
+ *
+ * @param path
+ * @return
+ */
+ public boolean allows(String path) {
+ if (!path.startsWith(prefix)) {
+ return false;
+ }
+ if (filter == null) {
+ return true;
+ }
+ if (shouldReroot) {
+ path = getRerootedPath(path);
+ }
+ return filter.allows(path);
+ }
+
+ /**
+ * Equality is based on prefixes representing the same string. Importantly,
+ * the filter does not affect equality.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PathPrefix) {
+ if (prefix.equals(((PathPrefix) obj).prefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The prefix.
+ *
+ * @return the result is guaranteed to be non-<code>null</code>, and
+ * either be the empty string or it will not begin with a slash and
+ * will end with a slash; these guarantees are very useful when
+ * concatenating paths that incorporate prefixes
+ */
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public String getRerootedPath(String path) {
+ assert (path.startsWith(prefix));
+ if (shouldReroot) {
+ return path.substring(prefix.length());
+ } else {
+ return path;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return prefix.hashCode();
+ }
+
+ public boolean shouldReroot() {
+ return shouldReroot;
+ }
+
+ private void assertValidPrefix(String prefix) {
+ assert (prefix != null);
+ assert ("".equals(prefix) || (!prefix.startsWith("/") && prefix.endsWith("/"))) : "malformed prefix";
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
new file mode 100644
index 0000000..08a7832
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
@@ -0,0 +1,270 @@
+/*
+ * 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.resource.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Combines the information conveyed about a set of path prefixes to quickly
+ * answer questions regarding an entire set of path prefixes.
+ */
+public class PathPrefixSet {
+
+ private static class TrieNode {
+ // TODO(bruce): test to see if Map would be faster; I'm on the fence
+ private final List<TrieNode> children = new ArrayList<TrieNode>();
+ private final String part;
+ private PathPrefix prefix;
+
+ public TrieNode(String part) {
+ this.part = part;
+ }
+
+ public TrieNode addChild(String part) {
+ assert (findChild(part) == null);
+ TrieNode newChild = new TrieNode(part);
+ children.add(newChild);
+ return newChild;
+ }
+
+ public TrieNode findChild(String part) {
+ for (TrieNode child : children) {
+ if (child.part.equals(part)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ public PathPrefix getPathPrefix() {
+ return prefix;
+ }
+
+ public boolean hasChildren() {
+ return !children.isEmpty();
+ }
+
+ public void setPathPrefix(PathPrefix prefix) {
+ this.prefix = prefix;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb, "");
+ return sb.toString();
+ }
+
+ private void toString(StringBuilder sb, String indent) {
+ if (sb.length() > 0) {
+ sb.append('\n');
+ }
+ sb.append(indent);
+ sb.append(' ');
+ sb.append(part);
+ for (TrieNode child : children) {
+ child.toString(sb, indent + " ");
+ }
+ }
+ }
+
+ private int modCount;
+ private final Map<String, PathPrefix> prefixes = new HashMap<String, PathPrefix>();
+ private final TrieNode rootTrieNode = new TrieNode("/");
+
+ /**
+ * @param prefix the prefix to add
+ * @return <code>true</code> if the prefix was not already in the set;
+ * otherwise, it replaced an identical one having the same prefix,
+ * which has the effect of changing which filter is used (last one
+ * wins)
+ */
+ public boolean add(PathPrefix prefix) {
+ ++modCount;
+ String pathPrefix = prefix.getPrefix();
+ prefixes.put(pathPrefix, prefix);
+
+ /*
+ * An empty prefix means we have no prefix requirement, but we do attached
+ * the prefix to the root so that we can apply the filter.
+ */
+ if ("".equals(pathPrefix)) {
+ rootTrieNode.setPathPrefix(prefix);
+ return false;
+ }
+
+ // TODO(bruce): consider not using split for speed
+ String[] parts = pathPrefix.split("/");
+ TrieNode parentNode = rootTrieNode;
+ boolean didAdd = false;
+ for (String part : parts) {
+ TrieNode childNode = parentNode.findChild(part);
+ if (childNode != null) {
+ // Follow existing branch.
+ parentNode = childNode;
+ } else {
+ // Add a new branch.
+ parentNode = parentNode.addChild(part);
+ didAdd = true;
+ }
+ }
+ assert (parentNode != null);
+ // This may clobber an existing one, but that's okay. Last one wins.
+ parentNode.setPathPrefix(prefix);
+ return didAdd;
+ }
+
+ public int getModCount() {
+ return modCount;
+ }
+
+ /**
+ * Determines whether or not a directory might have resources that could be
+ * included. The primary purpose of this method is to allow
+ * {@link ClassPathEntry} subclasses to avoid descending into directory
+ * hierarchies that could not possibly contain resources that would be
+ * included by {@link #includesResource(String).
+ *
+ * @param dirPath must be a valid abstract directory name or the empty string
+ * @return
+ */
+ public boolean includesDirectory(String dirPath) {
+ assertValidAbstractDirectoryPathName(dirPath);
+
+ /*
+ * There are five cases:
+ *
+ * (0) dirPath is the empty string, which is (a) trivially included unless
+ * (b) no prefix paths have been specified at all.
+ *
+ * (1) The empty string was specified as a prefix, which causes everything
+ * to be included.
+ *
+ * (2) As we walk the parts of dirPath, we see a path prefix attached to one
+ * of the trie nodes we encounter. This means that there was a specified
+ * prefix that this dirPath falls underneath, so it is included.
+ *
+ * (3) dirPath is longer than the trie, but we never encounter a path prefix
+ * as we walk the trie. This indicates that this directory doesn't fall into
+ * any of the specified prefixes.
+ *
+ * (4) dirPath is not longer than the trie and stays on the trie the whole
+ * time, which means it is included (since at least some longer prefix
+ * includes it).
+ */
+
+ // if ("".equals(dirPath)) {
+ // if (rootTrieNode.hasChildren() || rootTrieNode.getPathPrefix() != null) {
+ // // Case (0)(a): trivially true.
+ // return true;
+ // } else {
+ // // Case (0)(b): no directories are included.
+ // return false;
+ // }
+ // }
+ if (rootTrieNode.getPathPrefix() != null) {
+ // Case (1).
+ return true;
+ }
+
+ TrieNode parentNode = rootTrieNode;
+
+ String[] parts = dirPath.split("/");
+ for (String part : parts) {
+ assert (!"".equals(part));
+ TrieNode childNode = parentNode.findChild(part);
+ if (childNode != null) {
+ PathPrefix pathPrefix = childNode.getPathPrefix();
+ if (pathPrefix != null) {
+ // Case (2).
+ return true;
+ }
+
+ // Haven't found a path prefix yet, so keep walking.
+ parentNode = childNode;
+ } else {
+ // Case (3).
+ return false;
+ }
+ }
+
+ // Case (4).
+ return true;
+ }
+
+ /**
+ * Determines whether or not a given resource should be allowed by this path
+ * prefix set and the corresponding filters.
+ *
+ * @param resourceAbstractPathName
+ * @return <code>true</code> if the resource matches some specified prefix
+ * and any associated filters don't exclude it
+ */
+ public boolean includesResource(String resourceAbstractPathName) {
+ assertValidAbstractResourcePathName(resourceAbstractPathName);
+
+ TrieNode parentNode = rootTrieNode;
+ PathPrefix matchingPrefix = rootTrieNode.getPathPrefix();
+
+ // TODO(bruce): consider not using split for speed
+ String[] parts = resourceAbstractPathName.split("/");
+
+ // Walk all but the last path part, which is assumed to be a file name.
+ for (int i = 0, n = parts.length - 1; i < n; ++i) {
+ String part = parts[i];
+ assert (!"".equals(part));
+ TrieNode childNode = parentNode.findChild(part);
+ if (childNode != null) {
+ // Follow valid branch.
+ matchingPrefix = childNode.getPathPrefix();
+ parentNode = childNode;
+ } else {
+ // No valid branch to follow.
+ break;
+ }
+ }
+
+ if (matchingPrefix == null) {
+ // Didn't match any specified prefix.
+ return false;
+ }
+
+ // It did match a prefix, but we still need to test.
+ return matchingPrefix.allows(resourceAbstractPathName);
+ }
+
+ public Collection<PathPrefix> values() {
+ return Collections.unmodifiableCollection(prefixes.values());
+ }
+
+ private void assertValidAbstractDirectoryPathName(String name) {
+ assert (name != null);
+ // assert ("".equals(name) || (!name.startsWith("/") &&
+ // name.endsWith("/")));
+ assert (!name.startsWith("/") && name.endsWith("/"));
+ }
+
+ private void assertValidAbstractResourcePathName(String name) {
+ assert (name != null);
+ assert (!"".equals(name));
+ assert (!name.startsWith("/") && !name.endsWith("/"));
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceFilter.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceFilter.java
new file mode 100644
index 0000000..51cbfdc
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceFilter.java
@@ -0,0 +1,28 @@
+/*
+ * 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.resource.impl;
+
+/**
+ * Used to decide whether or not a resource name should be included.
+ */
+public interface ResourceFilter {
+
+ /**
+ * Determines if the specified path is included by the filter.
+ */
+ boolean allows(String path);
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
new file mode 100644
index 0000000..0d429ff
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
@@ -0,0 +1,366 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+import com.google.gwt.dev.util.msg.Message0;
+import com.google.gwt.dev.util.msg.Message1String;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarFile;
+
+/**
+ * The normal implementation of {@link ResourceOracle}.
+ */
+public class ResourceOracleImpl implements ResourceOracle {
+
+ private static class Messages {
+ static final Message1String EXAMINING_PATH_ROOT = new Message1String(
+ TreeLogger.DEBUG, "Searching for resources within $0");
+
+ static final Message1String IGNORING_SHADOWED_RESOURCE = new Message1String(
+ TreeLogger.DEBUG,
+ "Resource '$0' is being shadowed by another resource higher in the classpath having the same name; this one will not be used");
+
+ static final Message1String NEW_RESOURCE_FOUND = new Message1String(
+ TreeLogger.TRACE, "Found new resource: $0");
+
+ static final Message0 NO_RESOURCES_CHANGED = new Message0(TreeLogger.DEBUG,
+ "No resources changed");
+
+ static final Message0 REFRESHING_RESOURCES = new Message0(TreeLogger.TRACE,
+ "Refreshing resources");
+
+ static final Message1String RESOURCE_BECAME_INVALID_BECAUSE_IT_IS_STALE = new Message1String(
+ TreeLogger.SPAM,
+ "Resource '$0' has been modified since it was last loaded and needs to be reloaded");
+
+ static final Message1String RESOURCE_BECAME_INVALID_BECAUSE_IT_MOVED = new Message1String(
+ TreeLogger.DEBUG,
+ "Resource '$0' was found on a different classpath entry and needs to be reloaded");
+ }
+
+ /**
+ * Used by rebasing {@link ResourceOracle ResourceOracles} to map from a full
+ * classpath-based abstract path to an abstract path within a logical package.
+ *
+ * @see ResourceOracleImpl#shouldRebasePaths()
+ */
+ private static class ResourceWrapper extends AbstractResource {
+ private final String path;
+ private final AbstractResource resource;
+
+ public ResourceWrapper(String path, AbstractResource resource) {
+ this.path = path;
+ this.resource = resource;
+ }
+
+ @Override
+ public ClassPathEntry getClassPathEntry() {
+ return resource.getClassPathEntry();
+ }
+
+ @Override
+ public String getLocation() {
+ return resource.getLocation();
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public URL getURL() {
+ return resource.getURL();
+ }
+
+ @Override
+ public boolean isStale() {
+ return resource.isStale();
+ }
+
+ @Override
+ public InputStream openContents() {
+ return resource.openContents();
+ }
+ }
+
+ public static ClassPathEntry createEntryForUrl(TreeLogger logger, URL url)
+ throws URISyntaxException, IOException {
+ String urlString = url.toString();
+ if (url.getProtocol().equals("file")) {
+ URI uri = new URI(urlString);
+ File f = new File(uri);
+ if (f.isDirectory()) {
+ return new DirectoryClassPathEntry(f);
+ } else if (f.isFile() && f.getName().endsWith(".jar")) {
+ return new JarFileClassPathEntry(new JarFile(f));
+ } else {
+ logger.log(TreeLogger.WARN, "Unexpected error reading classpath; " + f
+ + " is neither a directory nor a jar");
+ return null;
+ }
+ } else {
+ logger.log(TreeLogger.WARN, "Unknown URL type for " + urlString, null);
+ return null;
+ }
+ }
+
+ private static void addAllClassPathEntries(TreeLogger logger,
+ ClassLoader classLoader, List<ClassPathEntry> classPath) {
+ for (; classLoader != null; classLoader = classLoader.getParent()) {
+ if (classLoader instanceof URLClassLoader) {
+ URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
+ URL[] urls = urlClassLoader.getURLs();
+ for (URL url : urls) {
+ Throwable caught;
+ try {
+ ClassPathEntry entry = createEntryForUrl(logger, url);
+ if (entry != null) {
+ classPath.add(entry);
+ }
+ continue;
+ } catch (URISyntaxException e) {
+ caught = e;
+ } catch (IOException e) {
+ caught = e;
+ }
+ logger.log(TreeLogger.WARN, "Error processing classpath URL '" + url
+ + "'", caught);
+ }
+ }
+ }
+ }
+
+ private static List<ClassPathEntry> getAllClassPathEntries(TreeLogger logger,
+ ClassLoader classLoader) {
+ ArrayList<ClassPathEntry> classPath = new ArrayList<ClassPathEntry>();
+ addAllClassPathEntries(logger, classLoader, classPath);
+ return classPath;
+ }
+
+ private final List<ClassPathEntry> classPath = new ArrayList<ClassPathEntry>();
+
+ private Set<String> exposedPathNames = Collections.emptySet();
+
+ private Map<String, Resource> exposedResourceMap = Collections.emptyMap();
+
+ private Set<Resource> exposedResources = Collections.emptySet();
+
+ private Map<String, AbstractResource> internalMap = Collections.emptyMap();
+
+ private PathPrefixSet pathPrefixSet = new PathPrefixSet();
+
+ /**
+ * Constructs a {@link ResourceOracleImpl} from a set of
+ * {@link ClassPathEntry ClassPathEntries}. The passed-in list is copied, but
+ * the underlying entries in the list are not. Those entries must be
+ * effectively immutable except for reflecting actual changes to the
+ * underlying resources.
+ */
+ public ResourceOracleImpl(List<ClassPathEntry> classPath) {
+ this.classPath.addAll(classPath);
+ }
+
+ /**
+ * Constructs a {@link ResourceOracleImpl} from the thread's default
+ * {@link ClassLoader}.
+ */
+ public ResourceOracleImpl(TreeLogger logger) {
+ this(logger, Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * Constructs a {@link ResourceOracleImpl} from a {@link ClassLoader}. The
+ * specified {@link ClassLoader} and all of its parents which are instances of
+ * {@link URLClassLoader} will have their class path entries added to this
+ * instances underlying class path.
+ */
+ public ResourceOracleImpl(TreeLogger logger, ClassLoader classLoader) {
+ this(getAllClassPathEntries(logger, classLoader));
+ }
+
+ public Set<String> getPathNames() {
+ return exposedPathNames;
+ }
+
+ public Map<String, Resource> getResourceMap() {
+ return exposedResourceMap;
+ }
+
+ public Set<Resource> getResources() {
+ return exposedResources;
+ }
+
+ /**
+ * Rescans the associated paths to recompute the available resources.
+ *
+ * @param logger status and error details are written here
+ * @throws UnableToCompleteException
+ */
+ public void refresh(TreeLogger logger) {
+ TreeLogger refreshBranch = Messages.REFRESHING_RESOURCES.branch(logger,
+ null);
+
+ /*
+ * Allocate fresh data structures in anticipation of needing to honor the
+ * "new identity for the collections if anything changes" guarantee.
+ */
+ final Map<String, AbstractResource> newInternalMap = new HashMap<String, AbstractResource>();
+
+ /*
+ * Walk across path roots (i.e. classpath entries) in priority order. This
+ * is a "reverse painter's algorithm", relying on being careful never to add
+ * a resource that has already been added to the new map under construction
+ * to create the effect that resources founder earlier on the classpath take
+ * precedence.
+ */
+ int changeCount = 0;
+ for (ClassPathEntry pathRoot : classPath) {
+ TreeLogger branchForClassPathEntry = Messages.EXAMINING_PATH_ROOT.branch(
+ refreshBranch, pathRoot.getLocation(), null);
+
+ int prevChangeCount = changeCount;
+
+ Set<AbstractResource> newResources = pathRoot.findApplicableResources(
+ branchForClassPathEntry, pathPrefixSet);
+ for (AbstractResource newResource : newResources) {
+ String resourcePath = newResource.getPath();
+
+ // Make sure we don't already have a resource by this name.
+ if (newInternalMap.containsKey(resourcePath)) {
+ Messages.IGNORING_SHADOWED_RESOURCE.log(branchForClassPathEntry,
+ resourcePath, null);
+ continue;
+ }
+
+ AbstractResource oldResource = internalMap.get(resourcePath);
+ if (shouldUseNewResource(branchForClassPathEntry, oldResource,
+ newResource)) {
+ newInternalMap.put(resourcePath, newResource);
+ ++changeCount;
+ } else if (oldResource != null) {
+ // Nothing changed, so carry the identity of the old one forward.
+ newInternalMap.put(resourcePath, oldResource);
+ }
+ }
+
+ if (changeCount == prevChangeCount) {
+ Messages.NO_RESOURCES_CHANGED.log(branchForClassPathEntry, null);
+ }
+ }
+
+ if (changeCount == 0) {
+ /*
+ * Nothing was added or modified, but we still have to be sure we didn't
+ * lose any resources.
+ */
+ if (newInternalMap.size() == internalMap.size()) {
+ /*
+ * Exit without changing the current exposed collections to maintain the
+ * identity requirements described in the spec for ResourceOracle.
+ */
+ return;
+ }
+ }
+
+ internalMap = newInternalMap;
+ Map<String, Resource> externalMap = rerootResourcePaths(newInternalMap);
+
+ // Create a constant-time set for resources.
+ Set<Resource> newResources = new HashSet<Resource>(externalMap.values());
+ assert (newResources.size() == externalMap.size());
+
+ // Update the gettable fields with the new (unmodifiable) data structures.
+ exposedResources = Collections.unmodifiableSet(newResources);
+ exposedResourceMap = Collections.unmodifiableMap(externalMap);
+ exposedPathNames = Collections.unmodifiableSet(externalMap.keySet());
+ }
+
+ public void setPathPrefixes(PathPrefixSet pathPrefixSet) {
+ this.pathPrefixSet = pathPrefixSet;
+ }
+
+ private Map<String, Resource> rerootResourcePaths(
+ Map<String, AbstractResource> newInternalMap) {
+ Map<String, Resource> externalMap;
+ // Create an external map with rebased path names.
+ externalMap = new HashMap<String, Resource>();
+ for (AbstractResource resource : newInternalMap.values()) {
+ String path = resource.getPath();
+ if (externalMap.get(path) instanceof ResourceWrapper) {
+ // A rerooted resource blocks any other resource at this path.
+ continue;
+ }
+ for (PathPrefix pathPrefix : pathPrefixSet.values()) {
+ if (pathPrefix.allows(path)) {
+ assert (path.startsWith(pathPrefix.getPrefix()));
+ if (pathPrefix.shouldReroot()) {
+ path = pathPrefix.getRerootedPath(path);
+ AbstractResource wrapper = new ResourceWrapper(path, resource);
+ externalMap.put(path, wrapper);
+ } else {
+ externalMap.put(path, resource);
+ }
+ break;
+ }
+ }
+ assert (externalMap.containsKey(path));
+ }
+ return externalMap;
+ }
+
+ private boolean shouldUseNewResource(TreeLogger logger,
+ AbstractResource oldResource, AbstractResource newResource) {
+ String resourcePath = newResource.getPath();
+ if (oldResource != null) {
+ // Test 1: Is the resource found in a different location than before?
+ if (oldResource.getClassPathEntry() == newResource.getClassPathEntry()) {
+ // Test 2: Has the resource changed since we last found it?
+ if (!oldResource.isStale()) {
+ // The resource has not changed.
+ return false;
+ } else {
+ Messages.RESOURCE_BECAME_INVALID_BECAUSE_IT_IS_STALE.log(logger,
+ resourcePath, null);
+ }
+ } else {
+ Messages.RESOURCE_BECAME_INVALID_BECAUSE_IT_MOVED.log(logger,
+ resourcePath, null);
+ }
+ } else {
+ Messages.NEW_RESOURCE_FOUND.log(logger, resourcePath, null);
+ }
+
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 2359e09..9d083a6 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -15,17 +15,19 @@
*/
package com.google.gwt.dev.shell;
+import com.google.gwt.core.client.GWTBridge;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.ByteCodeCompiler;
-import com.google.gwt.dev.jdt.CacheManager;
-import com.google.gwt.dev.shell.JsniMethods.JsniMethod;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompiledClass;
+import com.google.gwt.dev.javac.JsniMethod;
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter;
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodOracle;
+import com.google.gwt.dev.util.Jsni;
import com.google.gwt.dev.util.JsniRef;
import com.google.gwt.util.tools.Utility;
@@ -45,7 +47,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -342,12 +343,17 @@
* space (thus, they bridge across the spaces).
*/
private static final Class<?>[] BRIDGE_CLASSES = new Class<?>[] {
- ShellJavaScriptHost.class, JsniMethods.class, JsniMethod.class};
+ ShellJavaScriptHost.class, GWTBridge.class};
private static final boolean CLASS_DUMP = false;
private static final String CLASS_DUMP_PATH = "rewritten-classes";
+ /**
+ * Caches the byte code for {@link JavaScriptHost}.
+ */
+ private static byte[] javaScriptHostBytes;
+
static {
for (Class<?> c : BRIDGE_CLASSES) {
BRIDGE_CLASS_NAMES.put(c.getName(), c);
@@ -381,31 +387,65 @@
}
}
+ /**
+ * Magic: {@link JavaScriptHost} was never compiled because it's a part of the
+ * hosted mode infrastructure. However, unlike {@link #BRIDGE_CLASSES},
+ * {@code JavaScriptHost} needs a separate copy per inside the ClassLoader for
+ * each module.
+ */
+ private static void ensureJavaScriptHostBytes(TreeLogger logger)
+ throws UnableToCompleteException {
+
+ if (javaScriptHostBytes != null) {
+ return;
+ }
+
+ String className = JavaScriptHost.class.getName();
+ try {
+ String path = className.replace('.', '/') + ".class";
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ URL url = cl.getResource(path);
+ if (url != null) {
+ javaScriptHostBytes = getClassBytesFromStream(url.openStream());
+ } else {
+ logger.log(TreeLogger.ERROR,
+ "Could not find required bootstrap class '" + className
+ + "' in the classpath", null);
+ throw new UnableToCompleteException();
+ }
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR,
+ "Error reading class bytes for " + className, e);
+ throw new UnableToCompleteException();
+ }
+ }
+
+ private static byte[] getClassBytesFromStream(InputStream is)
+ throws IOException {
+ try {
+ byte classBytes[] = new byte[is.available()];
+ int read = 0;
+ while (read < classBytes.length) {
+ read += is.read(classBytes, read, classBytes.length - read);
+ }
+ return classBytes;
+ } finally {
+ Utility.close(is);
+ }
+ }
+
private final HostedModeClassRewriter classRewriter;
- private final ByteCodeCompiler compiler;
+ private CompilationState compilationState;
private final DispatchClassInfoOracle dispClassInfoOracle = new DispatchClassInfoOracle();
- private Class<?> javaScriptHostClass;
+ private Class<?> gwtClass, javaScriptHostClass;
private final TreeLogger logger;
- /**
- * Stores a list of classes needing JSNI injection. This list will be cleared
- * when the {@link #stackDepth} is <code>0</code>.
- */
- private final List<Class<?>> pendingJsniInjectionClasses = new ArrayList<Class<?>>();
-
private ShellJavaScriptHost shellJavaScriptHost;
- /**
- * Used to guard against {@link ClassCircularityError}. Attempting to read
- * class annotations for the purpose of JSNI injection while defining a class
- * can lead to circularities; we must wait until we're at the "top of stack".
- */
- private int stackDepth = 0;
-
private final TypeOracle typeOracle;
@SuppressWarnings("unchecked")
@@ -416,48 +456,19 @@
private final Map<Integer, Object> weakJsoCache = new ReferenceMap(
AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
- public CompilingClassLoader(TreeLogger logger, ByteCodeCompiler compiler,
- TypeOracle typeOracle, ShellJavaScriptHost javaScriptHost)
+ public CompilingClassLoader(TreeLogger logger,
+ CompilationState compilationState, ShellJavaScriptHost javaScriptHost)
throws UnableToCompleteException {
super(null);
this.logger = logger;
- this.compiler = compiler;
- this.typeOracle = typeOracle;
+ this.compilationState = compilationState;
this.shellJavaScriptHost = javaScriptHost;
+ this.typeOracle = compilationState.getTypeOracle();
// Assertions are always on in hosted mode.
setDefaultAssertionStatus(true);
- // SPECIAL MAGIC: Prevents the compile process from ever trying to compile
- // these guys from source, which is what we want, since they are special and
- // neither of them would compile correctly from source.
- //
- // JavaScriptHost is special because its type cannot be known to the user.
- // It is referenced only from generated code and GWT.create.
- //
- for (Class<?> clazz : CacheManager.BOOTSTRAP_CLASSES) {
- String className = clazz.getName();
- try {
- String path = clazz.getName().replace('.', '/').concat(".class");
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- URL url = cl.getResource(path);
- if (url != null) {
- byte classBytes[] = getClassBytesFromStream(url.openStream());
- String loc = url.toExternalForm();
- compiler.putClassBytes(logger, className, classBytes, loc);
- } else {
- logger.log(TreeLogger.ERROR,
- "Could not find required bootstrap class '" + className
- + "' in the classpath", null);
- throw new UnableToCompleteException();
- }
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Error reading class bytes for "
- + className, e);
- throw new UnableToCompleteException();
- }
- }
- compiler.removeStaleByteCode(logger);
+ ensureJavaScriptHostBytes(logger);
// Create a class rewriter based on all the subtypes of the JSO class.
JClassType jsoType = typeOracle.findType(JsValueGlue.JSO_CLASS);
@@ -574,82 +585,22 @@
}
// Get the bytes, compiling if necessary.
- byte[] classBytes;
- try {
- ++stackDepth;
- if (classRewriter != null && classRewriter.isJsoIntf(className)) {
- // Generate a synthetic JSO interface class.
- classBytes = classRewriter.writeJsoIntf(className);
- } else {
- // A JSO impl class needs the class bytes for the original class.
- String lookupClassName = className;
- if (classRewriter != null && classRewriter.isJsoImpl(className)) {
- lookupClassName = className.substring(0, className.length() - 1);
- }
- classBytes = compiler.getClassBytes(logger, lookupClassName);
- if (classRewriter != null) {
- byte[] newBytes = classRewriter.rewrite(className, classBytes);
- if (CLASS_DUMP) {
- if (!Arrays.equals(classBytes, newBytes)) {
- classDump(className, classBytes);
- }
- }
- classBytes = newBytes;
- }
- }
- Class<?> newClass = defineClass(className, classBytes, 0,
- classBytes.length);
-
- if (className.equals(JavaScriptHost.class.getName())) {
- javaScriptHostClass = newClass;
- updateJavaScriptHost();
- }
-
- return newClass;
- } catch (UnableToCompleteException e) {
+ byte[] classBytes = findClassBytes(className);
+ if (classBytes == null) {
throw new ClassNotFoundException(className);
- } finally {
- --stackDepth;
- }
- }
-
- /**
- * Overridden to process JSNI annotations.
- */
- @Override
- protected synchronized Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class<?> newClass = super.loadClass(name, resolve);
-
- // Only real, non-local classes can have JSNI method annotations.
- if (!newClass.isInterface() && !newClass.isLocalClass()) {
- pendingJsniInjectionClasses.add(newClass);
}
- if (stackDepth == 0 && !pendingJsniInjectionClasses.isEmpty()) {
- // Save a copy because this can re-enter.
- Class<?>[] toCheck = pendingJsniInjectionClasses.toArray(new Class<?>[pendingJsniInjectionClasses.size()]);
- pendingJsniInjectionClasses.clear();
- for (Class<?> checkClass : toCheck) {
- JsniMethods jsniMethods = checkClass.getAnnotation(JsniMethods.class);
- if (jsniMethods != null) {
- for (JsniMethod jsniMethod : jsniMethods.value()) {
- String[] bodyParts = jsniMethod.body();
- int size = 0;
- for (String bodyPart : bodyParts) {
- size += bodyPart.length();
- }
- StringBuilder body = new StringBuilder(size);
- for (String bodyPart : bodyParts) {
- body.append(bodyPart);
- }
- shellJavaScriptHost.createNative(jsniMethod.file(),
- jsniMethod.line(), jsniMethod.name(), jsniMethod.paramNames(),
- body.toString());
- }
- }
- }
+ Class<?> newClass = defineClass(className, classBytes, 0, classBytes.length);
+ if (className.equals(JavaScriptHost.class.getName())) {
+ javaScriptHostClass = newClass;
+ updateJavaScriptHost();
}
+
+ if (className.equals("com.google.gwt.core.client.GWT")) {
+ gwtClass = newClass;
+ updateGwtClass();
+ }
+
return newClass;
}
@@ -662,22 +613,59 @@
dispClassInfoOracle.clear();
}
+ private byte[] findClassBytes(String className) {
+ if (JavaScriptHost.class.getName().equals(className)) {
+ // No need to rewrite.
+ return javaScriptHostBytes;
+ }
+
+ if (classRewriter != null && classRewriter.isJsoIntf(className)) {
+ // Generate a synthetic JSO interface class.
+ return classRewriter.writeJsoIntf(className);
+ }
+
+ // A JSO impl class needs the class bytes for the original class.
+ String lookupClassName = className.replace('.', '/');
+ if (classRewriter != null && classRewriter.isJsoImpl(className)) {
+ lookupClassName = lookupClassName.substring(0,
+ lookupClassName.length() - 1);
+ }
+
+ CompiledClass compiledClass = compilationState.getClassFileMap().get(
+ lookupClassName);
+ if (compiledClass != null) {
+ injectJsniFor(compiledClass);
+
+ byte[] classBytes = compiledClass.getBytes();
+ if (classRewriter != null) {
+ byte[] newBytes = classRewriter.rewrite(className, classBytes);
+ if (CLASS_DUMP) {
+ if (!Arrays.equals(classBytes, newBytes)) {
+ classDump(className, newBytes);
+ }
+ }
+ classBytes = newBytes;
+ }
+ return classBytes;
+ }
+ return null;
+ }
+
private String getBinaryName(JClassType type) {
String name = type.getPackage().getName() + '.';
name += type.getName().replace('.', '$');
return name;
}
- private byte[] getClassBytesFromStream(InputStream is) throws IOException {
- try {
- byte classBytes[] = new byte[is.available()];
- int read = 0;
- while (read < classBytes.length) {
- read += is.read(classBytes, read, classBytes.length - read);
+ private void injectJsniFor(CompiledClass compiledClass) {
+ for (JsniMethod jsniMethod : compiledClass.getJsniMethods()) {
+ String body = Jsni.getJavaScriptForHostedMode(logger, jsniMethod);
+ if (body == null) {
+ // The error has been logged; just ignore it for now.
+ continue;
}
- return classBytes;
- } finally {
- Utility.close(is);
+ shellJavaScriptHost.createNative(jsniMethod.location(),
+ jsniMethod.line(), jsniMethod.name(), jsniMethod.paramNames(), body);
}
}
@@ -695,8 +683,47 @@
/**
* Tricky one, this. Reaches over into this modules's JavaScriptHost class and
- * sets its static 'host' field to be the specified ModuleSpace instance
- * (which will either be this ModuleSpace or null).
+ * sets its static 'host' field to our module space.
+ *
+ * @param moduleSpace the ModuleSpace instance to store using
+ * JavaScriptHost.setHost().
+ * @see JavaScriptHost
+ */
+ private void updateGwtClass() {
+ if (gwtClass == null) {
+ return;
+ }
+ Throwable caught;
+ try {
+ GWTBridgeImpl bridge;
+ if (shellJavaScriptHost == null) {
+ bridge = null;
+ } else {
+ bridge = new GWTBridgeImpl(shellJavaScriptHost);
+ }
+ final Class<?>[] paramTypes = new Class[] {GWTBridge.class};
+ Method setBridgeMethod = gwtClass.getDeclaredMethod("setBridge",
+ paramTypes);
+ setBridgeMethod.setAccessible(true);
+ setBridgeMethod.invoke(gwtClass, new Object[] {bridge});
+ return;
+ } catch (SecurityException e) {
+ caught = e;
+ } catch (NoSuchMethodException e) {
+ caught = e;
+ } catch (IllegalArgumentException e) {
+ caught = e;
+ } catch (IllegalAccessException e) {
+ caught = e;
+ } catch (InvocationTargetException e) {
+ caught = e.getTargetException();
+ }
+ throw new RuntimeException("Error initializing GWT bridge", caught);
+ }
+
+ /**
+ * Tricky one, this. Reaches over into this modules's JavaScriptHost class and
+ * sets its static 'host' field to our module space.
*
* @param moduleSpace the ModuleSpace instance to store using
* JavaScriptHost.setHost().
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTBridgeImpl.java b/dev/core/src/com/google/gwt/dev/shell/GWTBridgeImpl.java
new file mode 100644
index 0000000..973145c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/GWTBridgeImpl.java
@@ -0,0 +1,57 @@
+/*
+ * 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.shell;
+
+import com.google.gwt.core.client.GWTBridge;
+import com.google.gwt.dev.About;
+
+/**
+ * This class is the hosted-mode peer for {@link com.google.gwt.core.client.GWT}.
+ */
+public class GWTBridgeImpl extends GWTBridge {
+
+ private final ShellJavaScriptHost host;
+
+ public GWTBridgeImpl(ShellJavaScriptHost host) {
+ this.host = host;
+ }
+
+ /**
+ * Resolves a deferred binding request and create the requested object.
+ */
+ public <T> T create(Class<?> requestedClass) {
+ String className = requestedClass.getName();
+ try {
+ return host.<T> rebindAndCreate(className);
+ } catch (Throwable e) {
+ String msg = "Deferred binding failed for '" + className
+ + "' (did you forget to inherit a required module?)";
+ throw new RuntimeException(msg, e);
+ }
+ };
+
+ public String getVersion() {
+ return About.GWT_VERSION_NUM;
+ }
+
+ /**
+ * Logs in dev shell.
+ */
+ public void log(String message, Throwable e) {
+ host.log(message, e);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
index 90f3a5a..bdbcd1b 100644
--- a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
+++ b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
@@ -25,6 +25,7 @@
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.jjs.JJSOptions;
+import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.HttpHeaders;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.log.ServletContextTreeLogger;
@@ -410,12 +411,15 @@
return;
}
- URL foundResource;
+ URL foundResource = null;
try {
// Look for the requested file on the public path.
//
ModuleDef moduleDef = getModuleDef(logger, moduleName);
- foundResource = moduleDef.findPublicFile(partialPath);
+ Resource publicResource = moduleDef.findPublicFile(partialPath);
+ if (publicResource != null) {
+ foundResource = publicResource.getURL();
+ }
if (foundResource == null) {
// Look for generated files
diff --git a/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java b/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java
index adf1ced..5270bf1 100644
--- a/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java
+++ b/dev/core/src/com/google/gwt/dev/shell/HostedModeServletContextProxy.java
@@ -17,6 +17,7 @@
import com.google.gwt.dev.GWTShell;
import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.dev.resource.Resource;
import java.io.File;
import java.io.IOException;
@@ -172,15 +173,17 @@
String partialPath = path.substring(moduleContext.length());
// Try to get the resource from the application's public path
- URL url = moduleDef.findPublicFile(partialPath);
- if (url == null) {
- // Otherwise try the path but rooted in the shell's output directory
- File shellDir = new File(outDir, GWTShell.GWT_SHELL_PATH + File.separator
- + moduleDef.getName());
- File requestedFile = new File(shellDir, partialPath);
- if (requestedFile.exists()) {
- url = requestedFile.toURI().toURL();
- }
+ Resource publicResource = moduleDef.findPublicFile(partialPath);
+ if (publicResource != null) {
+ return publicResource.getURL();
+ }
+
+ // Otherwise try the path but rooted in the shell's output directory
+ File shellDir = new File(outDir, GWTShell.GWT_SHELL_PATH + File.separator
+ + moduleDef.getName());
+ File requestedFile = new File(shellDir, partialPath);
+ if (requestedFile.exists()) {
+ return requestedFile.toURI().toURL();
}
/*
@@ -188,19 +191,16 @@
* directory for the file. We'll default to using the output directory of
* the first linker defined in the <set-linker> tab.
*/
- if (url == null) {
- File requestedFile = new File(new File(outDir, moduleDef.getName()),
- partialPath);
- if (requestedFile.exists()) {
- try {
- url = requestedFile.toURI().toURL();
- } catch (MalformedURLException e) {
- // ignore since it was speculative anyway
- }
+ requestedFile = new File(new File(outDir, moduleDef.getName()), partialPath);
+ if (requestedFile.exists()) {
+ try {
+ return requestedFile.toURI().toURL();
+ } catch (MalformedURLException e) {
+ // ignore since it was speculative anyway
}
}
- return url;
+ return null;
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/shell/HostedModeSourceOracle.java b/dev/core/src/com/google/gwt/dev/shell/HostedModeSourceOracle.java
deleted file mode 100644
index 64547c5..0000000
--- a/dev/core/src/com/google/gwt/dev/shell/HostedModeSourceOracle.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2007 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.shell;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.StandardSourceOracle;
-import com.google.gwt.dev.jdt.StaticCompilationUnitProvider;
-import com.google.gwt.util.tools.Utility;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Does a little extra magic to handle hosted mode JSNI and
- * <code>GWT.create()</code>.
- */
-public class HostedModeSourceOracle extends StandardSourceOracle {
-
- private final JsniInjector injector;
- private final File jsniSaveDirectory;
-
- public HostedModeSourceOracle(TypeOracle typeOracle, File jsniSaveDirectory) {
- super(typeOracle);
- this.injector = new JsniInjector(typeOracle);
- this.jsniSaveDirectory = jsniSaveDirectory;
- }
-
- @Override
- protected CompilationUnitProvider doFilterCompilationUnit(TreeLogger logger,
- String typeName, CompilationUnitProvider existing)
- throws UnableToCompleteException {
-
- /*
- * MAGIC: The implementation of GWT can be very different between hosted
- * mode and web mode. The compiler has special knowledge of GWT for web
- * mode. The source for hosted mode is in GWT.java-hosted.
- */
- if (typeName.equals("com.google.gwt.core.client.GWT")) {
- try {
- String source = Utility.getFileFromClassPath("com/google/gwt/core/client/GWT.java-hosted");
- return new StaticCompilationUnitProvider("com.google.gwt.core.client",
- "GWT", source.toCharArray());
- } catch (IOException e) {
- logger.log(
- TreeLogger.ERROR,
- "Unable to load 'com/google/gwt/core/client/GWT.java-hosted' from class path; is your installation corrupt?",
- e);
- throw new UnableToCompleteException();
- }
- }
-
- // Otherwise, it's a regular translatable type, but we want to make sure
- // its JSNI stuff, if any, gets handled.
- //
- CompilationUnitProvider jsnified = injector.inject(logger, existing,
- jsniSaveDirectory);
- return jsnified;
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java b/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java
index b0cd9f8..17a1b5c 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java
@@ -108,27 +108,6 @@
}
/**
- * Logs in dev shell.
- */
- public static void log(String message, Throwable e) {
- sHost.log(message, e);
- }
-
- /**
- * Resolves a deferred binding request and create the requested object.
- */
- public static <T> T rebindAndCreate(Class<?> requestedClass) {
- String className = requestedClass.getName();
- try {
- return sHost.<T> rebindAndCreate(className);
- } catch (Throwable e) {
- String msg = "Deferred binding failed for '" + className
- + "' (did you forget to inherit a required module?)";
- throw new RuntimeException(msg, e);
- }
- }
-
- /**
* This method is called via reflection from the {@link CompilingClassLoader},
* providing the hosted mode application with all of the methods it needs to
* interface with the browser and the server (for deferred binding).
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java b/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java
deleted file mode 100644
index 34d2917..0000000
--- a/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.shell;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JMethod;
-import com.google.gwt.core.ext.typeinfo.JParameter;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.CompilationUnitProviderWithAlternateSource;
-import com.google.gwt.dev.js.ast.JsBlock;
-import com.google.gwt.dev.shell.JsniMethods.JsniMethod;
-import com.google.gwt.dev.util.Jsni;
-import com.google.gwt.dev.util.StringCopier;
-import com.google.gwt.dev.util.Util;
-
-import java.io.File;
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Adapts compilation units containing JSNI-accessible code by rewriting the
- * source.
- */
-public class JsniInjector {
-
- /**
- * A chunk of replacement text and where to put it.
- */
- private static class Replacement implements Comparable<Replacement> {
- public final int end;
-
- public final int start;
-
- public final char[] text;
-
- public Replacement(int start, int end, char[] text) {
- this.start = start;
- this.end = end;
- this.text = text;
- }
-
- public int compareTo(Replacement other) {
- if (start < other.start) {
- assert (end <= other.start) : "Overlapping changes not supported";
- return -1;
- } else if (start > other.start) {
- assert (start >= other.end) : "Overlapping changes not supported";
- return 1;
- } else {
- return 0;
- }
- }
- }
-
- private static final int BLOCK_SIZE = 1024;
-
- private static final String JSNIMETHOD_NAME = JsniMethod.class.getName().replace(
- '$', '.');
-
- private static final String JSNIMETHODS_NAME = JsniMethods.class.getName();
-
- private final Map<JClassType, List<JsniMethod>> jsniMethodMap = new IdentityHashMap<JClassType, List<JsniMethod>>();
- private final TypeOracle oracle;
-
- public JsniInjector(TypeOracle oracle) {
- this.oracle = oracle;
- }
-
- public CompilationUnitProvider inject(TreeLogger logger,
- CompilationUnitProvider cup, File jsniSaveDirectory)
- throws UnableToCompleteException {
-
- logger = logger.branch(TreeLogger.SPAM,
- "Checking for JavaScript native methods", null);
-
- // Analyze the source and build a list of changes.
- char[] source = cup.getSource();
- List<Replacement> changes = new ArrayList<Replacement>();
- rewriteCompilationUnit(logger, source, changes, cup, false);
-
- // Sort and apply the changes.
- int n = changes.size();
- if (n > 0) {
- Replacement[] repls = changes.toArray(new Replacement[n]);
- Arrays.sort(repls);
- StringCopier copier = new StringCopier(source);
- for (int i = 0; i < n; ++i) {
- Replacement repl = repls[i];
- copier.commit(repl.text, repl.start, repl.end);
- }
-
- char[] results = copier.finish();
-
- if (jsniSaveDirectory != null) {
- String originalPath = cup.getLocation().replace(File.separatorChar, '/');
- String suffix = cup.getPackageName().replace('.', '/');
- int pos = originalPath.indexOf(suffix);
- if (pos >= 0) {
- String filePath = originalPath.substring(pos);
- File out = new File(jsniSaveDirectory, filePath);
- Util.writeCharsAsFile(logger, out, results);
- }
- }
-
- return new CompilationUnitProviderWithAlternateSource(cup, results);
- } else {
- // No changes were made, so we return the original.
- logger.log(TreeLogger.SPAM, "No JavaScript native methods were found",
- null);
- return cup;
- }
- }
-
- private void collectJsniMethods(TreeLogger logger, char[] source,
- JClassType type) throws UnableToCompleteException {
-
- // Locate the nearest non-local type; don't try to annotate local types.
- JClassType targetType = type;
- while (targetType.isLocalType()) {
- targetType = targetType.getEnclosingType();
- }
- List<JsniMethod> jsniMethods = jsniMethodMap.get(targetType);
- String loc = type.getCompilationUnit().getLocation();
-
- for (JMethod method : type.getMethods()) {
- if (!method.isNative()) {
- continue;
- }
- Jsni.Interval interval = Jsni.findJsniSource(method);
- if (interval == null) {
- String msg = "No JavaScript body found for native method '" + method
- + "' in type '" + type + "'";
- logger.log(TreeLogger.ERROR, msg, null);
- throw new UnableToCompleteException();
- }
- // Parse it.
- String js = String.valueOf(source, interval.start, interval.end
- - interval.start);
- int startLine = Jsni.countNewlines(source, 0, interval.start) + 1;
- JsBlock body = Jsni.parseAsFunctionBody(logger, js, loc, startLine);
-
- // Add JsniMethod annotations to the target type.
- if (jsniMethods == null) {
- jsniMethods = new ArrayList<JsniMethod>();
- jsniMethodMap.put(targetType, jsniMethods);
- }
- jsniMethods.add(createJsniMethod(method, body, loc, source));
- }
- }
-
- private JsniMethod createJsniMethod(JMethod method, JsBlock jsniBody,
- final String file, char[] source) {
-
- final int line = Jsni.countNewlines(source, 0, method.getBodyStart()) + 1;
-
- final String name = Jsni.getJsniSignature(method);
-
- JParameter[] params = method.getParameters();
- final String[] paramNames = new String[params.length];
- for (int i = 0; i < params.length; ++i) {
- paramNames[i] = params[i].getName();
- }
-
- /*
- * Surround the original JS body statements with a try/catch so that we can
- * map JavaScript exceptions back into Java. Note that the method body
- * itself will print curly braces, so we don't need them around the
- * try/catch.
- */
- String jsTry = "try ";
- String jsCatch = " catch (e) {\n __static[\"@" + Jsni.JAVASCRIPTHOST_NAME
- + "::exceptionCaught(Ljava/lang/Object;)\"](e == null ? null : e);\n"
- + "}\n";
- String body = jsTry + Jsni.generateJavaScriptForHostedMode(jsniBody)
- + jsCatch;
-
- /*
- * Break up the body into 1k strings; this ensures we don't blow up any
- * class file limits.
- */
- int length = body.length();
- final String[] bodyParts = new String[(length + BLOCK_SIZE - 1)
- / BLOCK_SIZE];
- for (int i = 0; i < bodyParts.length; ++i) {
- int startIndex = i * BLOCK_SIZE;
- int endIndex = Math.min(startIndex + BLOCK_SIZE, length);
- bodyParts[i] = body.substring(startIndex, endIndex);
- }
-
- return new JsniMethod() {
-
- public Class<? extends Annotation> annotationType() {
- return JsniMethod.class;
- }
-
- public String[] body() {
- return bodyParts;
- }
-
- public String file() {
- return file;
- }
-
- public int line() {
- return line;
- }
-
- public String name() {
- return name;
- }
-
- public String[] paramNames() {
- return paramNames;
- }
-
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("@" + JSNIMETHOD_NAME + "(file=\"");
- sb.append(Jsni.escapedJavaScriptForStringLiteral(file));
- sb.append("\",line=");
- sb.append(line);
- sb.append(",name=\"@");
- sb.append(name);
- sb.append("\",paramNames={");
- for (String paramName : paramNames) {
- sb.append('\"');
- sb.append(paramName);
- sb.append('\"');
- sb.append(',');
- }
- sb.append("},body={");
- for (String bodyPart : bodyParts) {
- sb.append('"');
- sb.append(Jsni.escapedJavaScriptForStringLiteral(bodyPart));
- sb.append('"');
- sb.append(',');
- }
- sb.append("})");
- return sb.toString();
- }
- };
- }
-
- /**
- * Generate annotation metadata for all the JSNI methods in a list.
- */
- private char[] genJsniMethodsAnnotation(List<JsniMethod> jsniMethods,
- boolean pretty) {
- StringBuffer sb = new StringBuffer();
- String nl = pretty ? "\n " : "";
- sb.append("@" + JSNIMETHODS_NAME + "({");
- for (JsniMethod jsniMethod : jsniMethods) {
- sb.append(jsniMethod.toString());
- sb.append(',');
- sb.append(nl);
- }
- sb.append("})");
- return sb.toString().toCharArray();
- }
-
- private void rewriteCompilationUnit(TreeLogger logger, char[] source,
- List<Replacement> changes, CompilationUnitProvider cup, boolean pretty)
- throws UnableToCompleteException {
-
- // Collect all JSNI methods in the compilation unit.
- JClassType[] types = oracle.getTypesInCompilationUnit(cup);
- for (JClassType type : types) {
- if (!type.getQualifiedSourceName().startsWith("java.")) {
- collectJsniMethods(logger, source, type);
- }
- }
-
- // Annotate the appropriate types with JsniMethod annotations.
- for (JClassType type : types) {
- List<JsniMethod> jsniMethods = jsniMethodMap.get(type);
- if (jsniMethods != null && jsniMethods.size() > 0) {
- char[] annotation = genJsniMethodsAnnotation(jsniMethods, pretty);
- int declStart = type.getDeclStart();
- changes.add(new Replacement(declStart, declStart, annotation));
- }
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsniMethods.java b/dev/core/src/com/google/gwt/dev/shell/JsniMethods.java
deleted file mode 100644
index 2631851..0000000
--- a/dev/core/src/com/google/gwt/dev/shell/JsniMethods.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.shell;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Encodes all JSNI methods into a compiled hosted mode class file.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface JsniMethods {
-
- /**
- * Encodes a JSNI method into a compiled hosted mode class file.
- */
- @Target(value = {})
- public @interface JsniMethod {
- /**
- * Source file of the method.
- */
- String file();
-
- /**
- * Starting line number of the method.
- */
- int line();
-
- /**
- * The mangled method name (a jsni signature).
- */
- String name();
-
- /**
- * The parameter names.
- */
- String[] paramNames();
-
- /**
- * The script body. The reason this is an array rather than a single string
- * is that 64k is the max size of a single string in a class file, and some
- * methods (such as TypeSerializer method maps) will exceed this.
- */
- String[] body();
- }
-
- /**
- * The set of all methods.
- */
- JsniMethod[] value();
-}
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellGWT.java b/dev/core/src/com/google/gwt/dev/shell/ShellGWT.java
deleted file mode 100644
index a38cea1..0000000
--- a/dev/core/src/com/google/gwt/dev/shell/ShellGWT.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2007 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.shell;
-
-import com.google.gwt.dev.About;
-
-/**
- * This class is the hosted-mode peer for {@link com.google.gwt.core.client.GWT}.
- */
-public class ShellGWT {
-
- public static <T> T create(Class<?> classLiteral) {
- return JavaScriptHost.<T>rebindAndCreate(classLiteral);
- }
-
- public static String getTypeName(Object o) {
- return o != null ? o.getClass().getName() : null;
- }
-
- public static String getVersion() {
- return About.GWT_VERSION_NUM;
- };
-
- public static void log(String message, Throwable e) {
- JavaScriptHost.log(message, e);
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
index 2175316..39cb165 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -17,18 +17,13 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.Rules;
-import com.google.gwt.dev.jdt.ByteCodeCompiler;
import com.google.gwt.dev.jdt.RebindOracle;
-import com.google.gwt.dev.jdt.SourceOracle;
-
-import org.apache.commons.collections.map.AbstractReferenceMap;
-import org.apache.commons.collections.map.ReferenceIdentityMap;
import java.io.File;
-import java.util.Map;
/**
* Provides an environment for a {@link com.google.gwt.dev.shell.ModuleSpace}
@@ -36,10 +31,6 @@
*/
public class ShellModuleSpaceHost implements ModuleSpaceHost {
- @SuppressWarnings("unchecked")
- private static Map<ModuleDef, ByteCodeCompiler> byteCodeCompilersByModule = new ReferenceIdentityMap(
- AbstractReferenceMap.WEAK, AbstractReferenceMap.HARD, true);
-
protected final File genDir;
protected final TypeOracle typeOracle;
@@ -52,8 +43,6 @@
private RebindOracle rebindOracle;
- private final boolean saveJsni;
-
private final File shellDir;
private ModuleSpace space;
@@ -63,12 +52,11 @@
* @param saveJsni
*/
public ShellModuleSpaceHost(TreeLogger logger, TypeOracle typeOracle,
- ModuleDef module, File genDir, File shellDir, boolean saveJsni) {
+ ModuleDef module, File genDir, File shellDir) {
this.logger = logger;
this.typeOracle = typeOracle;
this.module = module;
this.genDir = genDir;
- this.saveJsni = saveJsni;
// Combine the user's output dir with the module name to get the
// module-specific output dir.
@@ -93,16 +81,6 @@
throws UnableToCompleteException {
this.space = readySpace;
- // Create a host for the hosted mode compiler.
- // We add compilation units to it as deferred binding generators write them.
- //
- SourceOracle srcOracle = new HostedModeSourceOracle(typeOracle, saveJsni
- ? genDir : null);
-
- // Create or find the compiler to be used by the compiling class loader.
- //
- ByteCodeCompiler compiler = getOrCreateByteCodeCompiler(srcOracle);
-
// Establish an environment for JavaScript property providers to run.
//
ModuleSpacePropertyOracle propOracle = new ModuleSpacePropertyOracle(
@@ -112,8 +90,8 @@
// It has to wait until now because we need to inject javascript.
//
Rules rules = module.getRules();
- rebindOracle = new StandardRebindOracle(typeOracle, propOracle, module,
- rules, genDir, shellDir, module.getCacheManager(), null);
+ rebindOracle = new StandardRebindOracle(module.getCompilationState(),
+ propOracle, module, rules, genDir, shellDir, new ArtifactSet());
// Create a completely isolated class loader which owns all classes
// associated with a particular module. This effectively builds a
@@ -126,8 +104,8 @@
// accidentally 'escaping' its domain and loading classes from the system
// class loader (the one that loaded the shell itself).
//
- classLoader = new CompilingClassLoader(logger, compiler, typeOracle,
- readySpace);
+ classLoader = new CompilingClassLoader(logger,
+ module.getCompilationState(), readySpace);
}
public String rebind(TreeLogger rebindLogger, String sourceTypeName)
@@ -136,18 +114,6 @@
return rebindOracle.rebind(rebindLogger, sourceTypeName);
}
- ByteCodeCompiler getOrCreateByteCodeCompiler(SourceOracle srcOracle) {
- ByteCodeCompiler compiler;
- synchronized (byteCodeCompilersByModule) {
- compiler = byteCodeCompilersByModule.get(module);
- if (compiler == null) {
- compiler = new ByteCodeCompiler(srcOracle, module.getCacheManager());
- byteCodeCompilersByModule.put(module, compiler);
- }
- }
- return compiler;
- }
-
private void checkForModuleSpace() {
if (space == null) {
throw new IllegalStateException("Module initialization error");
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
index f8fb4cd..1a3dfcc 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
@@ -24,24 +24,21 @@
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.GeneratedResource;
import com.google.gwt.core.ext.linker.impl.StandardGeneratedResource;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.cfg.PublicOracle;
-import com.google.gwt.dev.jdt.CacheManager;
-import com.google.gwt.dev.jdt.StaticCompilationUnitProvider;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
-import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.impl.Shared;
import com.google.gwt.dev.util.Util;
import java.io.ByteArrayOutputStream;
-import java.io.CharArrayWriter;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.net.MalformedURLException;
-import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -49,80 +46,91 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedSet;
/**
- * An abstract implementation of a generator context in terms of a
- * {@link com.google.gwt.dev.jdt.MutableCompilationServiceHost}, a
- * {@link com.google.gwt.dev.jdt.PropertyOracle}, and a
- * {@link com.google.gwt.core.server.typeinfo.TypeOracle}. The generator
- * interacts with the mutable source oracle by increasing the available
- * compilation units as they are generated.
+ * Manages generators and generated units during a single compilation.
*/
public class StandardGeneratorContext implements GeneratorContext {
/**
- * This compilation unit provider acts as a normal compilation unit provider
- * as well as a buffer into which generators can write their source. A
- * controller should ensure that source isn't requested until the generator
- * has finished writing it.
+ * This compilation unit acts as a normal compilation unit as well as a buffer
+ * into which generators can write their source. A controller should ensure
+ * that source isn't requested until the generator has finished writing it.
*/
- private static class GeneratedCompilationUnitProvider extends
- StaticCompilationUnitProvider {
+ private static class GeneratedUnitWithFile extends CompilationUnit {
- public CharArrayWriter caw;
+ private File file;
- public PrintWriter pw;
+ private PrintWriter pw;
- public char[] source;
+ private String source;
- public GeneratedCompilationUnitProvider(String packageName,
- String simpleTypeName) {
- super(packageName, simpleTypeName, null);
- caw = new CharArrayWriter();
- pw = new PrintWriter(caw, true);
+ private StringWriter sw;
+
+ private final String typeName;
+
+ public GeneratedUnitWithFile(String typeName) {
+ this.typeName = typeName;
+ sw = new StringWriter();
+ pw = new PrintWriter(sw, true);
}
/**
* Finalizes the source and adds this compilation unit to the host.
*/
public void commit() {
- source = caw.toCharArray();
- pw.close();
+ source = sw.toString();
pw = null;
- caw.close();
- caw = null;
+ sw = null;
}
@Override
- public char[] getSource() {
- if (source == null) {
+ public String getDisplayLocation() {
+ if (file == null) {
+ return "transient source for " + typeName;
+ } else {
+ return file.getAbsoluteFile().toURI().toString();
+ }
+ }
+
+ @Override
+ public String getSource() {
+ if (source == null && file == null) {
throw new IllegalStateException("source not committed");
}
+ if (source == null) {
+ source = Util.readFileAsString(file);
+ }
+ assert (source != null);
return source;
}
- }
- /**
- * {@link CompilationUnitProvider} used to represent generated source code
- * which is stored on disk. This class is only used if the -gen flag is
- * specified.
- */
- private static final class GeneratedCUP extends URLCompilationUnitProvider {
- private GeneratedCUP(URL url, String name) {
- super(url, name);
+ @Override
+ public String getTypeName() {
+ return typeName;
}
@Override
- public long getLastModified() throws UnableToCompleteException {
- // Make it seem really old so it won't cause recompiles.
- //
- return 0L;
- }
-
- @Override
- public boolean isTransient() {
+ public boolean isGenerated() {
return true;
}
+
+ public boolean isOnDisk() {
+ return file != null;
+ }
+
+ public void setFile(File file) {
+ assert (file.exists() && file.canRead());
+ this.file = file;
+ }
+
+ @Override
+ protected void dumpSource() {
+ if (file != null) {
+ source = null;
+ }
+ }
}
/**
@@ -161,9 +169,9 @@
private final ArtifactSet artifactSet;
- private final CacheManager cacheManager;
+ private final Set<GeneratedUnitWithFile> committedGeneratedCups = new HashSet<GeneratedUnitWithFile>();
- private final Set<GeneratedCompilationUnitProvider> committedGeneratedCups = new HashSet<GeneratedCompilationUnitProvider>();
+ private final CompilationState compilationState;
private Class<? extends Generator> currentGenerator;
@@ -179,23 +187,20 @@
private final PublicOracle publicOracle;
- private final TypeOracle typeOracle;
-
- private final Map<PrintWriter, GeneratedCompilationUnitProvider> uncommittedGeneratedCupsByPrintWriter = new IdentityHashMap<PrintWriter, GeneratedCompilationUnitProvider>();
+ private final Map<PrintWriter, GeneratedUnitWithFile> uncommittedGeneratedCupsByPrintWriter = new IdentityHashMap<PrintWriter, GeneratedUnitWithFile>();
/**
* Normally, the compiler host would be aware of the same types that are
* available in the supplied type oracle although it isn't strictly required.
*/
- public StandardGeneratorContext(TypeOracle typeOracle,
+ public StandardGeneratorContext(CompilationState compilationState,
PropertyOracle propOracle, PublicOracle publicOracle, File genDir,
- File outDir, CacheManager cacheManager, ArtifactSet artifactSet) {
- this.typeOracle = typeOracle;
+ File outDir, ArtifactSet artifactSet) {
+ this.compilationState = compilationState;
this.propOracle = propOracle;
this.publicOracle = publicOracle;
this.genDir = genDir;
this.outDir = outDir;
- this.cacheManager = cacheManager;
this.artifactSet = artifactSet;
}
@@ -203,7 +208,7 @@
* Commits a pending generated type.
*/
public final void commit(TreeLogger logger, PrintWriter pw) {
- GeneratedCompilationUnitProvider gcup = uncommittedGeneratedCupsByPrintWriter.get(pw);
+ GeneratedUnitWithFile gcup = uncommittedGeneratedCupsByPrintWriter.get(pw);
if (gcup != null) {
gcup.commit();
uncommittedGeneratedCupsByPrintWriter.remove(pw);
@@ -221,9 +226,7 @@
public void commitArtifact(TreeLogger logger, Artifact<?> artifact)
throws UnableToCompleteException {
// The artifactSet will be null in hosted mode, since we never run Linkers
- if (artifactSet != null) {
- artifactSet.replace(artifact);
- }
+ artifactSet.replace(artifact);
}
public GeneratedResource commitResource(TreeLogger logger, OutputStream os)
@@ -234,7 +237,6 @@
if (pendingResource != null) {
// Actually write the bytes to disk.
pendingResource.commit(logger);
- cacheManager.addGeneratedResource(pendingResource.getPartialPath());
// Add the GeneratedResource to the ArtifactSet
GeneratedResource toReturn;
@@ -293,26 +295,22 @@
"Generated source files...", null);
}
- assert (cacheManager.getTypeOracle() == typeOracle);
- TypeOracleBuilder builder = new TypeOracleBuilder(cacheManager);
- for (Iterator<GeneratedCompilationUnitProvider> iter = committedGeneratedCups.iterator(); iter.hasNext();) {
- GeneratedCompilationUnitProvider gcup = iter.next();
- String typeName = gcup.getTypeName();
- String genTypeName = gcup.getPackageName() + "." + typeName;
- genTypeNames.add(genTypeName);
- CompilationUnitProvider cup = writeSource(logger, gcup, typeName);
- builder.addCompilationUnit(cup);
- cacheManager.addGeneratedCup(cup);
+ for (GeneratedUnitWithFile gcup : committedGeneratedCups) {
+ String qualifiedTypeName = gcup.getTypeName();
+ genTypeNames.add(qualifiedTypeName);
+ maybeWriteSource(gcup, qualifiedTypeName);
+ compilationState.addGeneratedCompilationUnit(gcup);
if (subBranch != null) {
- subBranch.log(TreeLogger.DEBUG, cup.getLocation(), null);
+ subBranch.log(TreeLogger.DEBUG, gcup.getDisplayLocation(), null);
}
}
- builder.build(branch);
+ compilationState.compile(logger);
}
// Return the generated types.
+ TypeOracle typeOracle = getTypeOracle();
JClassType[] genTypes = new JClassType[genTypeNames.size()];
int next = 0;
for (Iterator<String> iter = genTypeNames.iterator(); iter.hasNext();) {
@@ -333,10 +331,8 @@
String msg = "For the following type(s), generated source was never committed (did you forget to call commit()?)";
logger = logger.branch(TreeLogger.WARN, msg, null);
- for (Iterator<GeneratedCompilationUnitProvider> iter = uncommittedGeneratedCupsByPrintWriter.values().iterator(); iter.hasNext();) {
- StaticCompilationUnitProvider cup = iter.next();
- String typeName = cup.getPackageName() + "." + cup.getTypeName();
- logger.log(TreeLogger.WARN, typeName, null);
+ for (GeneratedUnitWithFile unit : uncommittedGeneratedCupsByPrintWriter.values()) {
+ logger.log(TreeLogger.WARN, unit.getTypeName(), null);
}
}
@@ -355,7 +351,7 @@
}
public final TypeOracle getTypeOracle() {
- return typeOracle;
+ return compilationState.getTypeOracle();
}
public void setCurrentGenerator(Class<? extends Generator> currentGenerator) {
@@ -367,7 +363,8 @@
String typeName = packageName + "." + simpleTypeName;
// Is type already known to the host?
- JClassType existingType = typeOracle.findType(packageName, simpleTypeName);
+ JClassType existingType = getTypeOracle().findType(packageName,
+ simpleTypeName);
if (existingType != null) {
logger.log(TreeLogger.DEBUG, "Type '" + typeName
+ "' already exists and will not be re-created ", null);
@@ -385,8 +382,13 @@
// The type isn't there, so we can let the caller create it. Remember that
// it is pending so another attempt to create the same type will fail.
- GeneratedCompilationUnitProvider gcup = new GeneratedCompilationUnitProvider(
- packageName, simpleTypeName);
+ String qualifiedSourceName;
+ if (packageName.length() == 0) {
+ qualifiedSourceName = simpleTypeName;
+ } else {
+ qualifiedSourceName = packageName + '.' + simpleTypeName;
+ }
+ GeneratedUnitWithFile gcup = new GeneratedUnitWithFile(qualifiedSourceName);
uncommittedGeneratedCupsByPrintWriter.put(gcup.pw, gcup);
generatedTypeNames.add(typeName);
@@ -433,8 +435,11 @@
}
// See if the file is already committed.
- if (cacheManager.hasGeneratedResource(partialPath)) {
- return null;
+ SortedSet<GeneratedResource> resources = artifactSet.find(GeneratedResource.class);
+ for (GeneratedResource resource : resources) {
+ if (partialPath.equals(resource.getPartialPath())) {
+ return null;
+ }
}
// See if the file is pending.
@@ -483,43 +488,25 @@
* Writes the source of the specified compilation unit to disk if a gen
* directory is specified.
*
- * @param cup the compilation unit whose contents might need to be written
- * @param simpleTypeName the fully-qualified type name
- * @return a wrapper for the existing cup with a proper location
+ * @param unit the compilation unit whose contents might need to be written
+ * @param qualifiedTypeName the fully-qualified type name
*/
- private CompilationUnitProvider writeSource(TreeLogger logger,
- CompilationUnitProvider cup, String simpleTypeName)
- throws UnableToCompleteException {
+ private void maybeWriteSource(GeneratedUnitWithFile unit,
+ String qualifiedTypeName) {
- if (genDir == null) {
+ if (unit.isOnDisk() || genDir == null) {
// No place to write it.
- return cup;
- }
-
- if (Util.isCompilationUnitOnDisk(cup.getLocation())) {
- // Already on disk.
- return cup;
+ return;
}
// Let's do write it.
- String typeName = cup.getPackageName() + "." + simpleTypeName;
- String relativePath = typeName.replace('.', '/') + ".java";
- File srcFile = new File(genDir, relativePath);
- Util.writeCharsAsFile(logger, srcFile, cup.getSource());
-
- // Update the location of the cup
- Throwable caught = null;
- try {
- URL fileURL = srcFile.toURI().toURL();
- URLCompilationUnitProvider fileBaseCup = new GeneratedCUP(fileURL,
- cup.getPackageName());
- return fileBaseCup;
- } catch (MalformedURLException e) {
- caught = e;
+ String packageName = Shared.getPackageName(qualifiedTypeName);
+ String shortName = Shared.getShortName(qualifiedTypeName);
+ File dir = new File(genDir, packageName.replace('.', File.separatorChar));
+ dir.mkdirs();
+ File srcFile = new File(dir, shortName + ".java");
+ if (Util.writeStringAsFile(srcFile, unit.getSource())) {
+ unit.setFile(srcFile);
}
- logger.log(TreeLogger.ERROR,
- "Internal error: cannot build URL from synthesized file name '"
- + srcFile.getAbsolutePath() + "'", caught);
- throw new UnableToCompleteException();
}
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
index 554a351..c338a91 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -20,11 +20,10 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.cfg.PublicOracle;
import com.google.gwt.dev.cfg.Rule;
import com.google.gwt.dev.cfg.Rules;
-import com.google.gwt.dev.jdt.CacheManager;
+import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.jdt.RebindOracle;
import com.google.gwt.dev.util.Util;
@@ -51,10 +50,9 @@
private final List<String> usedTypeNames = new ArrayList<String>();
- public Rebinder(TypeOracle typeOracle, PropertyOracle propOracle,
- PublicOracle publicOracle) {
- genCtx = new StandardGeneratorContext(typeOracle, propOracle,
- publicOracle, genDir, outDir, cacheManager, artifactSet);
+ public Rebinder() {
+ genCtx = new StandardGeneratorContext(compilationState, propOracle,
+ publicOracle, genDir, outDir, artifactSet);
}
public String rebind(TreeLogger logger, String typeName)
@@ -135,7 +133,7 @@
private final ArtifactSet artifactSet;
- private final CacheManager cacheManager;
+ private final CompilationState compilationState;
private final File genDir;
@@ -147,22 +145,15 @@
private final Rules rules;
- private final TypeOracle typeOracle;
-
- public StandardRebindOracle(TypeOracle typeOracle, PropertyOracle propOracle,
- PublicOracle publicOracle, Rules rules, File genDir, File moduleOutDir,
- CacheManager cacheManager, ArtifactSet artifactSet) {
- this.typeOracle = typeOracle;
+ public StandardRebindOracle(CompilationState compilationState,
+ PropertyOracle propOracle, PublicOracle publicOracle, Rules rules,
+ File genDir, File moduleOutDir, ArtifactSet artifactSet) {
+ this.compilationState = compilationState;
this.propOracle = propOracle;
this.publicOracle = publicOracle;
this.rules = rules;
this.genDir = genDir;
this.outDir = moduleOutDir;
- if (cacheManager != null) {
- this.cacheManager = cacheManager;
- } else {
- this.cacheManager = new CacheManager(typeOracle);
- }
this.artifactSet = artifactSet;
}
@@ -171,7 +162,7 @@
logger = Messages.TRACE_TOPLEVEL_REBIND.branch(logger, typeName, null);
- Rebinder rebinder = new Rebinder(typeOracle, propOracle, publicOracle);
+ Rebinder rebinder = new Rebinder();
String result = rebinder.rebind(logger, typeName);
Messages.TRACE_TOPLEVEL_REBIND_RESULT.log(logger, result, null);
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteJsniMethods.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteJsniMethods.java
index 54a536f..a00ce8d 100644
--- a/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteJsniMethods.java
+++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteJsniMethods.java
@@ -367,7 +367,6 @@
+ descriptor;
String argsDescriptor = descriptor.substring(argsIndexBegin,
argsIndexEnd + 1);
- String sourceName = classDesc.replace('/', '.').replace('$', '.');
- return "@" + sourceName + "::" + name + argsDescriptor;
+ return "@" + classDesc.replace('/', '.') + "::" + name + argsDescriptor;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
index ae78db3..723a431 100644
--- a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
@@ -16,8 +16,11 @@
package com.google.gwt.dev.shell.tomcat;
import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.util.FileOracle;
-import com.google.gwt.dev.util.FileOracleFactory;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.impl.ClassPathEntry;
+import com.google.gwt.dev.resource.impl.PathPrefix;
+import com.google.gwt.dev.resource.impl.PathPrefixSet;
+import com.google.gwt.dev.resource.impl.ResourceOracleImpl;
import com.google.gwt.util.tools.Utility;
import org.apache.catalina.Connector;
@@ -39,7 +42,11 @@
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.ServerSocket;
+import java.net.URISyntaxException;
import java.net.URL;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* Wraps an instance of the Tomcat web server used in hosted mode.
@@ -249,14 +256,14 @@
/*
* Assumes that the leaf is a file (not a directory).
*/
- private void copyFileNoOverwrite(TreeLogger logger, FileOracle fileOracle,
- String srcResName, File catBase) {
+ private void copyFileNoOverwrite(TreeLogger logger, String srcResName,
+ Resource resource, File catBase) {
File dest = new File(catBase, srcResName);
InputStream is = null;
FileOutputStream os = null;
try {
- URL srcRes = fileOracle.find(srcResName);
+ URL srcRes = resource.getURL();
if (srcRes == null) {
logger.log(TreeLogger.TRACE, "Cannot find: " + srcResName, null);
return;
@@ -321,28 +328,61 @@
"Property 'catalina.base' not specified; checking for a standard catalina base image instead",
null);
- // Recursively copies out files and directories under
- // com.google.gwt.dev.etc.tomcat.
- //
- FileOracleFactory fof = new FileOracleFactory();
- final String tomcatEtcDir = "com/google/gwt/dev/etc/tomcat/";
- fof.addRootPackage(tomcatEtcDir, null);
- FileOracle fo = fof.create(logger);
- if (fo.isEmpty()) {
- logger.log(TreeLogger.WARN, "Could not find " + tomcatEtcDir, null);
- return null;
+ // Recursively copies out files and directories
+ String tomcatEtcDir = "com/google/gwt/dev/etc/tomcat/";
+ Map<String, Resource> resourceMap = null;
+ Throwable caught = null;
+ try {
+ resourceMap = getResourcesFor(logger, tomcatEtcDir);
+ } catch (URISyntaxException e) {
+ caught = e;
+ } catch (IOException e) {
+ caught = e;
}
File catBase = new File(workDir, "tomcat");
- String[] allChildren = fo.getAllFiles();
- for (int i = 0; i < allChildren.length; i++) {
- String src = allChildren[i];
- copyFileNoOverwrite(logger, fo, src, catBase);
+ if (resourceMap == null || resourceMap.isEmpty()) {
+ logger.log(TreeLogger.WARN, "Could not find " + tomcatEtcDir, caught);
+ } else {
+ for (Entry<String, Resource> entry : resourceMap.entrySet()) {
+ copyFileNoOverwrite(logger, entry.getKey(), entry.getValue(), catBase);
+ }
}
return catBase.getAbsolutePath();
}
+ /**
+ * Hacky, but fast.
+ */
+ private Map<String, Resource> getResourcesFor(TreeLogger logger,
+ String tomcatEtcDir) throws URISyntaxException, IOException {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ URL url = contextClassLoader.getResource(tomcatEtcDir);
+ if (url == null) {
+ return null;
+ }
+ String prefix = "";
+ String urlString = url.toString();
+ if (urlString.startsWith("jar:")) {
+ assert urlString.contains(".jar!/" + tomcatEtcDir);
+ urlString = urlString.substring(4, urlString.indexOf('!'));
+ url = new URL(urlString);
+ prefix = tomcatEtcDir;
+ }
+ ClassPathEntry entry = ResourceOracleImpl.createEntryForUrl(logger, url);
+ assert (entry != null);
+ ResourceOracleImpl resourceOracle = new ResourceOracleImpl(
+ Collections.singletonList(entry));
+ PathPrefixSet pathPrefixSet = new PathPrefixSet();
+ PathPrefix pathPrefix = new PathPrefix(prefix, null, true);
+ pathPrefixSet.add(pathPrefix);
+ resourceOracle.setPathPrefixes(pathPrefixSet);
+ resourceOracle.refresh(logger);
+ Map<String, Resource> resourceMap = resourceOracle.getResourceMap();
+ return resourceMap;
+ }
+
private void publishAttributeToWebApp(TreeLogger logger,
StandardContext webapp, String attrName, Object attrValue) {
logger.log(TreeLogger.TRACE, "Adding attribute '" + attrName
diff --git a/dev/core/src/com/google/gwt/dev/util/FileOracle.java b/dev/core/src/com/google/gwt/dev/util/FileOracle.java
deleted file mode 100644
index e44a207..0000000
--- a/dev/core/src/com/google/gwt/dev/util/FileOracle.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2006 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.util;
-
-import java.net.URL;
-
-/**
- * An abstraction for finding and retrieving a set of URLs by logical name.
- * Intuitively, it works like a jar in that each URL is uniquely located
- * somewhere in an abstract namespace. The abstract names must be constructed
- * from a series of zero or more valid Java identifiers followed the '/'
- * character and finally ending in a valid filename, for example,
- * "com/google/gwt/blah.txt". Each contained abstract path corresponds to a
- * physical URL.
- */
-public abstract class FileOracle {
-
- /**
- * Finds a URL by abstract path.
- *
- * @param abstractPath the abstract path of the URL to find.
- * @return the physical URL of the contained URL, or <code>null</code> the
- * abstract path does not refer to a contained URL.
- */
- public abstract URL find(String abstractPath);
-
- /**
- * Gets the abstract path for every URL indexed by this FileOracle. Elements
- * of the result set can be passed into {@link #find(String)} to retrieve the
- * physical URL.
- *
- * @return the abstract path of every URL indexed by this FileOracle
- */
- public abstract String[] getAllFiles();
-
- /**
- * Tests if this FileOracle has URLs.
- *
- * @return <tt>true</tt> if this list has no elements; <tt>false</tt>
- * otherwise.
- */
- public abstract boolean isEmpty();
-
-}
diff --git a/dev/core/src/com/google/gwt/dev/util/FileOracleFactory.java b/dev/core/src/com/google/gwt/dev/util/FileOracleFactory.java
deleted file mode 100644
index 70d80e1..0000000
--- a/dev/core/src/com/google/gwt/dev/util/FileOracleFactory.java
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright 2006 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.util;
-
-import com.google.gwt.core.ext.TreeLogger;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-/**
- * Creates a FileOracle based on a set of logical packages combined with either
- * a URLClassLoader. For each specified package, the ClassLoader is searched for
- * instances of that package as a directory. The results of this operation are
- * merged together into a single list of URLs whose order is determined by the
- * order of URLs in the ClassLoader. The relative order of different logical
- * packages originating from the same URL in the ClassLoader is undefined.
- *
- * Once the sorted list of URLs is resolved, each URL is recursively searched to
- * index all of its files (optionally, that pass the given FileOracleFilter).
- * The results of this indexing are used to create the output FileOracle. Once
- * the FileOracle is created, its index is fixed and no longer depends on the
- * underlying URLClassLoader or file system. However, URLs returned from the
- * FileOracle may become invalid if the contents of the file system change.
- *
- * Presently, only URLs beginning with <code>file:</code> and
- * <code>jar:file:</code> can be inspected to index children. Any other types
- * of URLs will generate a warning. The set of children indexed by
- * <code>jar:file:</code> type URLs is fixed at creation time, but the set of
- * children from <code>file:</code> type URLs will dynamically query the
- * underlying file system.
- */
-public class FileOracleFactory {
-
- /**
- * Used to decide whether or not a resource name should be included in an
- * enumeration.
- */
- public interface FileFilter {
- boolean accept(String name);
- }
-
- /**
- * Implementation of a FileOracle as an ordered (based on class path) list of
- * abstract names (relative to some root), each mapped to a concrete URL.
- */
- private static final class FileOracleImpl extends FileOracle {
-
- private final String[] logicalNames;
-
- private final Map logicalToPhysical;
-
- /**
- * Creates a new FileOracle.
- *
- * @param logicalNames An ordered list of abstract path name strings.
- * @param logicalToPhysical A map of every item in logicalNames onto a URL.
- */
- public FileOracleImpl(List logicalNames, Map logicalToPhysical) {
- this.logicalNames = (String[]) logicalNames.toArray(new String[logicalNames.size()]);
- this.logicalToPhysical = new HashMap(logicalToPhysical);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.dev.util.FileOracle#find(java.lang.String)
- */
- public URL find(String partialPath) {
- return (URL) logicalToPhysical.get(partialPath);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.dev.util.FileOracle#getAllFiles()
- */
- public String[] getAllFiles() {
- return logicalNames;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.dev.util.FileOracle#isEmpty()
- */
- public boolean isEmpty() {
- return logicalNames.length == 0;
- }
- }
-
- /**
- * Given a set of logical packages, finds every occurrence of each of those
- * packages within cl, and then sorts them relative to each other based on
- * classPathUrlList.
- *
- * @param logger Logs the process.
- * @param cl Provides the underlying class path.
- * @param packageSet The input set of logical packages to search for and sort.
- * @param classPathUrlList The order in which to sort the results.
- * @param sortedUrls An output list to which urls are appended.
- * @param sortedPackages An output list to which logical packages are appended
- * exactly corresponding to appends made to sortedUrls.
- * @param recordPackages If false, only empty strings are appended to
- * sortedPackages.
- */
- private static void addPackagesInSortedOrder(TreeLogger logger,
- URLClassLoader cl, Map packageMap, List classPathUrlList,
- List sortedUrls, List sortedPackages, List sortedFilters,
- boolean recordPackages) {
-
- // Exhaustively find every package on the classpath in an unsorted fashion
- //
- List unsortedUrls = new ArrayList();
- List unsortedPackages = new ArrayList();
- List unsortedFilters = new ArrayList();
- for (Iterator itPkg = packageMap.keySet().iterator(); itPkg.hasNext();) {
- String curPkg = (String) itPkg.next();
- FileFilter curFilter = (FileFilter) packageMap.get(curPkg);
- try {
- Enumeration found = cl.findResources(curPkg);
- if (!recordPackages) {
- curPkg = "";
- }
- while (found.hasMoreElements()) {
- URL match = (URL) found.nextElement();
- unsortedUrls.add(match);
- unsortedPackages.add(curPkg);
- unsortedFilters.add(curFilter);
- }
- } catch (IOException e) {
- logger.log(TreeLogger.WARN, "Unexpected error searching classpath for "
- + curPkg, e);
- }
- }
-
- /*
- * Now sort the collected list by the proper class path order. This is an
- * O(N*M) operation, but it should be okay for what we're doing
- */
-
- // pre-convert the List of URL to String[] to speed up the inner loop below
- int c = unsortedUrls.size();
- String[] unsortedUrlStrings = new String[c];
- for (int i = 0; i < c; ++i) {
- unsortedUrlStrings[i] = unsortedUrls.get(i).toString();
- // strip the jar prefix for text matching purposes
- if (unsortedUrlStrings[i].startsWith("jar:")) {
- unsortedUrlStrings[i] = unsortedUrlStrings[i].substring(4);
- }
- }
-
- // now sort the URLs based on classPathUrlList
- for (Iterator itCp = classPathUrlList.iterator(); itCp.hasNext();) {
- URL curCpUrl = (URL) itCp.next();
- String curUrlString = curCpUrl.toExternalForm();
- // find all URLs that match this particular entry
- for (int i = 0; i < c; ++i) {
- if (unsortedUrlStrings[i].startsWith(curUrlString)) {
- sortedUrls.add(unsortedUrls.get(i));
- sortedPackages.add(unsortedPackages.get(i));
- sortedFilters.add(unsortedFilters.get(i));
- }
- }
- }
- }
-
- /**
- * Index all the children of a particular folder (recursively).
- *
- * @param logger Logs the process.
- * @param filter If non-null, filters out which files get indexed.
- * @param stripBaseLen The number of characters to strip from the beginning of
- * every child's file path when computing the logical name.
- * @param curDir The directory to index.
- * @param logicalNames An output List of Children found under this URL.
- * @param logicalToPhysical An output Map of Children found under this URL
- * mapped to their concrete URLs.
- */
- private static void indexFolder(TreeLogger logger, FileFilter filter,
- int stripBaseLen, File curDir, List logicalNames, Map logicalToPhysical) {
- File[] files = curDir.listFiles();
- for (int i = 0; i < files.length; i++) {
- File f = files[i];
- if (f.exists()) {
- if (f.isDirectory()) {
- indexFolder(logger, filter, stripBaseLen, f, logicalNames,
- logicalToPhysical);
- } else if (f.isFile()) {
- try {
- String logicalName = f.getAbsolutePath().substring(stripBaseLen);
- logicalName = logicalName.replace(File.separatorChar, '/');
- if (logicalToPhysical.containsKey(logicalName)) {
- // this logical name is shadowed
- logger.log(TreeLogger.DEBUG, "Ignoring already-resolved "
- + logicalName, null);
- continue;
- }
- if (filter != null && !filter.accept(logicalName)) {
- // filtered out
- logger.log(TreeLogger.SPAM, "Filtered out " + logicalName, null);
- continue;
- }
- URL physicalUrl = f.toURL();
- logicalToPhysical.put(logicalName, physicalUrl);
- logicalNames.add(logicalName);
- logger.log(TreeLogger.TRACE, "Found " + logicalName, null);
- } catch (IOException e) {
- logger.log(TreeLogger.WARN, "Unexpected error resolving " + f, e);
- }
- }
- }
- }
- }
-
- /**
- * Index all the children in a particular folder of a jar.
- *
- * @param logger Logs the process.
- * @param filter If non-null, filters out which files get indexed.
- * @param jarUrl The URL of the containing jar file.
- * @param jarFile The jarFile to index.
- * @param basePath The sub tree within the jarFile to index.
- * @param pkgBase If non-empty, causes the logical names of children to be
- * shorter (rooting them higher in the tree).
- * @param logicalNames An output List of Children found under this URL.
- * @param logicalToPhysical An output Map of Children found under this URL
- * mapped to their concrete URLs.
- */
- private static void indexJar(TreeLogger logger, FileFilter filter,
- String jarUrl, JarFile jarFile, String basePath, String pkgBase,
- List logicalNames, Map logicalToPhysical) {
- int prefixCharsToStrip = basePath.length() - pkgBase.length();
- for (Enumeration enumJar = jarFile.entries(); enumJar.hasMoreElements();) {
- JarEntry jarEntry = (JarEntry) enumJar.nextElement();
- String jarEntryName = jarEntry.getName();
- if (jarEntryName.startsWith(basePath) && !jarEntry.isDirectory()) {
- String logicalName = jarEntryName.substring(prefixCharsToStrip);
- String physicalUrlString = jarUrl + "!/" + jarEntryName;
- if (logicalToPhysical.containsKey(logicalName)) {
- // this logical name is shadowed
- logger.log(TreeLogger.DEBUG, "Ignoring already-resolved "
- + logicalName, null);
- continue;
- }
- if (filter != null && !filter.accept(logicalName)) {
- // filtered out
- logger.log(TreeLogger.SPAM, "Filtered out " + logicalName, null);
- continue;
- }
- try {
- URL physicalUrl = new URL(physicalUrlString);
- logicalToPhysical.put(logicalName, physicalUrl);
- logicalNames.add(logicalName);
- logger.log(TreeLogger.TRACE, "Found " + logicalName, null);
- } catch (MalformedURLException e) {
- logger.log(TreeLogger.WARN, "Unexpected error resolving "
- + physicalUrlString, e);
- }
- }
- }
- }
-
- /**
- * Finds all children of the specified URL and indexes them.
- *
- * @param logger Logs the process.
- * @param filter If non-null, filters out which files get indexed.
- * @param url The URL to index, must be <code>file:</code> or
- * <code>jar:file:</code>
- * @param pkgBase A prefix to exclude when indexing children.
- * @param logicalNames An output List of Children found under this URL.
- * @param logicalToPhysical An output Map of Children found under this URL
- * mapped to their concrete URLs.
- * @throws URISyntaxException if an unexpected error occurs.
- * @throws IOException if an unexpected error occurs.
- */
- private static void indexURL(TreeLogger logger, FileFilter filter, URL url,
- String pkgBase, List logicalNames, Map logicalToPhysical)
- throws URISyntaxException, IOException {
-
- String urlString = url.toString();
- if (url.getProtocol().equals("file")) {
- URI uri = new URI(urlString);
- File f = new File(uri);
- if (f.isDirectory()) {
- int prefixCharsToStrip = f.getAbsolutePath().length() + 1
- - pkgBase.length();
- indexFolder(logger, filter, prefixCharsToStrip, f, logicalNames,
- logicalToPhysical);
- } else {
- // We can't handle files here, only directories. If this is a jar
- // reference, the url must come in as a "jar:file:<stuff>!/[stuff/]".
- // Fall through.
- logger.log(TreeLogger.WARN, "Unexpected error, " + f
- + " is neither a file nor a jar", null);
- }
- } else if (url.getProtocol().equals("jar")) {
- String path = url.getPath();
- int pos = path.indexOf('!');
- if (pos >= 0) {
- String jarPath = path.substring(0, pos);
- String dirPath = path.substring(pos + 2);
- URL jarURL = new URL(jarPath);
- if (jarURL.getProtocol().equals("file")) {
- URI jarURI = new URI(jarURL.toString());
- File f = new File(jarURI);
- JarFile jarFile = new JarFile(f);
- // From each child, strip off the leading classpath portion when
- // determining the logical name (sans the pkgBase name we want!)
- //
- indexJar(logger, filter, "jar" + ":" + jarPath, jarFile, dirPath, pkgBase,
- logicalNames, logicalToPhysical);
- } else {
- logger.log(TreeLogger.WARN, "Unexpected error, jar at " + jarURL
- + " must be a file: type URL", null);
- }
- } else {
- throw new URISyntaxException(path, "Cannot locate '!' separator");
- }
- } else {
- logger.log(TreeLogger.WARN, "Unknown URL type for " + urlString, null);
- }
- }
-
- /**
- * The underlying classloader.
- */
- private final URLClassLoader classLoader;
-
- /**
- * A map of packages indexed from the root of the class path onto their
- * corresponding FileFilters.
- */
- private final Map packages = new HashMap();
-
- /**
- * A map of packages that become their own roots (that is their children are
- * indexed relative to them) onto their corresponding FileFilters.
- */
- private final Map rootPackages = new HashMap();
-
- /**
- * Creates a FileOracleFactory with the default URLClassLoader.
- */
- public FileOracleFactory() {
- this((URLClassLoader) FileOracleFactory.class.getClassLoader());
- }
-
- /**
- * Creates a FileOracleFactory.
- *
- * @param classLoader The underlying class path to use.
- */
- public FileOracleFactory(URLClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
- /**
- * Adds a logical package to the product FileOracle. All instances of this
- * package that can be found in the underlying URLClassLoader will have their
- * their children indexed, relative to the class path entry on which they are
- * found.
- *
- * @param packageAsPath For example, "com/google/gwt/core/client".
- */
- public void addPackage(String packageAsPath, FileFilter filter) {
- packageAsPath = ensureTrailingBackslash(packageAsPath);
- packages.put(packageAsPath, filter);
- }
-
- /**
- * Adds a logical root package to the product FileOracle. All instances of
- * this package that can be found in the underlying URLClassLoader will have
- * their their children indexed, relative to their location within
- * packageAsPath. All root packages trump all non-root packages when
- * determining the final precedence order.
- *
- * @param packageAsPath For example, "com/google/gwt/core/client".
- */
- public void addRootPackage(String packageAsPath, FileFilter filter) {
- packageAsPath = ensureTrailingBackslash(packageAsPath);
- rootPackages.put(packageAsPath, filter);
- }
-
- /**
- * Creates the product FileOracle based on the logical packages previously
- * added.
- *
- * @param logger Logs the process.
- * @return a new FileOracle.
- */
- public FileOracle create(TreeLogger logger) {
-
- // get the full expanded URL class path for sorting purposes
- //
- List classPathUrls = new ArrayList();
- for (ClassLoader curCL = classLoader; curCL != null; curCL = curCL.getParent()) {
- if (curCL instanceof URLClassLoader) {
- URLClassLoader curURLCL = (URLClassLoader) curCL;
- URL[] curURLs = curURLCL.getURLs();
- classPathUrls.addAll(Arrays.asList(curURLs));
- }
- }
-
- /*
- * Collect a sorted list of URLs corresponding to all of the logical
- * packages mapped onto the
- */
-
- // The list of
- List urls = new ArrayList();
- List pkgNames = new ArrayList();
- List filters = new ArrayList();
-
- // don't record package names for root packages, they are rebased
- addPackagesInSortedOrder(logger, classLoader, rootPackages, classPathUrls,
- urls, pkgNames, filters, false);
- // record package names for non-root packages
- addPackagesInSortedOrder(logger, classLoader, packages, classPathUrls,
- urls, pkgNames, filters, true);
-
- // We have a complete sorted list of mapped URLs with package prefixes
-
- // Setup data collectors
- List logicalNames = new ArrayList();
- Map logicalToPhysical = new HashMap();
-
- for (int i = 0, c = urls.size(); i < c; ++i) {
- try {
- URL url = (URL) urls.get(i);
- String pkgName = (String) pkgNames.get(i);
- FileFilter filter = (FileFilter) filters.get(i);
- TreeLogger branch = logger.branch(TreeLogger.TRACE, url.toString(),
- null);
- indexURL(branch, filter, url, pkgName, logicalNames, logicalToPhysical);
- } catch (URISyntaxException e) {
- logger.log(TreeLogger.WARN,
- "Unexpected error searching " + urls.get(i), e);
- } catch (IOException e) {
- logger.log(TreeLogger.WARN,
- "Unexpected error searching " + urls.get(i), e);
- }
- }
-
- return new FileOracleImpl(logicalNames, logicalToPhysical);
- }
-
- /**
- * Helper method to regularize packages.
- *
- * @param packageAsPath For exmaple, "com/google/gwt/core/client"
- * @return For example, "com/google/gwt/core/client/"
- */
- private String ensureTrailingBackslash(String packageAsPath) {
- if (packageAsPath.endsWith("/")) {
- return packageAsPath;
- } else {
- return packageAsPath + "/";
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/util/Jsni.java b/dev/core/src/com/google/gwt/dev/util/Jsni.java
index b316b0b..801a192 100644
--- a/dev/core/src/com/google/gwt/dev/util/Jsni.java
+++ b/dev/core/src/com/google/gwt/dev/util/Jsni.java
@@ -16,50 +16,21 @@
package com.google.gwt.dev.util;
import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.JMethod;
-import com.google.gwt.core.ext.typeinfo.JParameter;
-import com.google.gwt.core.ext.typeinfo.JType;
-import com.google.gwt.dev.js.JsParser;
-import com.google.gwt.dev.js.JsParserException;
+import com.google.gwt.dev.javac.JsniMethod;
import com.google.gwt.dev.js.JsSourceGenerationVisitor;
-import com.google.gwt.dev.js.JsParserException.SourceDetail;
-import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsContext;
-import com.google.gwt.dev.js.ast.JsExprStmt;
import com.google.gwt.dev.js.ast.JsExpression;
import com.google.gwt.dev.js.ast.JsFunction;
import com.google.gwt.dev.js.ast.JsNameRef;
import com.google.gwt.dev.js.ast.JsNode;
-import com.google.gwt.dev.js.ast.JsProgram;
-import com.google.gwt.dev.js.ast.JsStatement;
import com.google.gwt.dev.shell.JavaScriptHost;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.List;
-
/**
* Helper methods working with JSNI.
*/
public class Jsni {
/**
- * Represents a logical interval of text.
- */
- public static class Interval {
-
- public final int end;
-
- public final int start;
-
- public Interval(int start, int end) {
- this.start = start;
- this.end = end;
- }
- }
-
- /**
* Generate source code, fixing up any JSNI references for hosted mode.
*
* <p/><table>
@@ -127,205 +98,36 @@
public static final String JSNI_BLOCK_START = "/*-{";
/**
- * Generates the code to wrap a set of parameters as an object array. In Java
- * 1.5 we can take advantage of autoboxing to not have to wrap primitives.
+ * Gets the body of a JSNI method, with Java refs escaped for hosted mode
+ * injection.
*/
- public static String buildArgList(JMethod method) {
- StringBuilder sb = new StringBuilder();
- sb.append("new Object[]{");
-
- JParameter[] params = method.getParameters();
- for (int i = 0; i < params.length; ++i) {
- sb.append(params[i].getName());
- sb.append(", ");
- }
-
- sb.append("}");
- String args = sb.toString();
- return args;
- }
-
- /**
- * Generates the code to pass the exact types associated with each argument of
- * this method.
- */
- public static String buildTypeList(JMethod method) {
- StringBuilder sb = new StringBuilder();
- sb.append("new Class[]{");
-
- JParameter[] params = method.getParameters();
- for (int i = 0; i < params.length; ++i) {
- JType type = params[i].getType();
- String typeName = type.getErasedType().getQualifiedSourceName();
- sb.append(typeName);
- sb.append(".class, ");
- }
-
- sb.append("}");
- String classes = sb.toString();
- return classes;
- }
-
- public static int countNewlines(char[] buf, int start, int end) {
- int total = 0;
- while (start < end) {
- switch (buf[start]) {
- case '\r':
- ++total;
- // if the next character is a line feed, eat it too
- if (start + 1 < end && buf[start + 1] == '\n') {
- ++start;
- }
- break;
- case '\n':
- ++total;
- break;
- }
- ++start;
- }
- return total;
- }
-
- public static int countNewlines(String src, int start, int end) {
- return countNewlines(src.toCharArray(), start, end);
- }
-
- /**
- * Replaces double-quotes, backslashes, and newlines in native JS code with
- * their appropriate escaped form (so they can be encoded in a java string).
- */
- public static String escapedJavaScriptForStringLiteral(String js) {
- StringBuilder sb = new StringBuilder(js);
- for (int i = 0; i < sb.length(); ++i) {
- char c = sb.charAt(i);
- switch (c) {
- case '\"':
- case '\\':
- sb.insert(i, '\\');
- ++i;
- break;
- case '\r':
- sb.setCharAt(i, 'r');
- sb.insert(i, '\\');
- ++i;
- break;
- case '\n':
- sb.setCharAt(i, 'n');
- sb.insert(i, '\\');
- ++i;
- break;
- }
- }
- return sb.toString();
- }
-
- public static Interval findJsniSource(JMethod method)
- throws UnableToCompleteException {
- assert (method.isNative());
- int bodyStart = method.getBodyStart();
- int bodyEnd = method.getBodyEnd();
- int bodyLen = bodyEnd - bodyStart + 1;
- char[] source = method.getEnclosingType().getCompilationUnit().getSource();
- String js = String.valueOf(source, bodyStart, bodyLen);
-
- int jsniStart = js.indexOf(JSNI_BLOCK_START);
- if (jsniStart == -1) {
+ public static String getJavaScriptForHostedMode(TreeLogger logger,
+ JsniMethod jsniMethod) {
+ /*
+ * Surround the original JS body statements with a try/catch so that we can
+ * map JavaScript exceptions back into Java. Note that the method body
+ * itself will print curly braces, so we don't need them around the
+ * try/catch.
+ */
+ String jsTry = "try ";
+ String jsCatch = " catch (e) {\n __static[\"@" + Jsni.JAVASCRIPTHOST_NAME
+ + "::exceptionCaught(Ljava/lang/Object;)\"](e);\n" + "}\n";
+ JsFunction func = jsniMethod.function(logger);
+ if (func == null) {
return null;
}
-
- int jsniEnd = js.indexOf(JSNI_BLOCK_END, jsniStart);
- if (jsniEnd == -1) {
- // Suspicious, but maybe this is just a weird comment, so let it slide.
- //
- return null;
- }
-
- int srcStart = bodyStart + jsniStart + JSNI_BLOCK_START.length();
- int srcEnd = bodyStart + jsniEnd;
- return new Interval(srcStart, srcEnd);
+ return jsTry + generateJavaScriptForHostedMode(func.getBody()) + jsCatch;
}
/**
* Returns a string representing the source output of the JsNode, where all
* JSNI idents have been replaced with legal JavaScript for hosted mode.
*/
- public static String generateJavaScriptForHostedMode(JsNode<?> node) {
+ private static String generateJavaScriptForHostedMode(JsNode<?> node) {
DefaultTextOutput out = new DefaultTextOutput(false);
JsSourceGenWithJsniIdentFixup vi = new JsSourceGenWithJsniIdentFixup(out);
vi.accept(node);
return out.toString();
}
- /**
- * Gets a unique name for this method and its signature (this is used to
- * determine whether one method overrides another).
- */
- public static String getJsniSignature(JMethod method) {
- return method.getEnclosingType().getQualifiedSourceName() + "::"
- + getMemberSignature(method);
- }
-
- /**
- * Gets a unique name for this method and its signature (this is used to
- * determine whether one method overrides another).
- */
- public static String getMemberSignature(JMethod method) {
- String name = method.getName();
- StringBuilder sb = new StringBuilder();
- sb.append(name);
- sb.append("(");
- JParameter[] params = method.getParameters();
- for (int i = 0; i < params.length; ++i) {
- JParameter param = params[i];
- String typeSig = param.getType().getJNISignature();
- sb.append(typeSig);
- }
- sb.append(")");
- String result = sb.toString();
- return result;
- }
-
- /**
- * In other words, it can have <code>return</code> statements.
- */
- public static JsBlock parseAsFunctionBody(TreeLogger logger, String js,
- String location, int startLine) throws UnableToCompleteException {
- // Wrap it in fake function and parse it.
- js = "function(){ " + js + " }";
-
- JsParser jsParser = new JsParser();
- JsProgram jsPgm = new JsProgram();
- StringReader r = new StringReader(js);
-
- try {
- List<JsStatement> stmts = jsParser.parse(jsPgm.getScope(), r, startLine);
-
- // Rip the body out of the parsed function and attach the JavaScript
- // AST to the method.
- //
- JsFunction fn = (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression();
- return fn.getBody();
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Error reading JavaScript source", e);
- throw new UnableToCompleteException();
- } catch (JsParserException e) {
- SourceDetail dtl = e.getSourceDetail();
- if (dtl != null) {
- StringBuilder sb = new StringBuilder();
- sb.append(location);
- sb.append("(");
- sb.append(dtl.getLine());
- sb.append(", ");
- sb.append(dtl.getLineOffset());
- sb.append("): ");
- sb.append(e.getMessage());
- logger.log(TreeLogger.ERROR, sb.toString(), e);
- throw new UnableToCompleteException();
- } else {
- logger.log(TreeLogger.ERROR, "Error parsing JSNI source", e);
- throw new UnableToCompleteException();
- }
- }
- }
-
}
diff --git a/dev/core/src/com/google/gwt/dev/util/Util.java b/dev/core/src/com/google/gwt/dev/util/Util.java
index 16edda6..237a3c3 100644
--- a/dev/core/src/com/google/gwt/dev/util/Util.java
+++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -30,6 +30,7 @@
import java.io.BufferedReader;
import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
@@ -173,23 +174,16 @@
}
/**
- * Copies an input stream out to a file. Closes the input steam and output
- * stream.
+ * Copies an input stream out to an output stream. Closes the input steam and
+ * output stream.
*/
public static void copy(TreeLogger logger, InputStream is, OutputStream os)
throws UnableToCompleteException {
try {
- byte[] buf = new byte[8 * 1024];
- int i = 0;
- while ((i = is.read(buf)) != -1) {
- os.write(buf, 0, i);
- }
+ copy(is, os);
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "Error during copy", e);
throw new UnableToCompleteException();
- } finally {
- Utility.close(is);
- Utility.close(os);
}
}
@@ -540,16 +534,14 @@
* Give the developer a chance to see the in-memory source that failed.
*/
public static void maybeDumpSource(TreeLogger logger, String location,
- char[] source, String typeName) {
+ String source, String typeName) {
if (isCompilationUnitOnDisk(location)) {
// Don't write another copy.
return;
}
- TreeLogger branch = logger.branch(TreeLogger.ERROR,
- "Compilation problem due to '" + location + "'", null);
- if (!branch.isLoggable(TreeLogger.INFO)) {
+ if (!logger.isLoggable(TreeLogger.INFO)) {
// Don't bother dumping source if they can't see the related message.
return;
}
@@ -558,16 +550,14 @@
Throwable caught = null;
try {
tmpSrc = File.createTempFile(typeName, ".java");
- writeCharsAsFile(logger, tmpSrc, source);
+ writeStringAsFile(tmpSrc, source);
String dumpPath = tmpSrc.getAbsolutePath();
- branch.log(TreeLogger.INFO, "See snapshot: " + dumpPath, null);
+ logger.log(TreeLogger.INFO, "See snapshot: " + dumpPath, null);
return;
} catch (IOException e) {
caught = e;
- } catch (UnableToCompleteException e) {
- caught = e;
}
- branch.log(TreeLogger.INFO, "Unable to dump source to disk", caught);
+ logger.log(TreeLogger.INFO, "Unable to dump source to disk", caught);
}
public static byte[] readFileAsBytes(File file) {
@@ -623,6 +613,22 @@
}
/**
+ * Reads an entire input stream as String. Closes the input stream.
+ */
+ public static String readStreamAsString(InputStream in) {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ copy(in, out);
+ return out.toString(DEFAULT_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(
+ "The JVM does not support the compiler's default encoding.", e);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
* @return null if the file could not be read
*/
public static byte[] readURLAsBytes(URL url) {
@@ -830,6 +836,14 @@
}
/**
+ * Returns a String representing the character content of the bytes; the bytes
+ * must be encoded using the compiler's default encoding.
+ */
+ public static String toString(byte[] bytes) {
+ return toString(bytes, DEFAULT_ENCODING);
+ }
+
+ /**
* Creates a string array from the contents of a collection.
*/
public static String[] toStringArray(Collection<String> coll) {
@@ -1018,6 +1032,19 @@
return true;
}
+ private static void copy(InputStream is, OutputStream os) throws IOException {
+ try {
+ byte[] buf = new byte[8 * 1024];
+ int i;
+ while ((i = is.read(buf)) != -1) {
+ os.write(buf, 0, i);
+ }
+ } finally {
+ Utility.close(is);
+ Utility.close(os);
+ }
+ }
+
/**
* Reads the specified number of bytes from the {@link InputStream}.
*
diff --git a/dev/core/src/com/google/gwt/util/tools/Utility.java b/dev/core/src/com/google/gwt/util/tools/Utility.java
index cf07319..dcc60b6 100644
--- a/dev/core/src/com/google/gwt/util/tools/Utility.java
+++ b/dev/core/src/com/google/gwt/util/tools/Utility.java
@@ -201,7 +201,7 @@
*/
public static String getFileFromClassPath(String partialPath)
throws IOException {
- InputStream in = Utility.class.getClassLoader().getResourceAsStream(
+ InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(
partialPath);
try {
if (in == null) {
@@ -279,7 +279,8 @@
if (override == null) {
String partialPath = Utility.class.getName().replace('.', '/').concat(
".class");
- URL url = Utility.class.getClassLoader().getResource(partialPath);
+ URL url = Thread.currentThread().getContextClassLoader().getResource(
+ partialPath);
if (url != null && "jar".equals(url.getProtocol())) {
String path = url.toString();
String jarPath = path.substring(path.indexOf("file:"),
diff --git a/dev/core/super/com/google/gwt/core/client/GWTBridge.java b/dev/core/super/com/google/gwt/core/client/GWTBridge.java
new file mode 100644
index 0000000..005bece
--- /dev/null
+++ b/dev/core/super/com/google/gwt/core/client/GWTBridge.java
@@ -0,0 +1,29 @@
+/*
+ * 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.core.client;
+
+/**
+ * When running in hosted mode, acts as a bridge from {@link GWT} into the
+ * hosted mode environment.
+ */
+public abstract class GWTBridge {
+
+ public abstract <T> T create(Class<?> classLiteral);
+
+ public abstract String getVersion();
+
+ public abstract void log(String message, Throwable e);
+}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java
index 90b5b94..6966b56 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JArrayTypeTest.java
@@ -17,7 +17,6 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.test.CA;
import com.google.gwt.core.ext.typeinfo.test.CB;
import com.google.gwt.core.ext.typeinfo.test.MyCustomList;
import com.google.gwt.core.ext.typeinfo.test.MyList;
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java
index 462da59..7d385fc 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JClassTypeTest.java
@@ -17,19 +17,10 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.jdt.StaticCompilationUnitProvider;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
-import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-
/**
* Tests related to JClassType. See individual test methods to details.
*/
@@ -43,7 +34,6 @@
}
public void testGetOverridableMethods() throws TypeOracleException {
- TreeLogger logger = TreeLogger.NULL;
TypeOracle typeOracle = moduleContext.getOracle();
// TypeOracle typeOracle = buildOracleFromTestPackage(logger);
@@ -223,34 +213,6 @@
}
}
- private void addCompilationUnitsInPath(TypeOracleBuilder builder,
- File sourcePathEntry, String pkgName) throws UnableToCompleteException,
- MalformedURLException {
- File pkgPath = new File(sourcePathEntry, pkgName.replace('.', '/'));
- File[] files = pkgPath.listFiles();
- if (files == null) {
- // No files found.
- return;
- }
-
- for (int i = 0; i < files.length; i++) {
- File file = files[i];
- if (file.isFile()) {
- // If it's a source file, slurp it in.
- if (file.getName().endsWith(".java")) {
- URL location = file.toURL();
- CompilationUnitProvider cup = new URLCompilationUnitProvider(
- location, pkgName);
- builder.addCompilationUnit(cup);
- }
- } else {
- // Recurse into subpackages.
- addCompilationUnitsInPath(builder, sourcePathEntry, pkgName
- + file.getName());
- }
- }
- }
-
private void assertMethodNotOverridable(TypeOracle typeOracle,
String expectedTypeName, String searchTypeName, String methodName,
String[] paramTypeNames) throws TypeOracleException {
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTestBase.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTestBase.java
index d00e716..2c3e989 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTestBase.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JDelegatingClassTypeTestBase.java
@@ -398,17 +398,6 @@
/**
* Test method for
- * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getCompilationUnit()}.
- */
- public void testGetCompilationUnit() throws NotFoundException {
- JDelegatingClassType testType = getTestType();
- JClassType baseType = testType.getBaseType();
-
- assertEquals(testType.getCompilationUnit(), baseType.getCompilationUnit());
- }
-
- /**
- * Test method for
* {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getConstructor(com.google.gwt.core.ext.typeinfo.JType[])}.
*/
public void testGetConstructor() throws NotFoundException {
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java
index 7ec4612..f10d243 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/JEnumTypeTest.java
@@ -18,8 +18,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.test.MyEnum;
-import com.google.gwt.dev.cfg.ModuleDef;
-import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
@@ -27,18 +26,18 @@
* Tests for {@link JEnumType}.
*/
public class JEnumTypeTest extends TestCase {
- private final TreeLogger logger = TreeLogger.NULL;
- private ModuleDef moduleDef;
+ private final boolean logToConsole = false;
- private final TypeOracle typeOracle;
+ private final ModuleContext moduleContext = new ModuleContext(logToConsole
+ ? new PrintWriterTreeLogger() : TreeLogger.NULL,
+ "com.google.gwt.core.ext.typeinfo.TypeOracleTest");
- public JEnumTypeTest() throws UnableToCompleteException, NotFoundException {
- moduleDef = ModuleDefLoader.loadFromClassPath(logger,
- "com.google.gwt.core.ext.typeinfo.TypeOracleTest");
- typeOracle = moduleDef.getTypeOracle(logger);
+ public JEnumTypeTest() throws UnableToCompleteException {
}
+ private final TypeOracle typeOracle = moduleContext.getOracle();
+
/**
* Test method for
* {@link com.google.gwt.core.ext.typeinfo.JEnumType#getEnumConstants()}.
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java
index acb8b2f..51ac681 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/ModuleContext.java
@@ -21,7 +21,7 @@
import com.google.gwt.dev.cfg.ModuleDefLoader;
/**
- * Helper for loading modules from the classpath.
+ * Helper for loading modules from the classpath.
*/
class ModuleContext {
private final TypeOracle oracle;
@@ -32,12 +32,8 @@
moduleDef = ModuleDefLoader.loadFromClassPath(logger, moduleName);
oracle = moduleDef.getTypeOracle(logger);
}
-
+
public TypeOracle getOracle() {
return oracle;
}
-
- public ModuleDef getModule() {
- return moduleDef;
- }
}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
index f9b6f16..a6ddb67 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
@@ -24,8 +24,7 @@
import com.google.gwt.core.ext.typeinfo.test.PrimitivesAnnotatedClass;
import com.google.gwt.core.ext.typeinfo.test.SourceRetentionAnnotation;
import com.google.gwt.core.ext.typeinfo.test.TestAnnotation;
-import com.google.gwt.dev.cfg.ModuleDef;
-import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
@@ -89,15 +88,14 @@
testAnnotation.emptyArray().length);
}
- private final TreeLogger logger = TreeLogger.NULL;
- private ModuleDef moduleDef;
+ private final boolean logToConsole = false;
+ private final ModuleContext moduleContext = new ModuleContext(logToConsole
+ ? new PrintWriterTreeLogger() : TreeLogger.NULL,
+ "com.google.gwt.core.ext.typeinfo.TypeOracleTest");
- private final TypeOracle typeOracle;
+ private final TypeOracle typeOracle = moduleContext.getOracle();
public TypeOracleAnnotationSupportTest() throws UnableToCompleteException {
- moduleDef = ModuleDefLoader.loadFromClassPath(logger,
- "com.google.gwt.core.ext.typeinfo.TypeOracleTest");
- typeOracle = moduleDef.getTypeOracle(logger);
}
/**
diff --git a/dev/core/test/com/google/gwt/dev/jdt/BinaryTypeReferenceRestrictionsCheckerTest.java b/dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java
similarity index 96%
rename from dev/core/test/com/google/gwt/dev/jdt/BinaryTypeReferenceRestrictionsCheckerTest.java
rename to dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java
index 5d60966..16b7e90 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/BinaryTypeReferenceRestrictionsCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java
@@ -13,9 +13,9 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
-import com.google.gwt.dev.jdt.BinaryTypeReferenceRestrictionsChecker.BinaryTypeReferenceSite;
+import com.google.gwt.dev.javac.BinaryTypeReferenceRestrictionsChecker.BinaryTypeReferenceSite;
import junit.framework.TestCase;
@@ -159,7 +159,7 @@
* annotation and in a local variable declaration. It then checks that the we
* find all of these locations except for the one used in an annotation.
*/
- public void testFindInvalidBinaryTypeReferenceSites() {
+ public void testFindAllBinaryTypeReferenceSites() {
CompilationResult compilationResult = new CompilationResult(
"TestCompilationUnit.java".toCharArray(), 0, 0, 0);
CompilationUnitDeclaration cud = new CompilationUnitDeclaration(null,
@@ -201,7 +201,7 @@
typeDeclaration.superclass, methodDeclaration.returnType,
localDeclaration.type};
- List<BinaryTypeReferenceSite> binaryTypeReferenceSites = BinaryTypeReferenceRestrictionsChecker.findInvalidBinaryTypeReferenceSites(cud);
+ List<BinaryTypeReferenceSite> binaryTypeReferenceSites = BinaryTypeReferenceRestrictionsChecker.findAllBinaryTypeReferenceSites(cud);
assertEquals(expectedExpressions.length, binaryTypeReferenceSites.size());
for (int i = 0; i < binaryTypeReferenceSites.size(); ++i) {
BinaryTypeReferenceSite binaryTypeReferenceSite = binaryTypeReferenceSites.get(i);
diff --git a/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
new file mode 100644
index 0000000..23cdb49
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.UnableToCompleteException;
+import com.google.gwt.dev.javac.CompilationUnit.State;
+import com.google.gwt.dev.javac.impl.MockJavaSourceFile;
+import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
+import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * Tests {@link CompilationState}.
+ */
+public class CompilationStateTest extends TestCase {
+
+ private MockJavaSourceOracle oracle = new MockJavaSourceOracle(
+ JavaSourceCodeBase.getStandardResources());
+
+ private CompilationState state = new CompilationState(oracle);
+
+ public void testAddGeneratedCompilationUnit() {
+ validateCompilationState();
+
+ // Add a unit and ensure it shows up.
+ addGeneratedUnit(JavaSourceCodeBase.FOO);
+ validateCompilationState(JavaSourceCodeBase.FOO.getTypeName());
+
+ // Ensure it disappears after a refresh.
+ state.refresh();
+ validateCompilationState();
+ }
+
+ static void assertUnitsChecked(Collection<CompilationUnit> units) {
+ for (CompilationUnit unit : units) {
+ assertSame(State.CHECKED, unit.getState());
+ assertNull(unit.getErrors());
+ assertTrue(unit.getCompiledClasses().size() > 0);
+ }
+ }
+
+ public void testCompile() throws UnableToCompleteException {
+ validateUncompiled();
+ state.compile(createTreeLogger());
+ assertUnitsChecked(state.getCompilationUnits());
+ }
+
+ public void testCompileError() throws UnableToCompleteException {
+ oracle.add(JavaSourceCodeBase.BAR);
+ state.refresh();
+ validateUncompiled();
+ state.compile(createTreeLogger());
+
+ CompilationUnit badUnit = state.getCompilationUnitMap().get(
+ JavaSourceCodeBase.BAR.getTypeName());
+ assertSame(State.ERROR, badUnit.getState());
+
+ Set<CompilationUnit> goodUnits = new HashSet<CompilationUnit>(
+ state.getCompilationUnits());
+ goodUnits.remove(badUnit);
+ assertUnitsChecked(goodUnits);
+ }
+
+ public void testCompileWithGeneratedUnits() throws UnableToCompleteException {
+ validateUncompiled();
+ state.compile(createTreeLogger());
+ assertUnitsChecked(state.getCompilationUnits());
+ addGeneratedUnit(JavaSourceCodeBase.FOO);
+ state.compile(createTreeLogger());
+ assertUnitsChecked(state.getCompilationUnits());
+ }
+
+ public void testCompileWithGeneratedUnitsError()
+ throws UnableToCompleteException {
+ validateUncompiled();
+ state.compile(createTreeLogger());
+ assertUnitsChecked(state.getCompilationUnits());
+ addGeneratedUnit(JavaSourceCodeBase.BAR);
+ state.compile(createTreeLogger());
+
+ CompilationUnit badUnit = state.getCompilationUnitMap().get(
+ JavaSourceCodeBase.BAR.getTypeName());
+ assertSame(State.ERROR, badUnit.getState());
+
+ Set<CompilationUnit> goodUnits = new HashSet<CompilationUnit>(
+ state.getCompilationUnits());
+ goodUnits.remove(badUnit);
+ assertUnitsChecked(goodUnits);
+ }
+
+ public void testSourceOracleAdd() {
+ validateCompilationState();
+
+ int size = state.getCompilationUnits().size();
+ oracle.add(JavaSourceCodeBase.FOO);
+ state.refresh();
+ assertEquals(size + 1, state.getCompilationUnits().size());
+ validateCompilationState();
+ }
+
+ public void testSourceOracleBasic() {
+ validateCompilationState();
+ }
+
+ public void testSourceOracleEmpty() {
+ oracle = new MockJavaSourceOracle();
+ state = new CompilationState(oracle);
+ validateCompilationState();
+ }
+
+ public void testSourceOracleRemove() {
+ validateCompilationState();
+
+ int size = state.getCompilationUnits().size();
+ oracle.remove(JavaSourceCodeBase.OBJECT.getTypeName());
+ state.refresh();
+ assertEquals(size - 1, state.getCompilationUnits().size());
+ validateCompilationState();
+ }
+
+ public void testSourceOracleReplace() {
+ validateCompilationState();
+
+ int size = state.getCompilationUnits().size();
+ oracle.replace(new MockJavaSourceFile(JavaSourceCodeBase.OBJECT));
+ state.refresh();
+ assertEquals(size, state.getCompilationUnits().size());
+ validateCompilationState();
+ }
+
+ public void testSourceOracleReplaceWithSame() {
+ validateCompilationState();
+
+ int size = state.getCompilationUnits().size();
+ oracle.replace(JavaSourceCodeBase.OBJECT);
+ state.refresh();
+ assertEquals(size, state.getCompilationUnits().size());
+ validateCompilationState();
+ }
+
+ private void addGeneratedUnit(JavaSourceFile sourceFile) {
+ state.addGeneratedCompilationUnit(new SourceFileCompilationUnit(sourceFile) {
+ @Override
+ public boolean isGenerated() {
+ return true;
+ }
+ });
+ }
+
+ private void validateCompilationState(String... generatedTypeNames) {
+ // Save off the reflected collections.
+ Map<String, CompilationUnit> unitMap = state.getCompilationUnitMap();
+ Set<CompilationUnit> units = state.getCompilationUnits();
+
+ // Validate that the collections are consistent with each other.
+ assertEquals(new HashSet<CompilationUnit>(unitMap.values()), units);
+
+ // Save off a mutable copy of the source map and generated types to compare.
+ Map<String, JavaSourceFile> sourceMap = new HashMap<String, JavaSourceFile>(
+ oracle.getSourceMap());
+ Set<String> generatedTypes = new HashSet<String>(
+ Arrays.asList(generatedTypeNames));
+ assertEquals(sourceMap.size() + generatedTypes.size(), units.size());
+ for (Entry<String, CompilationUnit> entry : unitMap.entrySet()) {
+ // Validate source file internally consistent.
+ String className = entry.getKey();
+ CompilationUnit unit = entry.getValue();
+ assertEquals(className, unit.getTypeName());
+
+ // Find the matching resource (and remove it).
+ if (unit.isGenerated()) {
+ assertTrue(generatedTypes.contains(className));
+ assertNotNull(generatedTypes.remove(className));
+ } else {
+ assertTrue(sourceMap.containsKey(className));
+ // TODO: Validate the source file matches the resource.
+ assertNotNull(sourceMap.remove(className));
+ }
+ }
+ // The mutable sets should be empty now.
+ assertEquals(0, sourceMap.size());
+ assertEquals(0, generatedTypes.size());
+ }
+
+ private void validateUncompiled() {
+ for (CompilationUnit unit : state.getCompilationUnits()) {
+ assertNull(unit.getJdtCud());
+ }
+ }
+
+ /**
+ * Tweak this if you want to see the log output.
+ */
+ private TreeLogger createTreeLogger() {
+ boolean reallyLog = false;
+ if (reallyLog) {
+ AbstractTreeLogger logger = new PrintWriterTreeLogger();
+ logger.setMaxDetail(TreeLogger.ALL);
+ return logger;
+ } else {
+ return TreeLogger.NULL;
+ }
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/jdt/GWTProblemTest.java b/dev/core/test/com/google/gwt/dev/javac/GWTProblemTest.java
similarity index 97%
rename from dev/core/test/com/google/gwt/dev/jdt/GWTProblemTest.java
rename to dev/core/test/com/google/gwt/dev/javac/GWTProblemTest.java
index 301bcba..865a490 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/GWTProblemTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/GWTProblemTest.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.ext.TreeLogger.HelpInfo;
diff --git a/dev/core/test/com/google/gwt/dev/jdt/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
similarity index 90%
rename from dev/core/test/com/google/gwt/dev/jdt/JSORestrictionsTest.java
rename to dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
index ac2d451..ce0305d 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/JSORestrictionsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
@@ -42,7 +42,7 @@
buggyCode.append(" int myStsate = 3;\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 4: "
+ shouldGenerateError(buggyCode, "Line 4: "
+ JSORestrictionsChecker.ERR_INSTANCE_FIELD);
}
@@ -53,7 +53,7 @@
buggyCode.append(" protected Buggy(int howBuggy) { }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 3: "
+ shouldGenerateError(buggyCode, "Line 3: "
+ JSORestrictionsChecker.ERR_CONSTRUCTOR_WITH_PARAMETERS);
}
@@ -67,7 +67,7 @@
buggyCode.append(" MyJSO makeOne() { return new MyJSO(); }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 6: "
+ shouldGenerateError(buggyCode, "Line 6: "
+ JSORestrictionsChecker.ERR_NEW_JSO);
}
@@ -78,7 +78,7 @@
buggyCode.append("}\n");
// The public constructor is implicit.
- shouldGenerateError(buggyCode, "Line 2: "
+ shouldGenerateError(buggyCode, "Line 2: "
+ JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
}
@@ -95,7 +95,7 @@
buggyCode.append(" }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 6: "
+ shouldGenerateError(buggyCode, "Line 6: "
+ JSORestrictionsChecker.errInterfaceWithMethods("Buggy.Squeaks"));
}
@@ -106,7 +106,7 @@
buggyCode.append(" protected Buggy() { while(true) { } }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 3: "
+ shouldGenerateError(buggyCode, "Line 3: "
+ JSORestrictionsChecker.ERR_NONEMPTY_CONSTRUCTOR);
}
@@ -118,7 +118,7 @@
buggyCode.append(" protected Buggy() { }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 3: "
+ shouldGenerateError(buggyCode, "Line 3: "
+ JSORestrictionsChecker.ERR_INSTANCE_METHOD_NONFINAL);
}
@@ -129,7 +129,7 @@
buggyCode.append(" Buggy() { }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 3: "
+ shouldGenerateError(buggyCode, "Line 3: "
+ JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
}
@@ -142,7 +142,7 @@
buggyCode.append(" }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 3: "
+ shouldGenerateError(buggyCode, "Line 3: "
+ JSORestrictionsChecker.ERR_IS_NONSTATIC_NESTED);
}
@@ -154,7 +154,7 @@
buggyCode.append(" public final Object clone() { return this; }\n");
buggyCode.append("}\n");
- shouldGenerateError(buggyCode, "Line 4: "
+ shouldGenerateError(buggyCode, "Line 4: "
+ JSORestrictionsChecker.ERR_OVERRIDDEN_METHOD);
}
@@ -179,13 +179,13 @@
UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
builder.setLowestLogLevel(TreeLogger.ERROR);
if (expectedError != null) {
- builder.expectError("Errors in \'transient source for Buggy\'", null);
+ builder.expectError("Errors in \'/mock/Buggy\'", null);
builder.expectError(expectedError, null);
- builder.expectError(
- "Compilation problem due to \'transient source for Buggy\'", null);
}
UnitTestTreeLogger logger = builder.createLogger();
- TypeOracleTestingUtils.buildTypeOracleForCode("Buggy", buggyCode, logger);
+ CompilationUnit buggyCup = new MockCompilationUnit("Buggy",
+ buggyCode.toString());
+ TypeOracleTestingUtils.buildStandardTypeOracleWith(logger, buggyCup);
logger.assertCorrectLogEntries();
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/JavaCompilationSuite.java b/dev/core/test/com/google/gwt/dev/javac/JavaCompilationSuite.java
new file mode 100644
index 0000000..1505a36
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/JavaCompilationSuite.java
@@ -0,0 +1,43 @@
+/*
+ * 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.dev.javac.impl.JavaSourceOracleImplTest;
+import com.google.gwt.dev.javac.impl.JdtBehaviorTest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Tests script and resource injection.
+ */
+public class JavaCompilationSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite(JavaCompilationSuite.class.getName());
+
+ suite.addTestSuite(BinaryTypeReferenceRestrictionsCheckerTest.class);
+ suite.addTestSuite(CompilationStateTest.class);
+ suite.addTestSuite(GWTProblemTest.class);
+ suite.addTestSuite(JdtBehaviorTest.class);
+ suite.addTestSuite(JdtCompilerTest.class);
+ suite.addTestSuite(JSORestrictionsTest.class);
+ suite.addTestSuite(JavaSourceOracleImplTest.class);
+ suite.addTestSuite(LongFromJSNITest.class);
+ suite.addTestSuite(TypeOracleMediatorTest.class);
+
+ return suite;
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/JavaSourceCodeBase.java b/dev/core/test/com/google/gwt/dev/javac/JavaSourceCodeBase.java
new file mode 100644
index 0000000..d3679d9
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/JavaSourceCodeBase.java
@@ -0,0 +1,52 @@
+/*
+ * 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.dev.javac.impl.JavaResourceBase;
+import com.google.gwt.dev.javac.impl.MockJavaSourceFile;
+
+/**
+ * Contains standard Java source files for testing.
+ */
+public class JavaSourceCodeBase {
+
+ public static final MockJavaSourceFile ANNOTATION = new MockJavaSourceFile(
+ JavaResourceBase.ANNOTATION);
+ public static final MockJavaSourceFile BAR = new MockJavaSourceFile(
+ JavaResourceBase.BAR);
+ public static final MockJavaSourceFile CLASS = new MockJavaSourceFile(
+ JavaResourceBase.CLASS);
+ public static final MockJavaSourceFile FOO = new MockJavaSourceFile(
+ JavaResourceBase.FOO);
+ public static final MockJavaSourceFile JAVASCRIPTOBJECT = new MockJavaSourceFile(
+ JavaResourceBase.JAVASCRIPTOBJECT);
+ public static final MockJavaSourceFile MAP = new MockJavaSourceFile(
+ JavaResourceBase.MAP);
+ public static final MockJavaSourceFile OBJECT = new MockJavaSourceFile(
+ JavaResourceBase.OBJECT);
+ public static final MockJavaSourceFile SERIALIZABLE = new MockJavaSourceFile(
+ JavaResourceBase.SERIALIZABLE);
+ public static final MockJavaSourceFile STRING = new MockJavaSourceFile(
+ JavaResourceBase.STRING);
+ public static final MockJavaSourceFile SUPPRESS_WARNINGS = new MockJavaSourceFile(
+ JavaResourceBase.SUPPRESS_WARNINGS);
+
+ public static MockJavaSourceFile[] getStandardResources() {
+ return new MockJavaSourceFile[] {
+ ANNOTATION, CLASS, JAVASCRIPTOBJECT, MAP, OBJECT, SERIALIZABLE, STRING,
+ SUPPRESS_WARNINGS};
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/JdtCompilerTest.java b/dev/core/test/com/google/gwt/dev/javac/JdtCompilerTest.java
new file mode 100644
index 0000000..539abe7
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/JdtCompilerTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.dev.javac.impl.SourceFileCompilationUnit;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Test class for {@link JdtCompiler}.
+ */
+public class JdtCompilerTest extends TestCase {
+
+ static void assertUnitsCompiled(Collection<CompilationUnit> units) {
+ for (CompilationUnit unit : units) {
+ CompilationUnitDeclaration cud = unit.getJdtCud();
+ assertFalse(cud.hasErrors());
+ CompilationResult result = cud.compilationResult();
+ assertFalse(result.hasProblems());
+ assertTrue(result.getClassFiles().length > 0);
+ }
+ }
+
+ static void assertUnitHasErrors(CompilationUnit unit, int numErrors) {
+ CompilationUnitDeclaration cud = unit.getJdtCud();
+ CompilationResult result = cud.compilationResult();
+ assertTrue(result.hasErrors());
+ assertEquals(numErrors, result.getErrors().length);
+ assertTrue(result.getClassFiles().length > 0);
+ }
+
+ public void testCompile() {
+ List<CompilationUnit> units = new ArrayList<CompilationUnit>();
+ addAll(units, JavaSourceCodeBase.getStandardResources());
+ addAll(units, JavaSourceCodeBase.FOO, JavaSourceCodeBase.BAR);
+ JdtCompiler.compile(units);
+ assertUnitsCompiled(units);
+ }
+
+ public void testCompileError() {
+ List<CompilationUnit> units = new ArrayList<CompilationUnit>();
+ addAll(units, JavaSourceCodeBase.getStandardResources());
+ addAll(units, JavaSourceCodeBase.BAR);
+ JdtCompiler.compile(units);
+ assertUnitsCompiled(units.subList(0, units.size() - 1));
+ assertUnitHasErrors(units.get(units.size() - 1), 1);
+ }
+
+ public void testCompileIncremental() {
+ List<CompilationUnit> units = new ArrayList<CompilationUnit>();
+ addAll(units, JavaSourceCodeBase.getStandardResources());
+ JdtCompiler.compile(units);
+ assertUnitsCompiled(units);
+ addAll(units, JavaSourceCodeBase.FOO, JavaSourceCodeBase.BAR);
+ JdtCompiler.compile(units);
+ assertUnitsCompiled(units);
+ }
+
+ private void addAll(Collection<CompilationUnit> units,
+ JavaSourceFile... sourceFiles) {
+ for (JavaSourceFile sourceFile : sourceFiles) {
+ units.add(new SourceFileCompilationUnit(sourceFile));
+ }
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java b/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
similarity index 86%
rename from dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
rename to dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
index 4bb445c..0269e7b 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
@@ -13,32 +13,23 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.util.UnitTestTreeLogger;
import junit.framework.TestCase;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Test access to longs from JSNI.
*/
public class LongFromJSNITest extends TestCase {
- public void testBogusRef() throws UnableToCompleteException {
- StringBuffer code = new StringBuffer();
- code.append("class Buggy { \n");
- code.append("volatile long x = -1; \n");
- code.append("native void jsniMeth() /*-{ \n");
- code.append(" // @\\bogus refs should just be skipped \n");
- code.append(" $wnd.alert(\"x is: \"+this.@Buggy::x); }-*/; \n");
- code.append("} \n");
-
- shouldGenerateError(code, 3,
- "Referencing field 'Buggy.x': type 'long' is not safe to access in JSNI code");
- }
-
public void testCyclicReferences() throws UnableToCompleteException {
{
StringBuffer buggy = new StringBuffer();
@@ -204,19 +195,6 @@
"Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
}
- public void testRefInString() throws UnableToCompleteException {
- {
- StringBuffer code = new StringBuffer();
- code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
- code.append("class Buggy {\n");
- code.append(" void print(long x) { }\n");
- code.append(" native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
- code.append("}\n");
-
- shouldGenerateNoError(code);
- }
- }
-
public void testUnsafeAnnotation() throws UnableToCompleteException {
{
StringBuffer code = new StringBuffer();
@@ -231,6 +209,19 @@
}
}
+ public void testRefInString() throws UnableToCompleteException {
+ {
+ StringBuffer code = new StringBuffer();
+ code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
+ code.append("class Buggy {\n");
+ code.append(" void print(long x) { }\n");
+ code.append(" native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
+ code.append("}\n");
+
+ shouldGenerateNoError(code);
+ }
+ }
+
public void testViolator() throws UnableToCompleteException {
{
StringBuffer okay = new StringBuffer();
@@ -273,30 +264,26 @@
}
}
- private void addLongCheckingCups(TypeOracleBuilder builder)
- throws UnableToCompleteException {
- {
- StringBuilder code = new StringBuilder();
- code.append("package com.google.gwt.core.client;\n");
- code.append("public @interface UnsafeNativeLong {\n");
- code.append("}\n");
-
- TypeOracleTestingUtils.addCup(builder,
- "com.google.gwt.core.client.UnsafeNativeLong", code);
- }
+ private void addLongCheckingCups(Set<CompilationUnit> units) {
+ StringBuilder code = new StringBuilder();
+ code.append("package com.google.gwt.core.client;\n");
+ code.append("public @interface UnsafeNativeLong {\n");
+ code.append("}\n");
+ units.add(new MockCompilationUnit(
+ "com.google.gwt.core.client.UnsafeNativeLong", code.toString()));
}
private TypeOracle buildOracle(CharSequence buggyCode,
CharSequence extraCode, UnitTestTreeLogger logger)
throws UnableToCompleteException {
- TypeOracleBuilder builder = new TypeOracleBuilder();
- TypeOracleTestingUtils.addStandardCups(builder);
- addLongCheckingCups(builder);
- TypeOracleTestingUtils.addCup(builder, "Buggy", buggyCode);
+ Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+ addLongCheckingCups(units);
+ units.add(new MockCompilationUnit("Buggy", buggyCode.toString()));
if (extraCode != null) {
- TypeOracleTestingUtils.addCup(builder, "Extra", extraCode);
+ units.add(new MockCompilationUnit("Extra", extraCode.toString()));
}
- return builder.build(logger);
+ return TypeOracleTestingUtils.buildStandardTypeOracleWith(logger,
+ units.toArray(new CompilationUnit[units.size()]));
}
private void shouldGenerateError(CharSequence buggyCode,
@@ -305,11 +292,9 @@
UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder();
b.setLowestLogLevel(TreeLogger.ERROR);
if (message != null) {
- b.expect(TreeLogger.ERROR, "Errors in 'transient source for Buggy'", null);
- final String fullMessage = "Line " + line + ": " + message;
+ b.expect(TreeLogger.ERROR, "Errors in '/mock/Buggy'", null);
+ final String fullMessage = "Line " + line + ": " + message;
b.expect(TreeLogger.ERROR, fullMessage, null);
- b.expect(TreeLogger.ERROR,
- "Compilation problem due to 'transient source for Buggy'", null);
}
UnitTestTreeLogger logger = b.createLogger();
TypeOracle oracle = buildOracle(buggyCode, extraCode, logger);
diff --git a/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java b/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
new file mode 100644
index 0000000..9f07db9
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+public class MockCompilationUnit extends CompilationUnit {
+
+ private final String typeName;
+ private final String source;
+
+ public MockCompilationUnit(String typeName) {
+ this.typeName = typeName;
+ this.source = null;
+ }
+
+ public MockCompilationUnit(String typeName, String source) {
+ this.typeName = typeName;
+ this.source = source;
+ }
+
+ public String getDisplayLocation() {
+ return "/mock/" + getTypeName();
+ }
+
+ @Override
+ public String getSource() {
+ assert source != null;
+ return source;
+ }
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public boolean isGenerated() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/javac/MockJavaSourceOracle.java b/dev/core/test/com/google/gwt/dev/javac/MockJavaSourceOracle.java
new file mode 100644
index 0000000..bb77e8c
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/MockJavaSourceOracle.java
@@ -0,0 +1,92 @@
+/*
+ * 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.dev.javac.JavaSourceFile;
+import com.google.gwt.dev.javac.JavaSourceOracle;
+
+import junit.framework.Assert;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A simple {@link ResourceOracle} for testing.
+ */
+public class MockJavaSourceOracle implements JavaSourceOracle {
+
+ private Map<String, JavaSourceFile> exportedMap = Collections.emptyMap();
+ private Set<JavaSourceFile> exportedValues = Collections.emptySet();
+
+ public MockJavaSourceOracle(JavaSourceFile... sourceFiles) {
+ add(sourceFiles);
+ }
+
+ public Set<String> getClassNames() {
+ return exportedMap.keySet();
+ }
+
+ public Set<JavaSourceFile> getSourceFiles() {
+ return exportedValues;
+ }
+
+ public Map<String, JavaSourceFile> getSourceMap() {
+ return exportedMap;
+ }
+
+ void add(JavaSourceFile... sourceFiles) {
+ Map<String, JavaSourceFile> newMap = new HashMap<String, JavaSourceFile>(
+ exportedMap);
+ for (JavaSourceFile sourceFile : sourceFiles) {
+ String className = sourceFile.getTypeName();
+ Assert.assertFalse(newMap.containsKey(className));
+ newMap.put(className, sourceFile);
+ }
+ export(newMap);
+ }
+
+ void remove(String... classNames) {
+ Map<String, JavaSourceFile> newMap = new HashMap<String, JavaSourceFile>(
+ exportedMap);
+ for (String className : classNames) {
+ JavaSourceFile oldValue = newMap.remove(className);
+ Assert.assertNotNull(oldValue);
+ }
+ export(newMap);
+ }
+
+ void replace(JavaSourceFile... sourceFiles) {
+ Map<String, JavaSourceFile> newMap = new HashMap<String, JavaSourceFile>(
+ exportedMap);
+ for (JavaSourceFile sourceFile : sourceFiles) {
+ String className = sourceFile.getTypeName();
+ Assert.assertTrue(newMap.containsKey(className));
+ newMap.put(className, sourceFile);
+ }
+ export(newMap);
+ }
+
+ private void export(Map<String, JavaSourceFile> newMap) {
+ exportedMap = Collections.unmodifiableMap(newMap);
+ // Make a new hash set for constant lookup.
+ exportedValues = Collections.unmodifiableSet(new HashSet<JavaSourceFile>(
+ exportedMap.values()));
+ }
+
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/jdt/TypeOracleBuilderTest.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
similarity index 62%
rename from dev/core/test/com/google/gwt/dev/jdt/TypeOracleBuilderTest.java
rename to dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
index 02599d1..7218d07 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/TypeOracleBuilderTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
@@ -13,11 +13,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.dev.jdt;
+package com.google.gwt.dev.javac;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
@@ -27,114 +26,34 @@
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
+import com.google.gwt.dev.javac.CompilationUnit.State;
+import com.google.gwt.dev.javac.impl.Shared;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
-import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
-public class TypeOracleBuilderTest extends TestCase {
- private static abstract class TestCup implements CompilationUnitProvider {
- private final String packageName;
+public class TypeOracleMediatorTest extends TestCase {
- private final String[] typeNames;
-
- /**
- * Creates a new {@code TestCup} with several types. The first type in
- * {@code typeNames} is considered to be the main type.
- *
- * @param packageName the package for the types in this {@code TestCup}
- * @param typeNames the types for this {@code TestCup}. Must have at least
- * one type. The first type is considered to be the main type for
- * this {@code TestCup}.
- */
- public TestCup(String packageName, String... typeNames) {
- this.packageName = packageName;
- this.typeNames = typeNames;
- assert typeNames != null && typeNames.length > 0;
- for (int i = 0; i < typeNames.length; i++) {
- String typeName = typeNames[i];
- register(typeName, this);
+ private abstract class CheckedMockCompilationUnit extends MockCompilationUnit {
+ public CheckedMockCompilationUnit(String packageName,
+ String shortMainTypeName, String... shortTypeNames) {
+ super(Shared.makeTypeName(packageName, shortMainTypeName));
+ register(getTypeName(), this);
+ for (String shortTypeName : shortTypeNames) {
+ register(Shared.makeTypeName(packageName, shortTypeName), this);
}
}
+ @Override
+ public abstract String getSource();
+
public abstract void check(JClassType type) throws NotFoundException;
-
- public long getLastModified() throws UnableToCompleteException {
- return 0;
- }
-
- public String getLocation() {
- return "transient source for " + this.packageName + "."
- + this.typeNames[0];
- }
-
- public String getMainTypeName() {
- return typeNames[0];
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public String[] getTypeNames() {
- return typeNames;
- }
-
- public boolean isTransient() {
- return true;
- }
- }
-
- private static Map<String, TestCup> publicTypeNameToTestCupMap = new HashMap<String, TestCup>();
-
- /**
- * Creates a non-transient {@link CompilationUnitProvider} and
- * adds it the {@link TypeOracleBuilder}.
- *
- * @throws UnableToCompleteException
- */
- private static void addNonTransientCompilationUnitProvider(
- TypeOracleBuilder builder, String qualifiedTypeName, CharSequence code)
- throws UnableToCompleteException {
-
- final CompilationUnitProvider cup = TypeOracleTestingUtils.createCup(
- qualifiedTypeName, code);
-
- CompilationUnitProvider nonTransientCup = new CompilationUnitProvider() {
- public long getLastModified() throws UnableToCompleteException {
- return cup.getLastModified();
- }
-
- public String getLocation() {
- /*
- * Fake out TypeOracleBuilder so it does not look for a file at this
- * location.
- */
- return "http://" + cup.getLocation();
- }
-
- public String getMainTypeName() {
- return cup.getMainTypeName();
- }
-
- public String getPackageName() {
- return cup.getPackageName();
- }
-
- public char[] getSource() throws UnableToCompleteException {
- return cup.getSource();
- }
-
- public boolean isTransient() {
- return false;
- }
- };
-
- builder.addCompilationUnit(nonTransientCup);
}
private static void assertEqualArraysUnordered(Object[] expected,
@@ -152,34 +71,52 @@
}
}
- private static void check(JClassType classInfo) throws NotFoundException {
- final String qName = classInfo.getQualifiedSourceName();
- TestCup cup = publicTypeNameToTestCupMap.get(qName);
- assertNotNull(cup); // should've been declared during TestCup ctor
- cup.check(classInfo);
+ private static void assertIsAssignable(JClassType from, JClassType to) {
+ assertTrue("'" + from + "' should be assignable to '" + to + "'",
+ from.isAssignableTo(to));
+ assertTrue("'" + to + "' should be assignable from '" + from + "'",
+ to.isAssignableFrom(from));
}
- private static void register(String simpleTypeName, TestCup cup) {
- String qName = cup.getPackageName() + "." + simpleTypeName;
- publicTypeNameToTestCupMap.put(qName, cup);
+ private static void assertIsNotAssignable(JClassType from, JClassType to) {
+ assertFalse(from.isAssignableTo(to));
+ assertFalse(to.isAssignableFrom(from));
}
- protected TestCup CU_AfterAssimilate = new TestCup("test.assim",
- "AfterAssimilate") {
+ private static void recordAssignability(
+ Map<JClassType, Set<JClassType>> assignabilityMap, JClassType from,
+ JClassType to) {
+ Set<JClassType> set = assignabilityMap.get(from);
+ if (set == null) {
+ set = new HashSet<JClassType>();
+ assignabilityMap.put(from, set);
+ }
+ set.add(to);
+ }
+
+ /**
+ * Public so that this will be initialized before the CUs.
+ */
+ public final Map<String, CheckedMockCompilationUnit> publicTypeNameToTestCupMap = new HashMap<String, CheckedMockCompilationUnit>();
+
+ protected CheckedMockCompilationUnit CU_AfterAssimilate = new CheckedMockCompilationUnit(
+ "test.assim", "AfterAssimilate") {
public void check(JClassType type) {
- // Don't need to check the type itself.
+ assertEquals("test.assim.BeforeAssimilate",
+ type.getSuperclass().getQualifiedSourceName());
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test.assim;\n");
sb.append("class AfterAssimilate extends BeforeAssimilate { }");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_Assignable = new TestCup("test.sub", "Derived",
- "BaseInterface", "DerivedInterface", "Derived.Nested") {
+ protected CheckedMockCompilationUnit CU_Assignable = new CheckedMockCompilationUnit(
+ "test.sub", "Derived", "BaseInterface", "DerivedInterface",
+ "Derived.Nested") {
public void check(JClassType type) {
if ("Derived".equals(type.getSimpleSourceName()))
checkDerived(type);
@@ -187,7 +124,7 @@
checkNested(type);
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test.sub;\n");
sb.append("import test.Outer;");
@@ -196,7 +133,7 @@
sb.append("public class Derived extends Outer.Inner {\n");
sb.append(" public static class Nested extends Outer.Inner implements DerivedInterface { }\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
private void checkDerived(JClassType type) {
@@ -209,22 +146,23 @@
}
};
- protected TestCup CU_BeforeAssimilate = new TestCup("test.assim",
- "BeforeAssimilate") {
+ protected CheckedMockCompilationUnit CU_BeforeAssimilate = new CheckedMockCompilationUnit(
+ "test.assim", "BeforeAssimilate") {
public void check(JClassType type) {
- // Don't need to check the type itself.
+ assertEquals("test.assim.BeforeAssimilate", type.getQualifiedSourceName());
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test.assim;\n");
sb.append("class BeforeAssimilate { }");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_BindToTypeScope = new TestCup("test", "BindToTypeScope",
- "BindToTypeScope.Object", "BindToTypeScope.DerivedObject") {
+ protected CheckedMockCompilationUnit CU_BindToTypeScope = new CheckedMockCompilationUnit(
+ "test", "BindToTypeScope", "BindToTypeScope.Object",
+ "BindToTypeScope.DerivedObject") {
public void check(JClassType type) throws NotFoundException {
if ("BindToTypeScope".equals(type.getSimpleSourceName()))
@@ -249,14 +187,14 @@
assertEquals("test.BindToTypeScope.Object", type.getQualifiedSourceName());
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class BindToTypeScope {\n");
sb.append(" public static class Object { }\n");
sb.append(" public static class DerivedObject extends Object { }\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
private void checkDerivedObject(JClassType type) throws NotFoundException {
@@ -273,23 +211,25 @@
}
};
- protected TestCup CU_DeclaresInnerGenericType = new TestCup(
- "parameterized.type.build.dependency", "Class1") {
+ protected CheckedMockCompilationUnit CU_DeclaresInnerGenericType = new CheckedMockCompilationUnit(
+ "parameterized.type.build.dependency", "Class1", "Class1.Inner") {
@Override
public void check(JClassType type) throws NotFoundException {
+ assertNotNull(type.isGenericType());
}
- public char[] getSource() throws UnableToCompleteException {
+ public String getSource() {
StringBuilder sb = new StringBuilder();
sb.append("package parameterized.type.build.dependency;\n");
sb.append("public class Class1<T> {\n");
sb.append(" public interface Inner<T> {}\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_DefaultClass = new TestCup("test", "DefaultClass") {
+ protected CheckedMockCompilationUnit CU_DefaultClass = new CheckedMockCompilationUnit(
+ "test", "DefaultClass") {
public void check(JClassType type) {
assertEquals("DefaultClass", type.getSimpleSourceName());
assertEquals("test.DefaultClass", type.getQualifiedSourceName());
@@ -301,45 +241,47 @@
assertEquals(0, type.getFields().length);
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class DefaultClass extends Object { }\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_ExtendsGenericList = new TestCup("test.refresh",
- "ExtendsGenericList") {
+ protected CheckedMockCompilationUnit CU_ExtendsGenericList = new CheckedMockCompilationUnit(
+ "test.refresh", "ExtendsGenericList") {
@Override
public void check(JClassType type) throws NotFoundException {
+ assertNotNull(type.getSuperclass().isParameterized());
}
- public char[] getSource() {
+ public String getSource() {
StringBuilder sb = new StringBuilder();
sb.append("package test.refresh;\n");
sb.append("class ExtendsGenericList extends GenericList<Object> {}");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_ExtendsParameterizedType = new TestCup(
+ protected CheckedMockCompilationUnit CU_ExtendsParameterizedType = new CheckedMockCompilationUnit(
"parameterized.type.build.dependency", "Class2") {
@Override
public void check(JClassType type) throws NotFoundException {
+ assertNotNull(type.getSuperclass().isParameterized());
}
- public char[] getSource() throws UnableToCompleteException {
+ public String getSource() {
StringBuilder sb = new StringBuilder();
sb.append("package parameterized.type.build.dependency;\n");
sb.append("public class Class2 extends Class1<Object> {}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_FieldsAndTypes = new TestCup("test", "Fields",
- "SomeType") {
+ protected CheckedMockCompilationUnit CU_FieldsAndTypes = new CheckedMockCompilationUnit(
+ "test", "Fields", "SomeType") {
public void check(JClassType type) throws NotFoundException {
if ("Fields".equals(type.getSimpleSourceName())) {
assertEquals("test.Fields", type.getQualifiedSourceName());
@@ -423,12 +365,13 @@
assertEquals("int[][]", fieldType.getQualifiedSourceName());
} else {
- // No need to check SomeType since there's already a DefaultClass
+ // No need to check SomeType since
+ // there's already a DefaultClass
// test.
}
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("class SomeType { }");
@@ -446,56 +389,98 @@
sb.append(" private SomeType[] someTypeArray;\n");
sb.append(" private int[][] intArrayArray;\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_GenericList = new TestCup("test.refresh", "GenericList") {
+ protected CheckedMockCompilationUnit CU_GenericList = new CheckedMockCompilationUnit(
+ "test.refresh", "GenericList") {
@Override
public void check(JClassType type) throws NotFoundException {
+ assertNotNull(type.isGenericType());
}
- public char[] getSource() throws UnableToCompleteException {
+ public String getSource() {
StringBuilder sb = new StringBuilder();
sb.append("package test.refresh;\n");
sb.append("class GenericList<T> {\n");
sb.append(" public static final int CONSTANT = 0;\n");
sb.append("}");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_HasSyntaxErrors = new TestCup("test", "HasSyntaxErrors",
- "NoSyntaxErrors") {
+ protected CheckedMockCompilationUnit CU_HasSyntaxErrors = new CheckedMockCompilationUnit(
+ "test", "HasSyntaxErrors", "NoSyntaxErrors") {
public void check(JClassType classInfo) {
fail("This class should have been removed");
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("class NoSyntaxErrors { }\n");
sb.append("public class HasSyntaxErrors { a syntax error }\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_HasUnresolvedSymbols = new TestCup("test", "Invalid",
- "Valid") {
+ protected CheckedMockCompilationUnit CU_HasUnresolvedSymbols = new CheckedMockCompilationUnit(
+ "test", "Invalid", "Valid") {
public void check(JClassType classInfo) {
fail("Both classes should have been removed");
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class Invalid extends NoSuchClass { }\n");
sb.append("class Valid extends Object { }\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_MetaData = new TestCup("test", "MetaData") {
+ protected CheckedMockCompilationUnit CU_LocalClass = new CheckedMockCompilationUnit(
+ "test", "Enclosing", "Enclosing.1") {
+
+ public void check(JClassType type) {
+ final String name = type.getSimpleSourceName();
+ if ("Enclosing".equals(name))
+ checkEnclosing(type);
+ else
+ checkLocal(type);
+ }
+
+ public void checkEnclosing(JClassType type) {
+ assertEquals("Enclosing", type.getSimpleSourceName());
+ assertEquals("test.Enclosing", type.getQualifiedSourceName());
+ JClassType[] nested = type.getNestedTypes();
+ assertEquals(1, nested.length);
+ JClassType inner = nested[0];
+ assertEquals("test.Enclosing.1", inner.getQualifiedSourceName());
+ }
+
+ public void checkLocal(JClassType type) {
+ assertEquals("1", type.getSimpleSourceName());
+ assertEquals("test.Enclosing.1", type.getQualifiedSourceName());
+ assertEquals("test.Enclosing",
+ type.getEnclosingType().getQualifiedSourceName());
+ }
+
+ public String getSource() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package test;\n");
+ sb.append("public class Enclosing {\n");
+ sb.append(" public static Object getLocal() {");
+ sb.append(" return new Object() { };\n");
+ sb.append(" }\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+ };
+
+ protected CheckedMockCompilationUnit CU_MetaData = new CheckedMockCompilationUnit(
+ "test", "MetaData") {
public void check(JClassType type) throws NotFoundException {
{
@@ -553,7 +538,7 @@
}
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("/**\n");
@@ -574,11 +559,12 @@
sb.append(" private Object bar = null;\n");
sb.append(" private Object noMd = null;\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_MethodsAndParams = new TestCup("test", "Methods") {
+ protected CheckedMockCompilationUnit CU_MethodsAndParams = new CheckedMockCompilationUnit(
+ "test", "Methods") {
public void check(JClassType type) throws NotFoundException {
TypeOracle tio = type.getOracle();
@@ -634,7 +620,7 @@
assertEquals(0, thrownTypes.length);
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class Methods {\n");
@@ -645,25 +631,27 @@
sb.append(" public void overloaded(int x, Object y) throws Throwable { return; }\n");
sb.append(" public Object overloaded(int x, char y) { return null; }\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_Object = new TestCup("java.lang", "Object") {
+ protected CheckedMockCompilationUnit CU_Object = new CheckedMockCompilationUnit(
+ "java.lang", "Object") {
public void check(JClassType type) {
assertEquals("Object", type.getSimpleSourceName());
assertEquals("java.lang.Object", type.getQualifiedSourceName());
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;");
sb.append("public class Object { }");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_OuterInner = new TestCup("test", "Outer", "Outer.Inner") {
+ protected CheckedMockCompilationUnit CU_OuterInner = new CheckedMockCompilationUnit(
+ "test", "Outer", "Outer.Inner") {
public void check(JClassType type) {
final String name = type.getSimpleSourceName();
@@ -689,75 +677,87 @@
assertEquals("test.Outer.Inner", inner.getQualifiedSourceName());
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class Outer {\n");
sb.append(" public static class Inner { }\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_ReferencesGenericListConstant = new TestCup(
+ protected CheckedMockCompilationUnit CU_ReferencesGenericListConstant = new CheckedMockCompilationUnit(
"test.refresh", "ReferencesGenericListConstant") {
@Override
public void check(JClassType type) throws NotFoundException {
+ assertEquals("test.refresh.ReferencesGenericListConstant",
+ type.getQualifiedSourceName());
}
- public char[] getSource() throws UnableToCompleteException {
+ public String getSource() {
StringBuilder sb = new StringBuilder();
sb.append("package test.refresh;\n");
sb.append("class ReferencesGenericListConstant {\n");
sb.append(" public static final int MY_CONSTANT = GenericList.CONSTANT;\n");
sb.append("}");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed = new TestCup(
+ protected CheckedMockCompilationUnit CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed = new CheckedMockCompilationUnit(
"parameterized.type.build.dependency", "Class0") {
@Override
public void check(JClassType type) throws NotFoundException {
+ JClassType[] intfs = type.getImplementedInterfaces();
+ assertEquals(1, intfs.length);
+ assertNotNull(intfs[0].isParameterized());
}
- public char[] getSource() throws UnableToCompleteException {
+ public String getSource() {
StringBuilder sb = new StringBuilder();
sb.append("package parameterized.type.build.dependency;\n");
sb.append("public class Class0 implements Class2.Inner<Object> {\n");
sb.append("}\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_RefsInfectedCompilationUnit = new TestCup("test",
- "RefsInfectedCompilationUnit") {
+ protected CheckedMockCompilationUnit CU_RefsInfectedCompilationUnit = new CheckedMockCompilationUnit(
+ "test", "RefsInfectedCompilationUnit") {
public void check(JClassType classInfo) {
fail("This class should should have been removed because it refers to a class in another compilation unit that had problems");
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package test;\n");
sb.append("public class RefsInfectedCompilationUnit extends Valid { }\n");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
- protected TestCup CU_Throwable = new TestCup("java.lang", "Throwable") {
+ protected CheckedMockCompilationUnit CU_Throwable = new CheckedMockCompilationUnit(
+ "java.lang", "Throwable") {
public void check(JClassType type) {
assertEquals("Throwable", type.getSimpleSourceName());
assertEquals("java.lang.Throwable", type.getQualifiedSourceName());
}
- public char[] getSource() {
+ public String getSource() {
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;");
sb.append("public class Throwable { }");
- return sb.toString().toCharArray();
+ return sb.toString();
}
};
+ private final TypeOracleMediator mediator = new TypeOracleMediator();
+
+ private final TypeOracle typeOracle = mediator.getTypeOracle();
+
+ private final Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+
public void checkTypes(JClassType[] types) throws NotFoundException {
for (int i = 0; i < types.length; i++) {
JClassType type = types[i];
@@ -768,100 +768,123 @@
}
}
- public void testAssimilation() throws UnableToCompleteException {
- TypeOracle typeOracle0 = new TypeOracle();
- TreeLogger logger = createTreeLogger();
+ public void testAssignable() throws UnableToCompleteException,
+ TypeOracleException {
+ units.add(CU_Object);
+ units.add(CU_Assignable);
+ units.add(CU_OuterInner);
+ compileAndRefresh();
+ JClassType[] allTypes = typeOracle.getTypes();
+ assertEquals(7, allTypes.length);
- // Build onto an empty type oracle.
- //
- TypeOracleBuilder builder1 = new TypeOracleBuilder(typeOracle0);
- builder1.addCompilationUnit(CU_Object);
- builder1.addCompilationUnit(CU_BeforeAssimilate);
- TypeOracle typeOracle1 = builder1.build(logger);
- assertSame(typeOracle0, typeOracle1);
- assertEquals(2, typeOracle1.getTypes().length);
- JClassType before = typeOracle1.findType("test.assim.BeforeAssimilate");
+ Map<JClassType, Set<JClassType>> assignabilityMap = new HashMap<JClassType, Set<JClassType>>();
+
+ JClassType inner = typeOracle.findType("test.Outer.Inner");
+ JClassType baseIntf = typeOracle.findType("test.sub.BaseInterface");
+ JClassType derivedIntf = typeOracle.findType("test.sub.DerivedInterface");
+ recordAssignability(assignabilityMap, derivedIntf, baseIntf);
+ JClassType derived = typeOracle.findType("test.sub.Derived");
+ recordAssignability(assignabilityMap, derived, inner);
+ JClassType nested = typeOracle.findType("test.sub.Derived.Nested");
+ recordAssignability(assignabilityMap, nested, inner);
+ recordAssignability(assignabilityMap, nested, derivedIntf);
+ recordAssignability(assignabilityMap, nested, baseIntf);
+
+ for (JClassType fromType : allTypes) {
+ for (JClassType toType : allTypes) {
+ if (fromType == toType || toType == typeOracle.getJavaLangObject()) {
+ assertIsAssignable(fromType, toType);
+ } else {
+ Set<JClassType> set = assignabilityMap.get(fromType);
+ if (set != null && set.contains(toType)) {
+ assertIsAssignable(fromType, toType);
+ } else {
+ assertIsNotAssignable(fromType, toType);
+ }
+ }
+ }
+ }
+ }
+
+ public void testAssimilation() throws UnableToCompleteException,
+ TypeOracleException {
+ units.add(CU_Object);
+ units.add(CU_BeforeAssimilate);
+ compileAndRefresh();
+ assertEquals(2, typeOracle.getTypes().length);
+ JClassType before = typeOracle.findType("test.assim.BeforeAssimilate");
// Build onto an existing type oracle.
- //
- TypeOracleBuilder builder2 = new TypeOracleBuilder(typeOracle1);
- builder2.addCompilationUnit(CU_AfterAssimilate);
- TypeOracle typeOracle2 = builder2.build(logger);
- assertSame(typeOracle1, typeOracle2);
- assertEquals(3, typeOracle2.getTypes().length);
+ units.add(CU_AfterAssimilate);
+ compileAndRefresh();
+ assertEquals(3, typeOracle.getTypes().length);
// Make sure identities remained intact across the assimilation.
- //
- JClassType after = typeOracle2.findType("test.assim.AfterAssimilate");
-
+ JClassType after = typeOracle.findType("test.assim.AfterAssimilate");
assertSame(before, after.getSuperclass());
}
public void testBindToTypeScope() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_BindToTypeScope);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_BindToTypeScope);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
assertEquals(4, types.length);
- checkTypes(types);
}
public void testDefaultClass() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_DefaultClass);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_DefaultClass);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
assertEquals(2, types.length);
- checkTypes(types);
}
public void testFieldsAndTypes() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_FieldsAndTypes);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_FieldsAndTypes);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
assertEquals(3, types.length);
- checkTypes(types);
+ }
+
+ public void testLocal() throws TypeOracleException, UnableToCompleteException {
+ units.add(CU_Object);
+ units.add(CU_LocalClass);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
+ assertEquals(3, types.length);
}
public void testMetaData() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_MetaData);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_MetaData);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
assertEquals(2, types.length);
- checkTypes(types);
}
public void testMethodsAndParams() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_Throwable);
- tiob.addCompilationUnit(CU_MethodsAndParams);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_Throwable);
+ units.add(CU_MethodsAndParams);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
assertEquals(3, types.length);
- checkTypes(types);
}
public void testOuterInner() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_OuterInner);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_OuterInner);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
assertEquals(3, types.length);
- checkTypes(types);
}
/**
@@ -873,16 +896,14 @@
* CU_DeclaresInnerGenericType.
*/
public void testParameterizedTypeBuildDependencies()
- throws UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
+ throws UnableToCompleteException, TypeOracleException {
+ units.add(CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed);
+ units.add(CU_ExtendsParameterizedType);
+ units.add(CU_DeclaresInnerGenericType);
+ units.add(CU_Object);
- tiob.addCompilationUnit(CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed);
- tiob.addCompilationUnit(CU_ExtendsParameterizedType);
- tiob.addCompilationUnit(CU_DeclaresInnerGenericType);
- tiob.addCompilationUnit(CU_Object);
-
- TypeOracle tio = tiob.build(createTreeLogger());
- assertNull(tio.findType("test.parameterizedtype.build.dependencies.Class2"));
+ compileAndRefresh();
+ assertNull(typeOracle.findType("test.parameterizedtype.build.dependencies.Class2"));
}
/**
@@ -893,44 +914,42 @@
* @throws NotFoundException
* @throws IOException
*/
- public void testRefresh() throws UnableToCompleteException, NotFoundException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
+ public void testRefresh() throws UnableToCompleteException,
+ TypeOracleException {
+ units.add(CU_Object);
+ units.add(CU_ExtendsGenericList);
+ units.add(CU_GenericList);
+ units.add(CU_ReferencesGenericListConstant);
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_ExtendsGenericList);
- tiob.addCompilationUnit(CU_GenericList);
- tiob.addCompilationUnit(CU_ReferencesGenericListConstant);
-
- TreeLogger logger = createTreeLogger();
- TypeOracle to = tiob.build(logger);
+ compileAndRefresh();
// Get the types produced by the TypeOracle
- JClassType extendsGenericListType = to.getType("test.refresh.ExtendsGenericList");
- JClassType genericListType = to.getType("test.refresh.GenericList");
- JClassType objectType = to.getJavaLangObject();
- JClassType referencesGenericListConstantType = to.getType("test.refresh.ReferencesGenericListConstant");
+ JClassType extendsGenericListType = typeOracle.getType("test.refresh.ExtendsGenericList");
+ JClassType genericListType = typeOracle.getType("test.refresh.GenericList");
+ JClassType objectType = typeOracle.getJavaLangObject();
+ JClassType referencesGenericListConstantType = typeOracle.getType("test.refresh.ReferencesGenericListConstant");
/*
- * Add the CU_GenericList again and simulate a refresh. This should cause
+ * Invalidate CU_GenericList and simulate a refresh. This should cause
* anything that depends on GenericList to be rebuilt by the type oracle.
*/
- tiob.addCompilationUnit(CU_GenericList);
- refreshTypeOracle(tiob, to);
- to = tiob.build(logger);
+ CU_GenericList.setState(State.FRESH);
+ compileAndRefresh();
assertNotSame(genericListType.getQualifiedSourceName() + "; ",
- to.getType("test.refresh.GenericList"), genericListType);
+ typeOracle.getType("test.refresh.GenericList"), genericListType);
assertNotSame(extendsGenericListType.getQualifiedSourceName() + "; ",
- to.getType("test.refresh.ExtendsGenericList"), extendsGenericListType);
+ typeOracle.getType("test.refresh.ExtendsGenericList"),
+ extendsGenericListType);
assertSame(objectType.getQualifiedSourceName() + "; ",
- to.getJavaLangObject(), objectType);
+ typeOracle.getJavaLangObject(), objectType);
/*
* Make sure that referencing a constant field will cause a type to be
* rebuilt if the constant changes.
*/
assertNotSame(referencesGenericListConstantType.getQualifiedSourceName(),
- to.getType("test.refresh.ReferencesGenericListConstant"),
+ typeOracle.getType("test.refresh.ReferencesGenericListConstant"),
referencesGenericListConstantType);
}
@@ -946,21 +965,19 @@
* @throws UnableToCompleteException
* @throws IOException
*/
- public void testRefreshWithErrors() throws UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
-
+ public void testRefreshWithErrors() throws UnableToCompleteException,
+ TypeOracleException {
// Add Object
StringBuffer sb = new StringBuffer();
sb.append("package java.lang;");
sb.append("public class Object { }");
- addNonTransientCompilationUnitProvider(tiob, "java.lang.Object", sb);
+ addCompilationUnit("java.lang.Object", sb);
// Add UnmodifiedClass that will never change.
sb = new StringBuffer();
sb.append("package test.refresh.with.errors;");
sb.append("public class UnmodifiedClass { }");
- addNonTransientCompilationUnitProvider(tiob,
- "test.refresh.with.errors.UnmodifiedClass", sb);
+ addCompilationUnit("test.refresh.with.errors.UnmodifiedClass", sb);
// Add GoodClass that references a class that will go bad.
sb = new StringBuffer();
@@ -968,95 +985,113 @@
sb.append("public class GoodClass {\n");
sb.append(" ClassThatWillGoBad ctwgb;\n");
sb.append("}\n");
- addNonTransientCompilationUnitProvider(tiob,
- "test.refresh.with.errors.GoodClass", sb);
+ addCompilationUnit("test.refresh.with.errors.GoodClass", sb);
// Add ClassThatWillGoBad that goes bad on the next refresh.
- StaticCompilationUnitProvider cupThatWillGoBad = new StaticCompilationUnitProvider(
- "test.refresh.with.errors", "ClassThatWillGoBad", null) {
- boolean goBad = false;
+ MockCompilationUnit unitThatWillGoBad = new MockCompilationUnit(
+ "test.refresh.with.errors.ClassThatWillGoBad") {
+ private String source = "package test.refresh.with.errors;\n"
+ + "public class ClassThatWillGoBad { }\n";
@Override
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
+ public String getSource() {
+ return source;
+ }
- if (!goBad) {
- sb.append("package test.refresh.with.errors;\n");
- sb.append("public class ClassThatWillGoBad {\n");
- sb.append("}\n");
- goBad = true;
- } else {
- sb.append("This will cause a syntax error.");
- }
- return sb.toString().toCharArray();
+ @Override
+ void setState(State newState) {
+ super.setState(newState);
+ source = "This will cause a syntax error.";
}
};
- tiob.addCompilationUnit(cupThatWillGoBad);
+ units.add(unitThatWillGoBad);
- TreeLogger logger = createTreeLogger();
- TypeOracle to = tiob.build(logger);
- assertNotNull(to.findType("test.refresh.with.errors.UnmodifiedClass"));
- assertNotNull(to.findType("test.refresh.with.errors.GoodClass"));
- assertNotNull(to.findType("test.refresh.with.errors.ClassThatWillGoBad"));
+ compileAndRefresh();
- // Add AnotherGoodClass that references a class that was not recompiled.
+ assertNotNull(typeOracle.findType("test.refresh.with.errors.UnmodifiedClass"));
+ assertNotNull(typeOracle.findType("test.refresh.with.errors.GoodClass"));
+ assertNotNull(typeOracle.findType("test.refresh.with.errors.ClassThatWillGoBad"));
+
+ // Add AnotherGoodClass that references a
+ // class that was not recompiled.
sb = new StringBuffer();
sb.append("package test.refresh.with.errors;\n");
sb.append("public class AnotherGoodClass {\n");
sb.append(" UnmodifiedClass uc; // This will cause the runaway pruning.\n");
sb.append("}\n");
- addNonTransientCompilationUnitProvider(tiob,
- "test.refresh.with.errors.AnotherGoodClass", sb);
+ addCompilationUnit("test.refresh.with.errors.AnotherGoodClass", sb);
- // Add BadClass that has errors and originally forced issue 2238.
+ // Add BadClass that has errors and originally
+ // forced issue 2238.
sb = new StringBuffer();
sb.append("package test.refresh.with.errors;\n");
sb.append("public class BadClass {\n");
sb.append(" This will trigger a syntax error.\n");
sb.append("}\n");
- addNonTransientCompilationUnitProvider(tiob,
- "test.refresh.with.errors.BadClass", sb);
+ addCompilationUnit("test.refresh.with.errors.BadClass", sb);
// Now this cup should cause errors.
- tiob.addCompilationUnit(cupThatWillGoBad);
+ unitThatWillGoBad.setState(State.FRESH);
- refreshTypeOracle(tiob, to);
- to = tiob.build(logger);
+ compileAndRefresh();
- assertNotNull(to.findType("test.refresh.with.errors.UnmodifiedClass"));
- assertNotNull(to.findType("test.refresh.with.errors.AnotherGoodClass"));
- assertNull(to.findType("test.refresh.with.errors.BadClass"));
- assertNull(to.findType("test.refresh.with.errors.ClassThatWillGoBad"));
- assertNull(to.findType("test.refresh.with.errors.GoodClass"));
+ assertNotNull(typeOracle.findType("test.refresh.with.errors.UnmodifiedClass"));
+ assertNotNull(typeOracle.findType("test.refresh.with.errors.AnotherGoodClass"));
+ assertNull(typeOracle.findType("test.refresh.with.errors.BadClass"));
+ assertNull(typeOracle.findType("test.refresh.with.errors.ClassThatWillGoBad"));
+ assertNull(typeOracle.findType("test.refresh.with.errors.GoodClass"));
}
public void testSyntaxErrors() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_HasSyntaxErrors);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_HasSyntaxErrors);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
// Only java.lang.Object should remain.
//
assertEquals(1, types.length);
assertEquals("java.lang.Object", types[0].getQualifiedSourceName());
- checkTypes(types);
}
public void testUnresolvedSymbls() throws TypeOracleException,
UnableToCompleteException {
- TypeOracleBuilder tiob = createTypeInfoOracleBuilder();
- tiob.addCompilationUnit(CU_Object);
- tiob.addCompilationUnit(CU_HasUnresolvedSymbols);
- tiob.addCompilationUnit(CU_RefsInfectedCompilationUnit);
- TypeOracle tio = tiob.build(createTreeLogger());
- JClassType[] types = tio.getTypes();
+ units.add(CU_Object);
+ units.add(CU_HasUnresolvedSymbols);
+ units.add(CU_RefsInfectedCompilationUnit);
+ compileAndRefresh();
+ JClassType[] types = typeOracle.getTypes();
// Only java.lang.Object should remain.
//
assertEquals(1, types.length);
assertEquals("java.lang.Object", types[0].getQualifiedSourceName());
- checkTypes(types);
+ }
+
+ /**
+ * Creates a {@link CompilationUnit} and adds it the set of units.
+ *
+ * @throws UnableToCompleteException
+ */
+ private void addCompilationUnit(String qualifiedTypeName, CharSequence source) {
+ units.add(new MockCompilationUnit(qualifiedTypeName, source.toString()));
+ }
+
+ private void check(JClassType classInfo) throws NotFoundException {
+ final String qName = classInfo.getQualifiedSourceName();
+ CheckedMockCompilationUnit cup = publicTypeNameToTestCupMap.get(qName);
+ if (cup != null) {
+ cup.check(classInfo);
+ }
+ }
+
+ private void compileAndRefresh() throws UnableToCompleteException,
+ TypeOracleException {
+ TreeLogger logger = createTreeLogger();
+ CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger, units);
+ JdtCompiler.compile(units);
+ CompilationUnitInvalidator.invalidateUnitsWithErrors(logger, units);
+ mediator.refresh(logger, units);
+ checkTypes(typeOracle.getTypes());
}
/**
@@ -1073,12 +1108,7 @@
}
}
- private TypeOracleBuilder createTypeInfoOracleBuilder() {
- return new TypeOracleBuilder();
- }
-
- private void refreshTypeOracle(TypeOracleBuilder tiob, TypeOracle to) {
- CacheManager cacheManager = tiob.getCacheManager();
- cacheManager.invalidateOnRefresh(to);
+ private void register(String qualifiedTypeName, CheckedMockCompilationUnit cup) {
+ publicTypeNameToTestCupMap.put(qualifiedTypeName, cup);
}
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
new file mode 100644
index 0000000..4a9a2e5
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
@@ -0,0 +1,76 @@
+/*
+ * 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.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utilities for tests that build a type oracle and watch for errors.
+ *
+ */
+public class TypeOracleTestingUtils {
+
+ public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
+ CompilationUnit... extraUnits) throws UnableToCompleteException {
+ Set<CompilationUnit> extraUnitSet = new HashSet<CompilationUnit>();
+ Collections.addAll(extraUnitSet, extraUnits);
+ return buildStandardTypeOracleWith(logger, extraUnitSet);
+ }
+
+ public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
+ Set<CompilationUnit> extraUnits) throws UnableToCompleteException {
+ Set<CompilationUnit> unitSet = new HashSet<CompilationUnit>();
+ addStandardCups(unitSet);
+ for (CompilationUnit extraUnit : extraUnits) {
+ unitSet.add(extraUnit);
+ }
+ return buildTypeOracle(logger, unitSet);
+ }
+
+ /**
+ * Add compilation units for basic classes like Object and String.
+ */
+ private static void addStandardCups(Set<CompilationUnit> units) {
+ for (JavaSourceFile resource : JavaSourceCodeBase.getStandardResources()) {
+ units.add(new SourceFileCompilationUnit(resource));
+ }
+ }
+
+ private static TypeOracle buildTypeOracle(TreeLogger logger,
+ Set<CompilationUnit> units) throws UnableToCompleteException {
+ JdtCompiler.compile(units);
+ Map<String, CompiledClass> classMap = new HashMap<String, CompiledClass>();
+ for (CompilationUnit unit : units) {
+ for (CompiledClass compiledClass : unit.getCompiledClasses()) {
+ classMap.put(compiledClass.getBinaryName(), compiledClass);
+ }
+ }
+ CompilationUnitInvalidator.validateCompilationUnits(units, classMap);
+ CompilationUnitInvalidator.invalidateUnitsWithErrors(logger, units);
+ TypeOracleMediator mediator = new TypeOracleMediator();
+ mediator.refresh(logger, units);
+ return mediator.getTypeOracle();
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/JavaResourceBase.java b/dev/core/test/com/google/gwt/dev/javac/impl/JavaResourceBase.java
new file mode 100644
index 0000000..43f6657
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/JavaResourceBase.java
@@ -0,0 +1,141 @@
+/*
+ * 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.impl;
+
+/**
+ * Contains standard Java source files for testing.
+ */
+public class JavaResourceBase {
+
+ public static final MockResource ANNOTATION = new MockJavaResource(
+ "java.lang.annotation.Annotation") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.lang.annotation;\n");
+ code.append("public interface Annotation {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockJavaResource BAR = new MockJavaResource("test.Bar") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;\n");
+ code.append("public class Bar extends Foo {\n");
+ code.append(" public String value() { return \"Bar\"; }\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockResource CLASS = new MockJavaResource(
+ "java.lang.Class") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.lang;\n");
+ code.append("public class Class<T> {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockJavaResource FOO = new MockJavaResource("test.Foo") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;\n");
+ code.append("public class Foo {\n");
+ code.append(" public String value() { return \"Foo\"; }\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockResource JAVASCRIPTOBJECT = new MockJavaResource(
+ "com.google.gwt.core.client.JavaScriptObject") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.core.client;\n");
+ code.append("public class JavaScriptObject {\n");
+ code.append(" protected JavaScriptObject() { }\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockResource MAP = new MockJavaResource("java.util.Map") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.util;\n");
+ code.append("public interface Map<K,V> { }\n");
+ return code;
+ }
+ };
+ public static final MockResource OBJECT = new MockJavaResource(
+ "java.lang.Object") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.lang;\n");
+ code.append("public class Object {\n");
+ code.append(" public String toString() { return \"Object\"; }\n");
+ code.append(" public Object clone() { return this; } ");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockResource SERIALIZABLE = new MockJavaResource(
+ "java.lang.Serializable") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.lang;\n");
+ code.append("public interface Serializable { }\n");
+ return code;
+ }
+ };
+ public static final MockResource STRING = new MockJavaResource(
+ "java.lang.String") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.lang;\n");
+ code.append("public final class String {\n");
+ code.append(" public int length() { return 0; }\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockResource SUPPRESS_WARNINGS = new MockJavaResource(
+ "java.lang.SuppressWarnings") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package java.lang;\n");
+ code.append("public @interface SuppressWarnings {\n");
+ code.append(" String[] value();\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+
+ public static MockResource[] getStandardResources() {
+ return new MockResource[] {
+ ANNOTATION, CLASS, JAVASCRIPTOBJECT, MAP, OBJECT, SERIALIZABLE, STRING,
+ SUPPRESS_WARNINGS};
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/JavaSourceOracleImplTest.java b/dev/core/test/com/google/gwt/dev/javac/impl/JavaSourceOracleImplTest.java
new file mode 100644
index 0000000..b063893
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/JavaSourceOracleImplTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.javac.JavaSourceFile;
+import com.google.gwt.dev.resource.Resource;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * Tests {@link JavaSourceOracleImpl} using a mock {@link ResourceOracle}.
+ */
+public class JavaSourceOracleImplTest extends TestCase {
+
+ private MockResourceOracle resourceOracle = new MockResourceOracle(
+ JavaResourceBase.getStandardResources());
+
+ private JavaSourceOracleImpl sourceOracle = new JavaSourceOracleImpl(
+ resourceOracle);
+
+ public void testAdd() {
+ validateSourceOracle();
+
+ Map<String, JavaSourceFile> originalSourceMap = sourceOracle.getSourceMap();
+ resourceOracle.add(JavaResourceBase.FOO);
+ Map<String, JavaSourceFile> newSourceMap = sourceOracle.getSourceMap();
+ assertNotSame(originalSourceMap, newSourceMap);
+ assertEquals(originalSourceMap.size() + 1, newSourceMap.size());
+ validateSourceOracle();
+ }
+
+ public void testBasic() {
+ validateSourceOracle();
+ }
+
+ public void testEmpty() {
+ resourceOracle = new MockResourceOracle();
+ sourceOracle = new JavaSourceOracleImpl(resourceOracle);
+ validateSourceOracle();
+ }
+
+ public void testRemove() {
+ validateSourceOracle();
+
+ Map<String, JavaSourceFile> originalSourceMap = sourceOracle.getSourceMap();
+ resourceOracle.remove(JavaResourceBase.OBJECT.getPath());
+ Map<String, JavaSourceFile> newSourceMap = sourceOracle.getSourceMap();
+ assertNotSame(originalSourceMap, newSourceMap);
+ assertEquals(originalSourceMap.size() - 1, newSourceMap.size());
+ validateSourceOracle();
+ }
+
+ public void testReplace() {
+ validateSourceOracle();
+
+ Map<String, JavaSourceFile> originalSourceMap = sourceOracle.getSourceMap();
+ resourceOracle.replace(new MockResource(JavaResourceBase.OBJECT.getPath()) {
+ @Override
+ protected CharSequence getContent() {
+ return JavaResourceBase.OBJECT.getContent();
+ }
+ });
+ Map<String, JavaSourceFile> newSourceMap = sourceOracle.getSourceMap();
+ assertNotSame(originalSourceMap, newSourceMap);
+ assertEquals(originalSourceMap.size(), newSourceMap.size());
+ assertFalse(originalSourceMap.equals(newSourceMap));
+ validateSourceOracle();
+ }
+
+ public void testReplaceWithSame() {
+ validateSourceOracle();
+
+ Map<String, JavaSourceFile> originalSourceMap = sourceOracle.getSourceMap();
+ resourceOracle.replace(JavaResourceBase.OBJECT);
+ Map<String, JavaSourceFile> newSourceMap = sourceOracle.getSourceMap();
+ assertNotSame(originalSourceMap, newSourceMap);
+ assertEquals(originalSourceMap.size(), newSourceMap.size());
+ assertEquals(originalSourceMap, newSourceMap);
+ validateSourceOracle();
+ }
+
+ /**
+ * Validate that the source oracle accurately reflects the resource oracle.
+ */
+ private void validateSourceOracle() {
+ // Save off the reflected collections.
+ Map<String, JavaSourceFile> sourceMap = sourceOracle.getSourceMap();
+ Set<String> classNames = sourceOracle.getClassNames();
+ Set<JavaSourceFile> sourceFiles = sourceOracle.getSourceFiles();
+
+ // Validate that the collections are consistent with each other.
+ assertEquals(sourceMap.keySet(), classNames);
+ assertEquals(new HashSet<JavaSourceFile>(sourceMap.values()), sourceFiles);
+
+ // Save off a mutable copy of the resource map to compare with.
+ Map<String, Resource> resourceMap = new HashMap<String, Resource>(
+ resourceOracle.getResourceMap());
+ assertEquals(resourceMap.size(), sourceMap.size());
+ for (Entry<String, JavaSourceFile> entry : sourceMap.entrySet()) {
+ // Validate source file internally consistent.
+ String className = entry.getKey();
+ JavaSourceFile sourceFile = entry.getValue();
+ assertEquals(className, sourceFile.getTypeName());
+ assertEquals(Shared.getPackageName(className),
+ sourceFile.getPackageName());
+ assertEquals(Shared.getShortName(className), sourceFile.getShortName());
+
+ // Find the matching resource (and remove it from the resource map!)
+ String expectedPath = Shared.toPath(className);
+ assertTrue(resourceMap.containsKey(expectedPath));
+
+ // Validate the source file matches the resource.
+ Resource resource = resourceMap.remove(expectedPath);
+ assertNotNull(resource);
+ assertEquals(Shared.readContent(resource.openContents()),
+ sourceFile.readSource());
+ }
+ // The resource map should be empty now.
+ assertEquals(0, resourceMap.size());
+
+ // Validate collection identity hasn't changed.
+ assertSame(sourceMap, sourceOracle.getSourceMap());
+ assertSame(sourceFiles, sourceOracle.getSourceFiles());
+ assertSame(classNames, sourceOracle.getClassNames());
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/JdtBehaviorTest.java b/dev/core/test/com/google/gwt/dev/javac/impl/JdtBehaviorTest.java
new file mode 100644
index 0000000..fb4115a
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/JdtBehaviorTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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.impl;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Validates certain JDT behaviors that the compilation process may depend on
+ * for correctness. One useful aspect would be that if we upgrade JDT in the
+ * future, this test could help validate our assumptions.
+ */
+public class JdtBehaviorTest extends TestCase {
+
+ /**
+ * Hook-point if we need to modify the compiler behavior.
+ */
+ private class CompilerImpl extends Compiler {
+
+ public CompilerImpl(INameEnvironment environment,
+ ICompilerRequestor requestor) {
+ super(environment, DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ getCompilerOptions(), requestor, new DefaultProblemFactory(
+ Locale.getDefault()));
+ }
+ }
+
+ /**
+ * Hook point to accept results.
+ */
+ private class ICompilerRequestorImpl implements ICompilerRequestor {
+ public void acceptResult(CompilationResult result) {
+ if (result.hasErrors()) {
+ StringBuilder sb = new StringBuilder();
+ for (CategorizedProblem problem : result.getErrors()) {
+ sb.append(problem.toString());
+ sb.append('\n');
+ }
+ fail(sb.toString());
+ }
+ for (ClassFile classFile : result.getClassFiles()) {
+ char[][] classNameArray = classFile.getCompoundName();
+ char[][] packageArray = CharOperation.subarray(classNameArray, 0,
+ classNameArray.length - 1);
+ char[] packageName = CharOperation.concatWith(packageArray, '.');
+ char[] className = CharOperation.concatWith(classNameArray, '.');
+ addPackages(String.valueOf(packageName));
+ classFiles.put(String.valueOf(className), classFile);
+ }
+ }
+
+ private void addPackages(String packageName) {
+ while (true) {
+ packages.add(String.valueOf(packageName));
+ int pos = packageName.lastIndexOf('.');
+ if (pos > 0) {
+ packageName = packageName.substring(0, pos);
+ } else {
+ packages.add("");
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * How JDT receives files from the environment.
+ */
+ private class INameEnvironmentImpl implements INameEnvironment {
+ public void cleanup() {
+ // intentionally blank
+ }
+
+ public NameEnvironmentAnswer findType(char[] type, char[][] pkg) {
+ return findType(CharOperation.arrayConcat(pkg, type));
+ }
+
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ final char[] typeChars = CharOperation.concatWith(compoundTypeName, '.');
+ String typeName = String.valueOf(typeChars);
+ // System.out.println("findType: " + typeName);
+ ClassFile classFile = classFiles.get(typeName);
+ if (classFile != null) {
+ try {
+ byte[] bytes = classFile.getBytes();
+ char[] loc = classFile.fileName();
+ ClassFileReader cfr = new ClassFileReader(bytes, loc);
+ return new NameEnvironmentAnswer(cfr, null);
+ } catch (ClassFormatException e) {
+ throw new RuntimeException("Unexpectedly unable to parse class file",
+ e);
+ }
+ }
+ return null;
+ }
+
+ public boolean isPackage(char[][] parentPkg, char[] pkg) {
+ final char[] pathChars = CharOperation.concatWith(parentPkg, pkg, '.');
+ String packageName = String.valueOf(pathChars);
+ // System.out.println("isPackage: " + packageName);
+ return packages.contains(packageName);
+ }
+ }
+
+ private class ResourceAdapter implements ICompilationUnit {
+
+ private final MockJavaSourceFile sourceFile;
+
+ public ResourceAdapter(MockResource resource) {
+ sourceFile = new MockJavaSourceFile(resource);
+ }
+
+ public char[] getContents() {
+ return sourceFile.readSource().toCharArray();
+ }
+
+ public char[] getFileName() {
+ return sourceFile.getLocation().toCharArray();
+ }
+
+ public char[] getMainTypeName() {
+ return sourceFile.getShortName().toCharArray();
+ }
+
+ public char[][] getPackageName() {
+ return CharOperation.splitOn('.',
+ sourceFile.getPackageName().toCharArray());
+ }
+
+ @Override
+ public String toString() {
+ return sourceFile.toString();
+ }
+ }
+
+ private static CompilerOptions getCompilerOptions() {
+ Map<String, String> settings = new HashMap<String, String>();
+ settings.put(CompilerOptions.OPTION_LineNumberAttribute,
+ CompilerOptions.GENERATE);
+ settings.put(CompilerOptions.OPTION_SourceFileAttribute,
+ CompilerOptions.GENERATE);
+ /*
+ * Tricks like "boolean stopHere = true;" depend on this setting to work in
+ * hosted mode. In web mode, our compiler should optimize them out once we
+ * do real data flow.
+ */
+ settings.put(CompilerOptions.OPTION_PreserveUnusedLocal,
+ CompilerOptions.PRESERVE);
+ settings.put(CompilerOptions.OPTION_ReportDeprecation,
+ CompilerOptions.IGNORE);
+ settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
+ CompilerOptions.GENERATE);
+ settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
+ settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
+ settings.put(CompilerOptions.OPTION_TargetPlatform,
+ CompilerOptions.VERSION_1_5);
+
+ // This is needed by TypeOracleBuilder to parse metadata.
+ settings.put(CompilerOptions.OPTION_DocCommentSupport,
+ CompilerOptions.ENABLED);
+ return new CompilerOptions(settings);
+ }
+
+ protected Map<String, ClassFile> classFiles = new HashMap<String, ClassFile>();
+
+ /**
+ * New object for each test case.
+ */
+ protected INameEnvironmentImpl environment = new INameEnvironmentImpl();
+
+ protected Set<String> packages = new HashSet<String>();
+
+ /**
+ * New object for each test case.
+ */
+ protected ICompilerRequestorImpl requestor = new ICompilerRequestorImpl();
+
+ /**
+ * New object for each test case.
+ */
+ CompilerImpl compiler = new CompilerImpl(environment, requestor);
+
+ public void testIncrementalBuild() {
+ List<MockResource> resources = new ArrayList<MockResource>();
+ Collections.addAll(resources, JavaResourceBase.getStandardResources());
+ resources.add(JavaResourceBase.FOO);
+ doCompile(resources);
+
+ // Now incremental build the bar cup.
+ doCompile(Arrays.asList(JavaResourceBase.BAR));
+ }
+
+ public void testSingleBuild() {
+ List<MockResource> resources = new ArrayList<MockResource>();
+ Collections.addAll(resources, JavaResourceBase.getStandardResources());
+ resources.add(JavaResourceBase.FOO);
+ resources.add(JavaResourceBase.BAR);
+ doCompile(resources);
+ }
+
+ private void doCompile(List<? extends MockResource> resources) {
+ ICompilationUnit[] icus = new ICompilationUnit[resources.size()];
+ for (int i = 0; i < icus.length; ++i) {
+ icus[i] = new ResourceAdapter(resources.get(i));
+ }
+ compiler.compile(icus);
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaResource.java b/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaResource.java
new file mode 100644
index 0000000..2f3de7a
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaResource.java
@@ -0,0 +1,23 @@
+/*
+ * 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.impl;
+
+public abstract class MockJavaResource extends MockResource {
+
+ public MockJavaResource(String qualifiedTypeName) {
+ super(Shared.toPath(qualifiedTypeName));
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java b/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java
new file mode 100644
index 0000000..1225e50
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.javac.JavaSourceFile;
+
+public class MockJavaSourceFile extends JavaSourceFile {
+
+ private final String location;
+ private final String qualifiedTypeName;
+ private final String source;
+
+ public MockJavaSourceFile(JavaSourceFile sourceFile) {
+ this(sourceFile.getTypeName(), sourceFile.readSource(),
+ sourceFile.getLocation());
+ }
+
+ public MockJavaSourceFile(MockResource resource) {
+ this(Shared.toTypeName(resource.getPath()),
+ resource.getContent().toString(), resource.getLocation());
+ }
+
+ public MockJavaSourceFile(String qualifiedTypeName, String source) {
+ this(qualifiedTypeName, source, "/mock/" + Shared.toPath(qualifiedTypeName));
+ }
+
+ public MockJavaSourceFile(String qualifiedTypeName, String source,
+ String location) {
+ this.qualifiedTypeName = qualifiedTypeName;
+ this.source = source;
+ this.location = location;
+ }
+
+ @Override
+ public String getLocation() {
+ return location;
+ }
+
+ @Override
+ public String getPackageName() {
+ return Shared.getPackageName(qualifiedTypeName);
+ }
+
+ @Override
+ public String getShortName() {
+ return Shared.getShortName(qualifiedTypeName);
+ }
+
+ @Override
+ public String getTypeName() {
+ return qualifiedTypeName;
+ }
+
+ @Override
+ public String readSource() {
+ return source;
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java b/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java
new file mode 100644
index 0000000..a0fbc94
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java
@@ -0,0 +1,56 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.util.Util;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * An in-memory {@link Resource}.
+ */
+public abstract class MockResource extends Resource {
+ private final String path;
+
+ public MockResource(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public String getLocation() {
+ return "/mock/" + path;
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public URL getURL() {
+ return null;
+ }
+
+ @Override
+ public InputStream openContents() {
+ return new ByteArrayInputStream(Util.getBytes(getContent().toString()));
+ }
+
+ protected abstract CharSequence getContent();
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/MockResourceOracle.java b/dev/core/test/com/google/gwt/dev/javac/impl/MockResourceOracle.java
new file mode 100644
index 0000000..c224b9c
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/MockResourceOracle.java
@@ -0,0 +1,89 @@
+/*
+ * 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.impl;
+
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+
+import junit.framework.Assert;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A simple {@link ResourceOracle} for testing.
+ */
+public class MockResourceOracle implements ResourceOracle {
+
+ private Map<String, Resource> exportedMap = Collections.emptyMap();
+ private Set<Resource> exportedValues = Collections.emptySet();
+
+ public MockResourceOracle(Resource... resources) {
+ add(resources);
+ }
+
+ public Set<String> getPathNames() {
+ return exportedMap.keySet();
+ }
+
+ public Map<String, Resource> getResourceMap() {
+ return exportedMap;
+ }
+
+ public Set<Resource> getResources() {
+ return exportedValues;
+ }
+
+ void add(Resource... resources) {
+ Map<String, Resource> newMap = new HashMap<String, Resource>(exportedMap);
+ for (Resource resource : resources) {
+ String path = resource.getPath();
+ Assert.assertFalse(newMap.containsKey(path));
+ newMap.put(path, resource);
+ }
+ export(newMap);
+ }
+
+ void remove(String... paths) {
+ Map<String, Resource> newMap = new HashMap<String, Resource>(exportedMap);
+ for (String path : paths) {
+ Resource oldValue = newMap.remove(path);
+ Assert.assertNotNull(oldValue);
+ }
+ export(newMap);
+ }
+
+ void replace(Resource... resources) {
+ Map<String, Resource> newMap = new HashMap<String, Resource>(exportedMap);
+ for (Resource resource : resources) {
+ String path = resource.getPath();
+ Assert.assertTrue(newMap.containsKey(path));
+ newMap.put(path, resource);
+ }
+ export(newMap);
+ }
+
+ private void export(Map<String, Resource> newMap) {
+ exportedMap = Collections.unmodifiableMap(newMap);
+ // Make a new hash set for constant lookup.
+ exportedValues = Collections.unmodifiableSet(new HashSet<Resource>(
+ exportedMap.values()));
+ }
+
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/jdt/ByteCodeCompilerTest.java b/dev/core/test/com/google/gwt/dev/jdt/ByteCodeCompilerTest.java
deleted file mode 100644
index 0f24786..0000000
--- a/dev/core/test/com/google/gwt/dev/jdt/ByteCodeCompilerTest.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-import com.google.gwt.dev.jdt.ByteCodeCompiler;
-import com.google.gwt.dev.jdt.RebindOracle;
-import com.google.gwt.dev.jdt.SourceOracle;
-import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
-import com.google.gwt.dev.util.FileOracle;
-import com.google.gwt.dev.util.FileOracleFactory;
-import com.google.gwt.dev.util.FileOracleFactory.FileFilter;
-import com.google.gwt.dev.util.log.Loggers;
-
-import junit.framework.TestCase;
-
-import java.net.URL;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class ByteCodeCompilerTest extends TestCase {
-
- private static class TestByteCodeCompilerHost implements SourceOracle,
- RebindOracle {
-
- private abstract class TestCup implements CompilationUnitProvider {
-
- /**
- * Creates a new {@code TestCup} with several types. The first type in
- * {@code typeNames} is considered to be the main type.
- *
- * @param packageName the package for the types in this {@code TestCup}
- * @param typeNames the types for this {@code TestCup}. Must have
- * at least one type. The first type is considered to be the main type
- * for this {@code TestCup}.
- */
- public TestCup(String packageName, String... typeNames) {
- this.packageName = packageName;
- registerPackage(packageName);
- for (int i = 0; i < typeNames.length; i++) {
- if (packageName.length() > 0) {
- registerType(packageName + "." + typeNames[i], this);
- } else {
- // In the default package.
- //
- registerType(typeNames[i], this);
- }
- }
- firstTypeName = typeNames[0];
- }
-
- public long getLastModified() throws UnableToCompleteException {
- return 0;
- }
-
- public String getLocation() {
- return "transient source for " + packageName + "." + firstTypeName;
- }
-
- public String getMainTypeName() {
- return firstTypeName;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public abstract char[] getSource();
-
- public boolean isTransient() {
- return true;
- }
-
- private final String firstTypeName;
- private final String packageName;
- }
-
- public TestByteCodeCompilerHost() {
- registerPackage(""); // the default package
- }
-
- public final CompilationUnitProvider findCompilationUnit(TreeLogger logger,
- String typeName) {
- return cupsByTypeName.get(typeName);
- }
-
- public final boolean isPackage(String possiblePackageName) {
- return pkgNames.contains(possiblePackageName);
- }
-
- // Override for specific test cases.
- //
- public String rebind(TreeLogger logger, String typeName)
- throws UnableToCompleteException {
- return typeName;
- }
-
- public final void registerPackage(String packageName) {
- String[] packageParts = packageName.split("\\.");
- String toRegister = null;
- for (int i = 0; i < packageParts.length; i++) {
- String part = packageParts[i];
- if (toRegister != null) {
- toRegister += "." + part;
- } else {
- toRegister = part;
- }
- pkgNames.add(toRegister);
- }
- }
-
- public final void registerType(String typeName, TestCup cup) {
- cupsByTypeName.put(typeName, cup);
- }
-
- {
- pkgNames = new HashSet<String>();
- cupsByTypeName = new HashMap<String, CompilationUnitProvider>();
- }
-
- final CompilationUnitProvider CU_AB = new TestCup("test", "A", "A.B") {
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package test;\n");
- sb.append("public class A {\n");
- sb.append(" public static class B extends A { }\n");
- sb.append("}\n");
- return sb.toString().toCharArray();
- }
- };
-
- final CompilationUnitProvider CU_C = new TestCup("test", "C", "C.Message") {
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package test;\n");
- sb.append("import com.google.gwt.core.client.GWT;\n");
- sb.append("public class C {\n");
- sb.append(" public static String getMessage() {\n");
- sb.append(" return ((Message)GWT.create(Message.class)).f();\n");
- sb.append(" }\n");
- sb.append(" public static class Message {\n");
- sb.append(" public String f() {\n");
- sb.append(" return \"C.Message\";\n");
- sb.append(" }\n");
- sb.append(" }\n");
- sb.append("}\n");
- return sb.toString().toCharArray();
- }
- };
-
- final CompilationUnitProvider CU_CLASS = new TestCup("java.lang", "Class") {
-
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package java.lang;\n");
- sb.append("public class Class { }\n");
- return sb.toString().toCharArray();
- }
- };
-
- /**
- * This one is different because D is not public and it lives in the default
- * package.
- */
- final CompilationUnitProvider CU_DE = new TestCup("", "D", "D.E") {
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("class D extends test.C.Message {\n");
- sb.append(" public static class E extends D {\n");
- sb.append(" public String getMessage() {\n");
- sb.append(" return \"D.E.Message\";\n");
- sb.append(" }\n");
- sb.append(" }\n");
- sb.append("}\n");
- return sb.toString().toCharArray();
- }
- };
-
- final CompilationUnitProvider CU_GWT = new TestCup(
- "com.google.gwt.core.client", "GWT") {
-
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package com.google.gwt.core.client;\n");
- sb.append("public final class GWT {\n");
- sb.append(" public static Object create(Class classLiteral) { return null; }\n");
- sb.append("}\n");
- return sb.toString().toCharArray();
- }
- };
-
- final CompilationUnitProvider CU_MAIN = new TestCup("test", "Main") {
-
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package test;\n");
- sb.append("import com.google.gwt.core.client.GWT;\n");
- sb.append("public class Main {\n");
- sb.append(" public static void main(String[] args) {\n");
- sb.append(" A a = (A)GWT.create(A.class);\n");
- sb.append(" }\n");
- sb.append("}\n");
- return sb.toString().toCharArray();
- }
- };
-
- final TestCup CU_OBJECT = new TestCup("java.lang", "Object") {
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package java.lang;\n");
- sb.append("public class Object { }\n");
- return sb.toString().toCharArray();
- }
- };
-
- final CompilationUnitProvider CU_STRING = new TestCup("java.lang", "String") {
-
- public char[] getSource() {
- StringBuffer sb = new StringBuffer();
- sb.append("package java.lang;\n");
- sb.append("public class String { }\n");
- return sb.toString().toCharArray();
- }
- };
-
- private final Map<String, CompilationUnitProvider> cupsByTypeName;
- private final Set<String> pkgNames;
- }
-
- private static void scanAndCompile(TreeLogger logger)
- throws UnableToCompleteException {
- FileOracleFactory fof = new FileOracleFactory();
- fof.addPackage("", new FileFilter() {
- public boolean accept(String string) {
- return string.endsWith(".java");
- }
- });
- final FileOracle fo = fof.create(logger);
-
- final SourceOracle host = new SourceOracle() {
-
- public CompilationUnitProvider findCompilationUnit(TreeLogger logger,
- String typeName) {
- // ONLY LOOK FOR TOP-LEVEL TYPES.
- //
- CompilationUnitProvider cup = cups.get(typeName);
- if (cup == null) {
- String path = typeName.replace('.', '/') + ".java";
- URL url = fo.find(path);
- if (url != null) {
- String pkgName = "";
- int len = findLengthOfPackagePart(typeName);
- if (len > 0) {
- pkgName = typeName.substring(0, len);
- }
- return new URLCompilationUnitProvider(url, pkgName);
- } else {
- return null;
- }
- }
- return cup;
- }
-
- public boolean isPackage(String possiblePackageName) {
- String path = possiblePackageName.replace('.', '/') + "/";
- URL url = fo.find(path);
- if (url != null) {
- return true;
- } else {
- return false;
- }
- }
-
- private int findLengthOfPackagePart(String typeName) {
- int maxDotIndex = 0;
- int i = typeName.indexOf('.');
- while (i != -1) {
- if (!isPackage(typeName.substring(0, i))) {
- break;
- } else {
- maxDotIndex = i;
- i = typeName.indexOf('.', i + 1);
- }
- }
- return maxDotIndex;
- }
-
- private Map<String, CompilationUnitProvider> cups = new HashMap<String, CompilationUnitProvider>();
- };
-
- ByteCodeCompiler cs = new ByteCodeCompiler(host);
- String[] allJava = fo.getAllFiles();
-
- for (int i = 0; i < 3; ++i) {
- long before = System.currentTimeMillis();
-
- for (int j = 0; j < allJava.length; j++) {
- String typeName = allJava[j].substring(0, allJava[j].length() - 5).replace(
- '/', '.');
- cs.getClassBytes(logger, typeName);
- }
-
- long after = System.currentTimeMillis();
- System.out.println("Iter " + i + " took " + (after - before) + " ms");
- }
- }
-
- // This one is standalone.
- //
- public void testJavaLangObject() throws Exception {
- ByteCodeCompiler cs = new ByteCodeCompiler(testHost);
- assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
- }
-
- // This one requires java.lang.Object.
- //
- public void testJavaLangString() throws Exception {
- ByteCodeCompiler cs = new ByteCodeCompiler(testHost);
- assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
- assertNotNull(cs.getClassBytes(logger, "java.lang.String"));
- }
-
- // Try deferred binding that takes three compile iterations.
- // - In Main, we rebind from A to C
- // - In C, we rebind from C to D.E
- //
- public void testRebindCreateTransitive() throws Exception {
- ByteCodeCompiler cs = new ByteCodeCompiler(new TestByteCodeCompilerHost() {
- public String rebind(TreeLogger logger, String typeName)
- throws com.google.gwt.core.ext.UnableToCompleteException {
- if ("test.C.Message".equals(typeName)) {
- return "D.E";
- } else {
- return typeName;
- }
- }
- });
-
- assertNotNull(cs.getClassBytes(logger, "test.C"));
- assertNotNull(cs.getClassBytes(logger, "test.C$Message"));
- assertNotNull(cs.getClassBytes(logger, "D"));
- assertNotNull(cs.getClassBytes(logger, "D$E"));
-
- assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
- assertNotNull(cs.getClassBytes(logger, "java.lang.String"));
- assertNotNull(cs.getClassBytes(logger, "java.lang.Class"));
- assertNotNull(cs.getClassBytes(logger, "com.google.gwt.core.client.GWT"));
- }
-
- // Try deferred binding that works.
- //
- public void testRebindCreateWithSuccess() throws Exception {
- ByteCodeCompiler cs = new ByteCodeCompiler(new TestByteCodeCompilerHost() {
- public String rebind(TreeLogger logger, String typeName)
- throws com.google.gwt.core.ext.UnableToCompleteException {
- if ("test.A".equals(typeName)) {
- return "test.A.B";
- } else {
- return typeName;
- }
- }
- });
-
- assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
- assertNotNull(cs.getClassBytes(logger, "java.lang.String"));
- assertNotNull(cs.getClassBytes(logger, "java.lang.Class"));
- assertNotNull(cs.getClassBytes(logger, "com.google.gwt.core.client.GWT"));
-
- assertNotNull(cs.getClassBytes(logger, "test.Main"));
- assertNotNull(cs.getClassBytes(logger, "test.A"));
- assertNotNull(cs.getClassBytes(logger, "test.A$B"));
-
- // Check again for the same class to make sure it's cached.
- // (Although you have to run this test with "-Dgwt.useGuiLogger" defined
- // to see what it does.)
- //
- assertNotNull(cs.getClassBytes(logger, "java.lang.Object"));
- }
-
- protected void setUp() throws Exception {
- logger = Loggers.createOptionalGuiTreeLogger();
- testHost = new TestByteCodeCompilerHost();
- }
-
- private TreeLogger logger = TreeLogger.NULL;
- private TestByteCodeCompilerHost testHost = null;
-}
diff --git a/dev/core/test/com/google/gwt/dev/jdt/TypeOracleTestingUtils.java b/dev/core/test/com/google/gwt/dev/jdt/TypeOracleTestingUtils.java
deleted file mode 100644
index 1b68679..0000000
--- a/dev/core/test/com/google/gwt/dev/jdt/TypeOracleTestingUtils.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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.jdt;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
-
-/**
- * Utilities for tests that build a type oracle and watch for errors.
- *
- */
-public class TypeOracleTestingUtils {
- public static void addCup(TypeOracleBuilder builder, String typeName,
- CharSequence code) throws UnableToCompleteException {
- CompilationUnitProvider cup = createCup(typeName, code);
- builder.addCompilationUnit(cup);
- }
-
- public static CompilationUnitProvider createCup(String typeName,
- CharSequence code) {
- String packageName;
- String className;
- int pos = typeName.lastIndexOf('.');
- if (pos >= 0) {
- packageName = typeName.substring(0, pos);
- className = typeName.substring(pos + 1);
- } else {
- packageName = "";
- className = typeName;
- }
- StaticCompilationUnitProvider cup = new StaticCompilationUnitProvider(
- packageName, className, code.toString().toCharArray());
- return cup;
- }
-
- /**
- * Add compilation units for basic classes like Object and String.
- */
- public static void addStandardCups(TypeOracleBuilder builder)
- throws UnableToCompleteException {
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.lang;\n");
- code.append("public class Object {\n");
- code.append(" public String toString() { return \"Object\"; }\n");
- code.append(" public Object clone() { return this; } ");
- code.append("}\n");
- addCup(builder, "java.lang.Object", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.lang;\n");
- code.append("public class Class<T> {\n");
- code.append("}\n");
- addCup(builder, "java.lang.Class", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.lang;\n");
- code.append("public final class String {\n");
- code.append(" public int length() { return 0; }\n");
- code.append("}\n");
- addCup(builder, "java.lang.String", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.lang;\n");
- code.append("public interface Serializable { }\n");
- addCup(builder, "java.lang.Serializable", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.util;\n");
- code.append("public interface Map<K,V> { }\n");
- addCup(builder, "java.util.Map", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.lang;\n");
- code.append("public @interface SuppressWarnings {\n");
- code.append(" String[] value();\n");
- code.append("}\n");
- addCup(builder, "java.lang.SuppressWarnings", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package java.lang.annotation;\n");
- code.append("public interface Annotation {\n");
- code.append("}\n");
- addCup(builder, "java.lang.annotation.Annotation", code);
- }
- {
- StringBuffer code = new StringBuffer();
- code.append("package com.google.gwt.core.client;\n");
- code.append("public class JavaScriptObject {\n");
- code.append(" protected JavaScriptObject() { }\n");
- code.append("}\n");
- addCup(builder, "com.google.gwt.core.client.JavaScriptObject", code);
- }
- }
-
- public static void buildTypeOracleForCode(String typeName, CharSequence code,
- TreeLogger testLogger) throws UnableToCompleteException {
- TypeOracleBuilder builder = new TypeOracleBuilder();
- addStandardCups(builder);
- addCup(builder, typeName, code);
- builder.build(testLogger);
- }
-}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
new file mode 100644
index 0000000..6d5e3ee
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
@@ -0,0 +1,208 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarFile;
+
+/**
+ * Shared abstract class for tests that rely on well-known test data.
+ *
+ * These tests rely on the external existence of the following files under
+ * <code>test/com/google/gwt/dev/javac/impl/testdata/</code>
+ *
+ * <pre>
+ * cpe1/com/google/gwt/user/User.gwt.xml
+ * cpe1/com/google/gwt/user/client/Command.java
+ * cpe1/com/google/gwt/user/client/Timer.java
+ * cpe1/com/google/gwt/user/client/ui/Widget.java
+ * cpe1/org/example/bar/client/BarClient1.txt
+ * cpe1/org/example/bar/client/BarClient2.txt
+ * cpe1/org/example/bar/client/etc/BarEtc.txt
+ * cpe1/org/example/foo/client/FooClient.java
+ * cpe1/org/example/foo/server/FooServer.java
+ *
+ * cpe1/com/google/gwt/i18n/I18N.gwt.xml
+ * cpe2/com/google/gwt/i18n/client/Messages.java
+ * cpe2/com/google/gwt/i18n/rebind/LocalizableGenerator.java
+ * cpe2/org/example/bar/client/BarClient2.txt
+ * cpe2/org/example/bar/client/BarClient3.txt
+ * </pre>
+ *
+ * The same files should be present in jar files named cpe1.jar and cpe2.jar;
+ * note that the contents of each will not have the <code>cpe1/</code> and
+ * <code>cpe2/</code> prefixes (respectively) on their contained files.
+ */
+public abstract class AbstractResourceOrientedTestBase extends TestCase {
+
+ private static class ExcludeSvnClassPathEntry extends ClassPathEntry {
+ private final ClassPathEntry cpe;
+
+ public ExcludeSvnClassPathEntry(ClassPathEntry cpe) {
+ this.cpe = cpe;
+ }
+
+ @Override
+ public Set<AbstractResource> findApplicableResources(TreeLogger logger,
+ PathPrefixSet pathPrefixSet) {
+ Set<AbstractResource> results = new HashSet<AbstractResource>();
+ Set<AbstractResource> rs = cpe.findApplicableResources(logger,
+ pathPrefixSet);
+ for (AbstractResource r : rs) {
+ if (r.getPath().indexOf(".svn/") < 0) {
+ results.add(r);
+ }
+ }
+ return results;
+ }
+
+ @Override
+ public String getLocation() {
+ return cpe.getLocation();
+ }
+
+ @Override
+ public String toString() {
+ return cpe.toString();
+ }
+ }
+
+ private static class MOCK_CPE1 extends MockClassPathEntry {
+ public MOCK_CPE1() {
+ super("/cpe1/");
+ addResource("com/google/gwt/user/User.gwt.xml");
+ addResource("com/google/gwt/user/client/Command.java");
+ addResource("com/google/gwt/user/client/Timer.java");
+ addResource("com/google/gwt/user/client/ui/Widget.java");
+ addResource("org/example/bar/client/BarClient1.txt");
+ addResource("org/example/bar/client/BarClient2.txt");
+ addResource("org/example/bar/client/etc/BarEtc.txt");
+ addResource("org/example/foo/client/FooClient.java");
+ addResource("org/example/foo/server/FooServer.java");
+ }
+ }
+
+ private static class MOCK_CPE2 extends MockClassPathEntry {
+ public MOCK_CPE2() {
+ super("C:\\cpe2");
+ addResource("com/google/gwt/i18n/I18N.gwt.xml");
+ addResource("com/google/gwt/i18n/client/Messages.java");
+ addResource("com/google/gwt/i18n/rebind/LocalizableGenerator.java");
+ addResource("org/example/bar/client/BarClient2.txt");
+ addResource("org/example/bar/client/BarClient3.txt");
+ }
+ }
+
+ // Set LOG_TO_CONSOLE to true to see a play-by-play.
+ private static final boolean LOG_TO_CONSOLE = false;
+
+ public static TreeLogger createTestTreeLogger() {
+ if (LOG_TO_CONSOLE) {
+ PrintWriterTreeLogger treeLogger = new PrintWriterTreeLogger();
+ treeLogger.setMaxDetail(TreeLogger.ALL);
+ treeLogger.log(TreeLogger.INFO, "=== logger start ===");
+ return treeLogger;
+ } else {
+ return TreeLogger.NULL;
+ }
+ }
+
+ protected void assertPathIncluded(Set<AbstractResource> resources, String path) {
+ assertNotNull(findResourceWithPath(resources, path));
+ }
+
+ protected void assertPathNotIncluded(Set<AbstractResource> resources,
+ String path) {
+ assertNull(findResourceWithPath(resources, path));
+ }
+
+ protected File findJarDirectory(String name) throws URISyntaxException {
+ ClassLoader classLoader = getClass().getClassLoader();
+ URL url = classLoader.getResource(name);
+ assertNotNull("Expecting on the classpath: " + name);
+ File file = new File(url.toURI());
+ assertTrue("Cannot read as file: " + url.toExternalForm(), file.canRead());
+ return file;
+ }
+
+ protected File findJarFile(String name) throws URISyntaxException {
+ ClassLoader classLoader = getClass().getClassLoader();
+ URL url = classLoader.getResource(name);
+ assertNotNull(
+ "Expecting on the classpath: "
+ + name
+ + "; did you forget to put the source root containing this very source file to the classpath?",
+ url);
+ File file = new File(url.toURI());
+ assertTrue("Cannot read as file: " + url.toExternalForm(), file.canRead());
+ return file;
+ }
+
+ protected Resource findResourceWithPath(Set<AbstractResource> resources,
+ String path) {
+ for (Resource r : resources) {
+ if (r.getPath().equals(path)) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ protected ClassPathEntry getClassPathEntry1AsDirectory()
+ throws URISyntaxException {
+ File dir = findJarDirectory("com/google/gwt/dev/resource/impl/testdata/cpe1");
+ return new ExcludeSvnClassPathEntry(new DirectoryClassPathEntry(dir));
+ }
+
+ protected ClassPathEntry getClassPathEntry1AsJar() throws IOException,
+ URISyntaxException {
+ File file = findJarFile("com/google/gwt/dev/resource/impl/testdata/cpe1.jar");
+ return new ExcludeSvnClassPathEntry(new JarFileClassPathEntry(new JarFile(
+ file)));
+ }
+
+ protected ClassPathEntry getClassPathEntry1AsMock() {
+ return new ExcludeSvnClassPathEntry(new MOCK_CPE1());
+ }
+
+ protected ClassPathEntry getClassPathEntry2AsDirectory()
+ throws URISyntaxException {
+ File dir = findJarDirectory("com/google/gwt/dev/resource/impl/testdata/cpe2");
+ return new ExcludeSvnClassPathEntry(new DirectoryClassPathEntry(dir));
+ }
+
+ protected ClassPathEntry getClassPathEntry2AsJar() throws URISyntaxException,
+ IOException {
+ File file = findJarFile("com/google/gwt/dev/resource/impl/testdata/cpe2.jar");
+ return new ExcludeSvnClassPathEntry(new JarFileClassPathEntry(new JarFile(
+ file)));
+ }
+
+ protected ClassPathEntry getClassPathEntry2AsMock() {
+ return new ExcludeSvnClassPathEntry(new MOCK_CPE2());
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
new file mode 100644
index 0000000..3454176
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
@@ -0,0 +1,262 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Set;
+
+public class ClassPathEntryTest extends AbstractResourceOrientedTestBase {
+
+ public void testAllCpe1FilesFound() throws URISyntaxException, IOException {
+ testAllCpe1FilesFound(getClassPathEntry1AsJar());
+ testAllCpe1FilesFound(getClassPathEntry1AsDirectory());
+ }
+
+ public void testAllCpe2FilesFound() throws URISyntaxException, IOException {
+ testAllCpe2FilesFound(getClassPathEntry2AsJar());
+ testAllCpe2FilesFound(getClassPathEntry2AsDirectory());
+ }
+
+ public void testPathPrefixSetChanges() throws IOException, URISyntaxException {
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testPathPrefixSetChanges(cpe1jar, cpe2jar);
+ testPathPrefixSetChanges(cpe1dir, cpe2dir);
+ testPathPrefixSetChanges(cpe1jar, cpe2dir);
+ testPathPrefixSetChanges(cpe1dir, cpe2jar);
+ }
+
+ public void testUseOfPrefixesWithFiltering() throws IOException,
+ URISyntaxException {
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testUseOfPrefixesWithFiltering(cpe1jar, cpe2jar);
+ testUseOfPrefixesWithFiltering(cpe1dir, cpe2dir);
+ testUseOfPrefixesWithFiltering(cpe1jar, cpe2dir);
+ testUseOfPrefixesWithFiltering(cpe1dir, cpe2jar);
+ }
+
+ public void testUseOfPrefixesWithoutFiltering() throws URISyntaxException,
+ IOException {
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testUseOfPrefixesWithoutFiltering(cpe1jar, cpe2jar);
+ testUseOfPrefixesWithoutFiltering(cpe1dir, cpe2dir);
+ testUseOfPrefixesWithoutFiltering(cpe1jar, cpe2dir);
+ testUseOfPrefixesWithoutFiltering(cpe1dir, cpe2jar);
+ }
+
+ public void testUseOfPrefixesWithoutFiltering(ClassPathEntry cpe1,
+ ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("com/google/gwt/user/client/", null));
+ pps.add(new PathPrefix("com/google/gwt/i18n/client/", null));
+
+ {
+ // Examine cpe1.
+ Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+
+ assertEquals(3, r.size());
+ assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
+ assertPathIncluded(r, "com/google/gwt/user/client/Timer.java");
+ assertPathIncluded(r, "com/google/gwt/user/client/ui/Widget.java");
+ }
+
+ {
+ // Examine cpe2.
+ Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+
+ assertEquals(1, r.size());
+ assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
+ }
+ }
+
+ // NOTE: if this test fails, ensure that the source root containing this very
+ // source file is *FIRST* on the classpath
+ private void testAllCpe1FilesFound(ClassPathEntry cpe1) {
+ TreeLogger logger = createTestTreeLogger();
+
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", null));
+
+ Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+
+ assertEquals(9, r.size());
+ assertPathIncluded(r, "com/google/gwt/user/User.gwt.xml");
+ assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
+ assertPathIncluded(r, "com/google/gwt/user/client/Timer.java");
+ assertPathIncluded(r, "com/google/gwt/user/client/ui/Widget.java");
+ assertPathIncluded(r, "org/example/bar/client/BarClient1.txt");
+ assertPathIncluded(r, "org/example/bar/client/BarClient2.txt");
+ assertPathIncluded(r, "org/example/bar/client/etc/BarEtc.txt");
+ assertPathIncluded(r, "org/example/foo/client/FooClient.java");
+ assertPathIncluded(r, "org/example/foo/server/FooServer.java");
+ }
+
+ // NOTE: if this test fails, ensure that the source root containing this very
+ // source file is on the classpath
+ private void testAllCpe2FilesFound(ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", null));
+ Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+
+ assertEquals(5, r.size());
+ assertPathIncluded(r, "com/google/gwt/i18n/I18N.gwt.xml");
+ assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
+ assertPathIncluded(r,
+ "com/google/gwt/i18n/rebind/LocalizableGenerator.java");
+ assertPathIncluded(r, "org/example/bar/client/BarClient2.txt");
+ assertPathIncluded(r, "org/example/bar/client/BarClient3.txt");
+ }
+
+ private void testPathPrefixSetChanges(ClassPathEntry cpe1, ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ {
+ // Filter is not set yet.
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("com/google/gwt/user/", null));
+ pps.add(new PathPrefix("com/google/gwt/i18n/", null));
+
+ // Examine cpe1 in the absence of the filter.
+ Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+
+ assertEquals(4, r1.size());
+ assertPathIncluded(r1, "com/google/gwt/user/User.gwt.xml");
+ assertPathIncluded(r1, "com/google/gwt/user/client/Command.java");
+ assertPathIncluded(r1, "com/google/gwt/user/client/Timer.java");
+ assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
+
+ // Examine cpe2 in the absence of the filter.
+ Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+
+ assertEquals(3, r2.size());
+ assertPathIncluded(r2, "com/google/gwt/i18n/I18N.gwt.xml");
+ assertPathIncluded(r2, "com/google/gwt/i18n/client/Messages.java");
+ assertPathIncluded(r2,
+ "com/google/gwt/i18n/rebind/LocalizableGenerator.java");
+ }
+
+ {
+ // Create a pps with a filter.
+ ResourceFilter excludeXmlFiles = new ResourceFilter() {
+ public boolean allows(String path) {
+ return !path.endsWith(".xml");
+ }
+ };
+
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("com/google/gwt/user/", excludeXmlFiles));
+ pps.add(new PathPrefix("com/google/gwt/i18n/", excludeXmlFiles));
+
+ // Examine cpe1 in the presence of the filter.
+ Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+
+ assertEquals(3, r1.size());
+ assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
+ assertPathIncluded(r1, "com/google/gwt/user/client/Command.java");
+ assertPathIncluded(r1, "com/google/gwt/user/client/Timer.java");
+ assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
+
+ // Examine cpe2 in the presence of the filter.
+ Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+
+ assertEquals(2, r2.size());
+ assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
+ assertPathIncluded(r2, "com/google/gwt/i18n/client/Messages.java");
+ assertPathIncluded(r2,
+ "com/google/gwt/i18n/rebind/LocalizableGenerator.java");
+ }
+
+ {
+ /*
+ * Change the prefix path set to the zero-lenth prefix (which allows
+ * everything), but specify a filter that disallows everything.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", new ResourceFilter() {
+ public boolean allows(String path) {
+ // Exclude everything.
+ return false;
+ }
+ }));
+
+ // Examine cpe1 in the presence of the filter.
+ Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+
+ assertEquals(0, r1.size());
+
+ // Examine cpe2 in the presence of the filter.
+ Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+
+ assertEquals(0, r2.size());
+ }
+ }
+
+ private void testUseOfPrefixesWithFiltering(ClassPathEntry cpe1,
+ ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ PathPrefixSet pps = new PathPrefixSet();
+ ResourceFilter excludeXmlFiles = new ResourceFilter() {
+ public boolean allows(String path) {
+ return !path.endsWith(".xml");
+ }
+ };
+ // The prefix is intentionally starting at the module-level, not 'client'.
+ pps.add(new PathPrefix("com/google/gwt/user/", excludeXmlFiles));
+ pps.add(new PathPrefix("com/google/gwt/i18n/", excludeXmlFiles));
+
+ {
+ // Examine cpe1.
+ Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+
+ assertEquals(3, r.size());
+ // User.gwt.xml would be included but for the filter.
+ assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
+ assertPathIncluded(r, "com/google/gwt/user/client/Timer.java");
+ assertPathIncluded(r, "com/google/gwt/user/client/ui/Widget.java");
+ }
+
+ {
+ // Examine cpe2.
+ Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+
+ assertEquals(2, r.size());
+ // I18N.gwt.xml would be included but for the filter.
+ assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
+ assertPathIncluded(r,
+ "com/google/gwt/i18n/rebind/LocalizableGenerator.java");
+ }
+ }
+
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/FileResourceTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/FileResourceTest.java
new file mode 100644
index 0000000..7a38934
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/FileResourceTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.dev.util.Util;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+
+public class FileResourceTest extends TestCase {
+
+ public void testDeletion() {
+ File f = null;
+ try {
+ f = File.createTempFile("com.google.gwt.dev.javac.impl.FileResourceTest",
+ ".tmp");
+ f.deleteOnExit();
+ Util.writeStringAsFile(f, "contents 1");
+ } catch (IOException e) {
+ fail("Failed to create test file");
+ }
+
+ File dir = f.getParentFile();
+ DirectoryClassPathEntry cpe = new DirectoryClassPathEntry(dir);
+ FileResource r = new FileResource(cpe, f.getName(), f);
+ assertEquals(f.getAbsoluteFile().toURI().toString(), r.getLocation());
+
+ /*
+ * In this case, there's no subdirectory, so the path should match the
+ * simple filename.
+ */
+ assertEquals(f.getName(), r.getPath());
+
+ // Shouldn't be stale yet.
+ assertFalse(r.isStale());
+
+ /*
+ * Touch the file at more than one second to ensure there's a noticeable
+ * difference on every platform.
+ */
+ f.setLastModified(f.lastModified() + 1500);
+
+ // Should be stale now.
+ assertTrue(r.isStale());
+ }
+
+ public void testModification() {
+ File f = null;
+ try {
+ f = File.createTempFile("com.google.gwt.dev.javac.impl.FileResourceTest",
+ ".tmp");
+ f.deleteOnExit();
+ Util.writeStringAsFile(f, "contents 1");
+ } catch (IOException e) {
+ fail("Failed to create test file");
+ }
+
+ File dir = f.getParentFile();
+ DirectoryClassPathEntry cpe = new DirectoryClassPathEntry(dir);
+ FileResource r = new FileResource(cpe, f.getName(), f);
+ assertEquals(f.getAbsoluteFile().toURI().toString(), r.getLocation());
+
+ /*
+ * In this case, there's no subdirectory, so the path should match the
+ * simple filename.
+ */
+ assertEquals(f.getName(), r.getPath());
+
+ // Shouldn't be stale yet.
+ assertFalse(r.isStale());
+
+ // Delete the file.
+ f.delete();
+
+ // Should be stale now.
+ assertTrue(r.isStale());
+
+ // Get can't contents anymore, either.
+ assertNull(r.openContents());
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java b/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java
new file mode 100644
index 0000000..25de30f
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java
@@ -0,0 +1,67 @@
+/*
+ * 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.resource.impl;
+
+import junit.framework.Assert;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public final class MockAbstractResource extends AbstractResource {
+ private boolean isStale;
+ private final MockClassPathEntry mockClassPathEntry;
+ private final String path;
+
+ public MockAbstractResource(MockClassPathEntry mockClassPathEntry, String path) {
+ this.mockClassPathEntry = mockClassPathEntry;
+ this.path = path;
+ }
+
+ @Override
+ public ClassPathEntry getClassPathEntry() {
+ return this.mockClassPathEntry;
+ }
+
+ @Override
+ public String getLocation() {
+ return this.mockClassPathEntry.pathRoot + "/" + path;
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public URL getURL() {
+ return null;
+ }
+
+ @Override
+ public boolean isStale() {
+ return isStale;
+ }
+
+ @Override
+ public InputStream openContents() {
+ Assert.fail("Not implemented");
+ return null;
+ }
+
+ public void setStale(boolean isStale) {
+ this.isStale = isStale;
+ }
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java b/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
new file mode 100644
index 0000000..913b071
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
@@ -0,0 +1,89 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class MockClassPathEntry extends ClassPathEntry {
+
+ final String pathRoot;
+ private final Map<String, MockAbstractResource> resourceMap = new HashMap<String, MockAbstractResource>();
+
+ /**
+ * By default, MockClassPathEntry has an all-inclusive path prefix. Tests may
+ * change it by calling {@link #setPathPrefixes(PathPrefixSet)}.
+ */
+ public MockClassPathEntry(String pathRoot) {
+ this.pathRoot = pathRoot;
+ }
+
+ public void addResource(String resourcePath) {
+ Resource old = resourceMap.get(resourcePath);
+ Assert.assertNull(
+ "resource already exists; use updateResource() to replace", old);
+ resourceMap.put(resourcePath, createMockResource(resourcePath));
+ }
+
+ @Override
+ public Set<AbstractResource> findApplicableResources(TreeLogger logger,
+ PathPrefixSet pathPrefixes) {
+ // Only include resources that have the prefix and pass its filter.
+ HashSet<AbstractResource> results = new HashSet<AbstractResource>();
+ for (Map.Entry<String, MockAbstractResource> entry : resourceMap.entrySet()) {
+ String path = entry.getKey();
+ if (pathPrefixes.includesResource(path)) {
+ results.add(entry.getValue());
+ }
+ }
+
+ return results;
+ }
+
+ @Override
+ public String getLocation() {
+ return pathRoot;
+ }
+
+ public void removeResource(String resourcePath) {
+ Resource old = resourceMap.get(resourcePath);
+ Assert.assertNotNull(
+ "resource does not already exists; use addResource() to add it first",
+ old);
+ resourceMap.remove(resourcePath);
+ }
+
+ public void updateResource(String resourcePath) {
+ MockAbstractResource old = resourceMap.get(resourcePath);
+ Assert.assertNotNull(
+ "resource does not already exists; use addResource() if you were trying to add",
+ old);
+ old.setStale(true);
+ resourceMap.put(resourcePath, createMockResource(resourcePath));
+ }
+
+ private MockAbstractResource createMockResource(final String path) {
+ return new MockAbstractResource(this, path);
+ }
+
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
new file mode 100644
index 0000000..e9d581c
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.resource.impl;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the trie and filtering behavior of path prefix set.
+ */
+public class PathPrefixSetTest extends TestCase {
+
+ public void testEmptyPrefixSet() {
+ PathPrefixSet pps = new PathPrefixSet();
+ assertFalse(pps.includesResource("com/google/gwt/user/client/Command.java"));
+ }
+
+ public void testNonOverlappingPrefixes() {
+ {
+ /*
+ * Test with null filters to ensure nothing gets filtered out.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("com/google/gwt/user/client/", null));
+ pps.add(new PathPrefix("com/google/gwt/i18n/client/", null));
+ pps.add(new PathPrefix("com/google/gwt/dom/client/", null));
+
+ assertTrue(pps.includesDirectory("com/"));
+ assertTrue(pps.includesDirectory("com/google/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/user/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/user/client/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/user/client/ui/"));
+
+ assertFalse(pps.includesDirectory("org/"));
+ assertFalse(pps.includesDirectory("org/example/"));
+ assertFalse(pps.includesDirectory("com/google/gwt/user/server/"));
+ assertFalse(pps.includesDirectory("com/google/gwt/xml/client/"));
+
+ assertTrue(pps.includesResource("com/google/gwt/user/client/Command.java"));
+ assertTrue(pps.includesResource("com/google/gwt/user/client/Timer.java"));
+ assertTrue(pps.includesResource("com/google/gwt/i18n/client/Messages.java"));
+ assertTrue(pps.includesResource("com/google/gwt/dom/client/DivElement.java"));
+
+ assertFalse(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
+ assertFalse(pps.includesResource("com/google/gwt/sample/hello/client/Hello.java"));
+ assertFalse(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
+ }
+
+ {
+ /*
+ * Test with a real filter to ensure it does have an effect.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ ResourceFilter allowsGifs = new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.toLowerCase().endsWith(".gif");
+ }
+ };
+
+ pps.add(new PathPrefix("com/google/gwt/user/public/", allowsGifs));
+ pps.add(new PathPrefix("com/google/gwt/sample/mail/public/", allowsGifs));
+
+ // Correct prefix, and filter should allow .
+ assertTrue(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
+ assertTrue(pps.includesResource("com/google/gwt/sample/mail/public/inboxIcon.gif"));
+
+ // Correct prefix, but filter should exclude.
+ assertFalse(pps.includesResource("com/google/gwt/user/public/README.txt"));
+ assertFalse(pps.includesResource("com/google/gwt/sample/mail/public/README.txt"));
+
+ // Wrong prefix, and filter would have excluded.
+ assertFalse(pps.includesResource("com/google/gwt/user/client/Command.java"));
+ assertFalse(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
+
+ // Wrong prefix, but filter would have allowed it.
+ assertFalse(pps.includesResource("com/google/gwt/i18n/public/flags.gif"));
+ }
+ }
+
+ public void testOverlappingPrefixes() {
+ {
+ /*
+ * Without a filter.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", null));
+ pps.add(new PathPrefix("a/", null));
+ pps.add(new PathPrefix("a/b/", null));
+ pps.add(new PathPrefix("a/b/c/", null));
+
+ assertTrue(pps.includesResource("W.java"));
+ assertTrue(pps.includesResource("a/X.java"));
+ assertTrue(pps.includesResource("a/b/Y.java"));
+ assertTrue(pps.includesResource("a/b/c/Z.java"));
+ assertTrue(pps.includesResource("a/b/c/d/V.java"));
+ }
+
+ {
+ /*
+ * Ensure the right filter applies.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", null));
+ pps.add(new PathPrefix("a/", null));
+ pps.add(new PathPrefix("a/b/", new ResourceFilter() {
+ public boolean allows(String path) {
+ // Disallow anything ending with "FILTERMEOUT".
+ return !path.endsWith("FILTERMEOUT");
+ }
+ }));
+ pps.add(new PathPrefix("a/b/c/", null));
+
+ assertTrue(pps.includesResource("W.java"));
+ assertTrue(pps.includesResource("a/X.java"));
+ assertTrue(pps.includesResource("a/b/Y.java"));
+ // This should be gone, since it is found in b.
+ assertFalse(pps.includesResource("a/b/FILTERMEOUT"));
+ /*
+ * This should not be gone, because it is using c's (null) filter instead
+ * of b's. The logic here is that the prefix including c is more specific
+ * and seemed to want c's resources to be included.
+ */
+ assertTrue(pps.includesResource("a/b/c/DONT_FILTERMEOUT"));
+ assertTrue(pps.includesResource("a/b/c/Z.java"));
+ assertTrue(pps.includesResource("a/b/c/d/V.java"));
+ }
+ }
+
+ /**
+ * In essense, this tests support for the default package in Java.
+ */
+ public void testZeroLengthPrefix() {
+ {
+ /*
+ * Without a filter.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", null));
+
+ assertTrue(pps.includesResource("W.java"));
+ assertTrue(pps.includesResource("a/X.java"));
+ assertTrue(pps.includesResource("a/b/Y.java"));
+ assertTrue(pps.includesResource("a/b/c/Z.java"));
+ }
+
+ {
+ /*
+ * With a filter.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("", new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith("Y.java");
+ }
+ }));
+
+ assertFalse(pps.includesResource("W.java"));
+ assertFalse(pps.includesResource("a/X.java"));
+ assertTrue(pps.includesResource("a/b/Y.java"));
+ assertFalse(pps.includesResource("a/b/c/Z.java"));
+
+ }
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplRealClasspathTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplRealClasspathTest.java
new file mode 100644
index 0000000..2d228bc
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplRealClasspathTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+
+import java.util.Map;
+
+/**
+ * Tests {@link ResourceOracleImpl} using the real class path.
+ *
+ */
+public class ResourceOracleImplRealClasspathTest extends
+ AbstractResourceOrientedTestBase {
+
+ private static final PathPrefix JUNIT_PREFIX = new PathPrefix(
+ "junit/framework/", new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith("TestCase.class");
+ }
+ });
+ private static final PathPrefix JUNIT_PREFIX_DUP = new PathPrefix(
+ "junit/framework/", new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith("TestCase.class");
+ }
+ });
+
+ private static final PathPrefix THIS_CLASS_PREFIX = new PathPrefix(
+ "com/google/gwt/dev/resource/impl/", new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith("ResourceOracleImplRealClasspathTest.class");
+ }
+ });
+
+ private static final PathPrefix THIS_CLASS_PREFIX_PLUS = new PathPrefix(
+ "com/google/gwt/dev/resource/impl/", new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith("ResourceOracleImpl.class")
+ || path.endsWith("ResourceOracleImplRealClasspathTest.class");
+ }
+ });
+
+ private final TreeLogger logger = createTestTreeLogger();
+ private final ResourceOracleImpl resourceOracle = new ResourceOracleImpl(
+ logger);
+
+ public void testBasic() {
+ PathPrefixSet pathPrefixSet = new PathPrefixSet();
+ pathPrefixSet.add(JUNIT_PREFIX);
+ pathPrefixSet.add(THIS_CLASS_PREFIX);
+ resourceOracle.setPathPrefixes(pathPrefixSet);
+ resourceOracle.refresh(logger);
+ Map<String, Resource> resourceMap = resourceOracle.getResourceMap();
+ assertEquals(2, resourceMap.size());
+ }
+
+ public void testRefresh() {
+ PathPrefixSet pathPrefixSet = new PathPrefixSet();
+ pathPrefixSet.add(JUNIT_PREFIX);
+ pathPrefixSet.add(THIS_CLASS_PREFIX);
+ resourceOracle.setPathPrefixes(pathPrefixSet);
+ resourceOracle.refresh(logger);
+ Map<String, Resource> resourceMap = resourceOracle.getResourceMap();
+ assertEquals(2, resourceMap.size());
+
+ // Plain refresh should have no effect.
+ resourceOracle.refresh(logger);
+ assertSame(resourceMap, resourceOracle.getResourceMap());
+
+ // Setting same path entries should have no effect.
+ resourceOracle.setPathPrefixes(pathPrefixSet);
+ resourceOracle.refresh(logger);
+ assertSame(resourceMap, resourceOracle.getResourceMap());
+
+ // Setting identical path entries should have no effect.
+ pathPrefixSet = new PathPrefixSet();
+ pathPrefixSet.add(JUNIT_PREFIX);
+ pathPrefixSet.add(THIS_CLASS_PREFIX);
+ resourceOracle.setPathPrefixes(pathPrefixSet);
+ resourceOracle.refresh(logger);
+ assertSame(resourceMap, resourceOracle.getResourceMap());
+
+ // Setting identical result should have no effect.
+ pathPrefixSet.add(JUNIT_PREFIX_DUP);
+ resourceOracle.refresh(logger);
+ assertSame(resourceMap, resourceOracle.getResourceMap());
+
+ // Actually change the working set.
+ pathPrefixSet.add(THIS_CLASS_PREFIX_PLUS);
+ resourceOracle.refresh(logger);
+ Map<String, Resource> newResourceMap = resourceOracle.getResourceMap();
+ assertNotSame(resourceMap, newResourceMap);
+ assertEquals(3, newResourceMap.size());
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
new file mode 100644
index 0000000..c6fe7e0
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
@@ -0,0 +1,491 @@
+/*
+ * 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.resource.impl;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.util.tools.Utility;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests {@link ResourceOracleImpl}.
+ *
+ * <pre>
+ * Important states to test:
+ * - No class path entries
+ * - A single class path entries
+ * - init/add/update/remove
+ * - Multiple class path entries
+ * - init/add/update/remove
+ * - same as previous with shadowing
+ * - same as previous with superceding
+ * </pre>
+ */
+public class ResourceOracleImplTest extends AbstractResourceOrientedTestBase {
+
+ // Starts empty but can change during tests.
+ private static class MOCK_CPE0 extends MockClassPathEntry {
+ public MOCK_CPE0() {
+ super("/cpe0/");
+ }
+ }
+
+ private static class MOCK_CPE3 extends MockClassPathEntry {
+ public MOCK_CPE3() {
+ super("/cpe3/");
+ }
+ }
+
+ private static class ResourceOracleSnapshot {
+ private final Set<Resource> resources;
+ private final Map<String, Resource> resourceMap;
+ private final Set<String> pathNames;
+
+ public ResourceOracleSnapshot(ResourceOracleImpl oracle) {
+ resources = oracle.getResources();
+ resourceMap = oracle.getResourceMap();
+ pathNames = oracle.getPathNames();
+ }
+
+ public void assertCollectionsConsistent(int expectedSize) {
+ assertEquals(expectedSize, resources.size());
+ assertEquals(resources.size(), resourceMap.size());
+ assertEquals(resources.size(), pathNames.size());
+
+ // Ensure every resource is in the map correctly.
+ for (Resource r : resources) {
+ assertSame(r, resourceMap.get(r.getPath()));
+ }
+
+ // Ensure that every resource path is in the set.
+ for (Resource r : resources) {
+ assertTrue(pathNames.contains(r.getPath()));
+ }
+ }
+
+ public void assertNotSameCollections(ResourceOracleSnapshot other) {
+ assertNotSame(resourceMap, other.resourceMap);
+ assertNotSame(resources, other.resources);
+ assertNotSame(pathNames, other.pathNames);
+ }
+
+ public void assertPathIncluded(String path) {
+ assertNotNull(findResourceWithPath(path));
+ }
+
+ /**
+ * Asserts that a resource having the specified path is present and that it
+ * was contributed by the specified classpath entry.
+ */
+ public void assertPathIncluded(String expectedPath,
+ ClassPathEntry expectedCpe) {
+ AbstractResource r = findResourceWithPath(expectedPath);
+ assertNotNull(r);
+ ClassPathEntry actualCpe = r.getClassPathEntry();
+ assertEquals(expectedCpe.getLocation(), actualCpe.getLocation());
+ }
+
+ public void assertPathNotIncluded(String path) {
+ assertNull(findResourceWithPath(path));
+ }
+
+ public void assertSameCollections(ResourceOracleSnapshot other) {
+ assertSame(resourceMap, other.resourceMap);
+ assertSame(resources, other.resources);
+ assertSame(pathNames, other.pathNames);
+ }
+
+ public AbstractResource findResourceWithPath(String path) {
+ for (Resource r : resources) {
+ if (r.getPath().equals(path)) {
+ return (AbstractResource) r;
+ }
+ }
+ return null;
+ }
+ }
+
+ public void testNoClassPathEntries() {
+ TreeLogger logger = createTestTreeLogger();
+ ResourceOracleImpl oracle = createResourceOracle(new MOCK_CPE0());
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
+ s.assertCollectionsConsistent(0);
+ }
+
+ /**
+ * Tests the actual reading of resources.
+ *
+ * @throws URISyntaxException
+ * @throws IOException
+ * @throws UnableToCompleteException
+ */
+ public void testReadingResource() throws IOException, URISyntaxException {
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testReadingResource(cpe1jar, cpe2jar);
+ testReadingResource(cpe1dir, cpe2jar);
+
+ testReadingResource(cpe1jar, cpe2dir);
+ testReadingResource(cpe1dir, cpe2dir);
+ }
+
+ public void testResourceAddition() throws IOException, URISyntaxException {
+ ClassPathEntry cpe1mock = getClassPathEntry1AsMock();
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+
+ ClassPathEntry cpe2mock = getClassPathEntry2AsMock();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testResourceAddition(cpe1jar, cpe2jar);
+ testResourceAddition(cpe1dir, cpe2jar);
+ testResourceAddition(cpe1mock, cpe2jar);
+
+ testResourceAddition(cpe1jar, cpe2dir);
+ testResourceAddition(cpe1dir, cpe2dir);
+ testResourceAddition(cpe1mock, cpe2dir);
+
+ testResourceAddition(cpe1jar, cpe2mock);
+ testResourceAddition(cpe1dir, cpe2mock);
+ testResourceAddition(cpe1mock, cpe2mock);
+ }
+
+ public void testResourceDeletion() throws IOException, URISyntaxException {
+ ClassPathEntry cpe1mock = getClassPathEntry1AsMock();
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+
+ ClassPathEntry cpe2mock = getClassPathEntry2AsMock();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testResourceDeletion(cpe1jar, cpe2jar);
+ testResourceDeletion(cpe1dir, cpe2jar);
+ testResourceDeletion(cpe1mock, cpe2jar);
+
+ testResourceDeletion(cpe1jar, cpe2dir);
+ testResourceDeletion(cpe1dir, cpe2dir);
+ testResourceDeletion(cpe1mock, cpe2dir);
+
+ testResourceDeletion(cpe1jar, cpe2mock);
+ testResourceDeletion(cpe1dir, cpe2mock);
+ testResourceDeletion(cpe1mock, cpe2mock);
+ }
+
+ public void testResourceModification() throws IOException, URISyntaxException {
+ ClassPathEntry cpe1mock = getClassPathEntry1AsMock();
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
+
+ ClassPathEntry cpe2mock = getClassPathEntry2AsMock();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+ ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
+
+ testResourceModification(cpe1jar, cpe2jar);
+ testResourceModification(cpe1dir, cpe2jar);
+ testResourceModification(cpe1mock, cpe2jar);
+
+ testResourceModification(cpe1jar, cpe2dir);
+ testResourceModification(cpe1dir, cpe2dir);
+ testResourceModification(cpe1mock, cpe2dir);
+
+ testResourceModification(cpe1jar, cpe2mock);
+ testResourceModification(cpe1dir, cpe2mock);
+ testResourceModification(cpe1mock, cpe2mock);
+
+ /*
+ * TODO(bruce): figure out a good way to test real resource modifications of
+ * jar files and directories
+ */
+ }
+
+ /**
+ * Creates an array of class path entries, setting up each one with a
+ * well-known set of client prefixes.
+ *
+ * @param entries
+ * @return
+ */
+ private ResourceOracleImpl createResourceOracle(ClassPathEntry... entries) {
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(new PathPrefix("com/google/gwt/user/client/", null));
+ pps.add(new PathPrefix("org/example/bar/client/", null));
+ pps.add(new PathPrefix("org/example/foo/client/", null));
+ pps.add(new PathPrefix("com/google/gwt/i18n/client/", null));
+
+ List<ClassPathEntry> classPath = new ArrayList<ClassPathEntry>();
+ for (ClassPathEntry entry : entries) {
+ classPath.add(entry);
+ }
+ ResourceOracleImpl oracle = new ResourceOracleImpl(classPath);
+ oracle.setPathPrefixes(pps);
+ return oracle;
+ }
+
+ private ResourceOracleSnapshot refreshAndSnapshot(TreeLogger logger,
+ ResourceOracleImpl oracle) {
+ oracle.refresh(logger);
+ return new ResourceOracleSnapshot(oracle);
+ }
+
+ private void testReadingResource(ClassPathEntry cpe1, ClassPathEntry cpe2)
+ throws IOException {
+ TreeLogger logger = createTestTreeLogger();
+
+ ResourceOracleImpl oracle = createResourceOracle(cpe1, cpe2);
+
+ oracle.refresh(logger);
+ ResourceOracleSnapshot s = new ResourceOracleSnapshot(oracle);
+ s.assertCollectionsConsistent(9);
+ s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe1);
+ s.assertPathIncluded("com/google/gwt/i18n/client/Messages.java", cpe2);
+
+ {
+ /*
+ * Read a resource in cpe1.
+ */
+ AbstractResource res = s.findResourceWithPath("com/google/gwt/user/client/Command.java");
+ BufferedReader rdr = null;
+ try {
+ InputStream is = res.openContents();
+ assertNotNull(is);
+ rdr = new BufferedReader(new InputStreamReader(is));
+ assertTrue(rdr.readLine().indexOf(
+ "package com.google.gwt.dev.resource.impl.testdata.cpe1.com.google.gwt.user.client;") >= 0);
+ } finally {
+ Utility.close(rdr);
+ }
+ }
+
+ {
+ /*
+ * Read a resource in cpe2.
+ */
+ AbstractResource res = s.findResourceWithPath("com/google/gwt/i18n/client/Messages.java");
+ BufferedReader rdr = null;
+ try {
+ InputStream is = res.openContents();
+ assertNotNull(is);
+ rdr = new BufferedReader(new InputStreamReader(is));
+ assertTrue(rdr.readLine().indexOf(
+ "package com.google.gwt.dev.resource.impl.testdata.cpe2.com.google.gwt.i18n.client;") >= 0);
+ } finally {
+ Utility.close(rdr);
+ }
+ }
+
+ {
+ /*
+ * TODO: Try to read an invalid resource and watch it fail as intended.
+ */
+ }
+ }
+
+ private void testResourceAddition(ClassPathEntry cpe1, ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ MOCK_CPE0 cpe0 = new MOCK_CPE0();
+ MOCK_CPE3 cpe3 = new MOCK_CPE3();
+ ResourceOracleImpl oracle = createResourceOracle(cpe0, cpe1, cpe2, cpe3);
+
+ {
+ /*
+ * Ensure it's correct as a baseline. These tests have hard-coded
+ * assumptions about the contents of each classpath entry.
+ */
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
+ s.assertCollectionsConsistent(9);
+ s.assertPathIncluded("com/google/gwt/user/client/Command.java");
+ s.assertPathIncluded("com/google/gwt/user/client/Timer.java");
+ s.assertPathIncluded("com/google/gwt/user/client/ui/Widget.java");
+ s.assertPathIncluded("org/example/bar/client/BarClient1.txt");
+ s.assertPathIncluded("org/example/bar/client/BarClient2.txt");
+ s.assertPathIncluded("org/example/bar/client/BarClient3.txt");
+ s.assertPathIncluded("org/example/bar/client/etc/BarEtc.txt");
+ s.assertPathIncluded("org/example/foo/client/FooClient.java");
+ s.assertPathIncluded("com/google/gwt/i18n/client/Messages.java");
+ }
+
+ {
+ /*
+ * Add duplicate resources later in the classpath, which won't be found.
+ * Consequently, the collections' identities should not change.
+ */
+ cpe3.addResource("com/google/gwt/user/client/Command.java");
+ cpe3.addResource("com/google/gwt/user/client/Timer.java");
+ cpe3.addResource("com/google/gwt/bar/client/etc/BarEtc.txt");
+
+ ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
+ after.assertCollectionsConsistent(9);
+ after.assertSameCollections(before);
+ }
+
+ {
+ /*
+ * Add a unique resource later in the classpath, which will be found.
+ * Consequently, the collections' identities should change.
+ */
+ cpe3.addResource("com/google/gwt/i18n/client/Constants.java");
+
+ ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
+ after.assertCollectionsConsistent(10);
+ after.assertNotSameCollections(before);
+ after.assertPathIncluded("com/google/gwt/i18n/client/Constants.java");
+ }
+ }
+
+ private void testResourceDeletion(ClassPathEntry cpe1, ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ MOCK_CPE0 cpe0 = new MOCK_CPE0();
+ MOCK_CPE3 cpe3 = new MOCK_CPE3();
+ ResourceOracleImpl oracle = createResourceOracle(cpe0, cpe1, cpe2, cpe3);
+
+ /*
+ * Intentionally add some duplicate resources.
+ */
+ cpe0.addResource("com/google/gwt/user/client/Command.java");
+ cpe0.addResource("com/google/gwt/i18n/client/Constants.java");
+ cpe3.addResource("com/google/gwt/user/client/Command.java");
+ cpe3.addResource("com/google/gwt/i18n/client/Constants.java");
+
+ {
+ /*
+ * Ensure it's correct as a baseline. These tests have hard-coded
+ * assumptions about the contents of each classpath entry.
+ */
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
+ s.assertCollectionsConsistent(10);
+ s.assertPathIncluded("com/google/gwt/user/client/Command.java");
+ s.assertPathIncluded("com/google/gwt/user/client/Timer.java");
+ s.assertPathIncluded("com/google/gwt/user/client/ui/Widget.java");
+ s.assertPathIncluded("org/example/bar/client/BarClient1.txt");
+ s.assertPathIncluded("org/example/bar/client/BarClient2.txt");
+ s.assertPathIncluded("org/example/bar/client/BarClient3.txt");
+ s.assertPathIncluded("org/example/bar/client/etc/BarEtc.txt");
+ s.assertPathIncluded("org/example/foo/client/FooClient.java");
+ s.assertPathIncluded("com/google/gwt/i18n/client/Messages.java");
+ s.assertPathIncluded("com/google/gwt/i18n/client/Constants.java");
+ }
+
+ {
+ /*
+ * Remove a shadowed resource, which shouldn't have been found anyway.
+ * Consequently, the collections' identities should not change.
+ */
+ cpe3.removeResource("com/google/gwt/user/client/Command.java");
+ cpe3.removeResource("com/google/gwt/i18n/client/Constants.java");
+
+ ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
+ after.assertCollectionsConsistent(10);
+ after.assertSameCollections(before);
+ }
+
+ {
+ /*
+ * Remove a unique resource, which will no longer be found. We also add a
+ * new one to ensure that lack of size change doesn't confuse anything.
+ * Consequently, the collections' identities should change.
+ */
+ cpe0.removeResource("com/google/gwt/i18n/client/Constants.java");
+ cpe3.addResource("com/google/gwt/user/client/Window.java");
+
+ ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
+ after.assertCollectionsConsistent(10);
+ after.assertNotSameCollections(before);
+ after.assertPathIncluded("com/google/gwt/user/client/Window.java");
+ after.assertPathNotIncluded("com/google/gwt/i18n/client/Constants.java");
+ }
+ }
+
+ private void testResourceModification(ClassPathEntry cpe1, ClassPathEntry cpe2) {
+ TreeLogger logger = createTestTreeLogger();
+
+ MOCK_CPE0 cpe0 = new MOCK_CPE0();
+ MOCK_CPE3 cpe3 = new MOCK_CPE3();
+ ResourceOracleImpl oracle = createResourceOracle(cpe0, cpe1, cpe2, cpe3);
+
+ {
+ /*
+ * Baseline assumptions about the set of resources present by default.
+ */
+ oracle.refresh(logger);
+ ResourceOracleSnapshot s = new ResourceOracleSnapshot(oracle);
+ s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe1);
+ s.assertPathIncluded("com/google/gwt/user/client/Timer.java", cpe1);
+ }
+
+ // Add intentionally duplicate resources.
+ cpe0.addResource("com/google/gwt/user/client/Command.java");
+ cpe3.addResource("com/google/gwt/user/client/Timer.java");
+
+ {
+ /*
+ * Ensure that the dups have the effect we expect.
+ */
+ oracle.refresh(logger);
+ ResourceOracleSnapshot s = new ResourceOracleSnapshot(oracle);
+ s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe0);
+ s.assertPathIncluded("com/google/gwt/user/client/Timer.java", cpe1);
+ }
+
+ {
+ /*
+ * Change a mock resource that was shadowed to ensure that the change
+ * isn't observed.
+ */
+ ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
+ before.assertCollectionsConsistent(9);
+
+ cpe3.updateResource("com/google/gwt/user/client/Timer.java");
+
+ ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
+ after.assertSameCollections(before);
+ }
+
+ {
+ /*
+ * Change a mock resource that was not shadowed to ensure that the change
+ * is observed.
+ */
+ ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
+ before.assertCollectionsConsistent(9);
+
+ cpe0.updateResource("com/google/gwt/user/client/Command.java");
+
+ ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
+ after.assertNotSameCollections(before);
+ }
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
new file mode 100644
index 0000000..5045c12
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
Binary files differ
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/User.gwt.xml b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/User.gwt.xml
new file mode 100644
index 0000000..bdf08de
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/User.gwt.xml
@@ -0,0 +1 @@
+test file
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/Command.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/Command.java
new file mode 100644
index 0000000..42ba14b
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/Command.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe1.com.google.gwt.user.client;
+
+public class Command {
+ // test class
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/Timer.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/Timer.java
new file mode 100644
index 0000000..d845e45
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/Timer.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe1.com.google.gwt.user.client;
+
+public class Timer {
+ // test class
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/ui/Widget.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/ui/Widget.java
new file mode 100644
index 0000000..79acdc7
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/com/google/gwt/user/client/ui/Widget.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe1.com.google.gwt.user.client.ui;
+
+public class Widget {
+ // test class
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/BarClient1.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/BarClient1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/BarClient1.txt
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/BarClient2.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/BarClient2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/BarClient2.txt
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/etc/BarEtc.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/etc/BarEtc.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/bar/client/etc/BarEtc.txt
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/client/FooClient.java
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1/org/example/foo/server/FooServer.java
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
new file mode 100644
index 0000000..08761bb
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
Binary files differ
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/I18N.gwt.xml b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/I18N.gwt.xml
new file mode 100644
index 0000000..bdf08de
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/I18N.gwt.xml
@@ -0,0 +1 @@
+test file
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/client/Messages.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/client/Messages.java
new file mode 100644
index 0000000..dff41a8
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/client/Messages.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe2.com.google.gwt.i18n.client;
+
+public class Messages {
+ // test class
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/rebind/LocalizableGenerator.java b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/rebind/LocalizableGenerator.java
new file mode 100644
index 0000000..dae8c55
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/com/google/gwt/i18n/rebind/LocalizableGenerator.java
@@ -0,0 +1,5 @@
+package com.google.gwt.dev.resource.impl.testdata.cpe2.com.google.gwt.i18n.rebind;
+
+public class LocalizableGenerator {
+ // test class
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/bar/client/BarClient2.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/bar/client/BarClient2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/bar/client/BarClient2.txt
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/bar/client/BarClient3.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/bar/client/BarClient3.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/bar/client/BarClient3.txt
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/rebuild_jars b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/rebuild_jars
new file mode 100644
index 0000000..630dc1a
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/rebuild_jars
@@ -0,0 +1,7 @@
+cd cpe1
+find . -type f | grep -v "\.svn" | xargs jar cvf ../cpe1.jar
+cd ..
+cd cpe2
+find . -type f | grep -v "\.svn" | xargs jar cvf ../cpe2.jar
+cd ..
+
diff --git a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
index 4b556f4..7b06e39 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Google Inc.
+ * Copyright 2007 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
@@ -18,59 +18,67 @@
import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
-import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.Artifact;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.GeneratedResource;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.cfg.PublicOracle;
-import com.google.gwt.dev.jdt.CacheManager;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.JavaSourceFile;
+import com.google.gwt.dev.javac.JavaSourceOracle;
+import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.Util;
import junit.framework.TestCase;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* A wide variety of tests on {@link StandardGeneratorContext}.
*/
public class StandardGeneratorContextTest extends TestCase {
- private static class MockArtifact extends Artifact<MockArtifact> {
+ public static class MockCompilationState extends CompilationState {
- public MockArtifact() {
- super(Linker.class);
+ public MockCompilationState() {
+ super(new JavaSourceOracle() {
+ public Set<String> getClassNames() {
+ return Collections.emptySet();
+ }
+
+ public Set<JavaSourceFile> getSourceFiles() {
+ return Collections.emptySet();
+ }
+
+ public Map<String, JavaSourceFile> getSourceMap() {
+ return Collections.emptyMap();
+ }
+ });
}
- @Override
- protected int compareToComparableArtifact(MockArtifact o) {
- return 0;
- }
-
- @Override
- protected Class<MockArtifact> getComparableArtifactType() {
- return MockArtifact.class;
- }
-
- @Override
- public int hashCode() {
- return 0;
- }
}
- private static class MockCacheManager extends CacheManager {
+ private static class MockGenerator extends Generator {
+ @Override
+ public String generate(TreeLogger logger, GeneratorContext context,
+ String typeName) throws UnableToCompleteException {
+ return typeName;
+ }
}
private static class MockPropertyOracle implements PropertyOracle {
@@ -85,23 +93,32 @@
}
}
- private static class MockGenerator extends Generator {
- @Override
- public String generate(TreeLogger logger, GeneratorContext context,
- String typeName) throws UnableToCompleteException {
- return typeName;
- }
- }
-
private static class MockPublicOracle implements PublicOracle {
- public URL findPublicFile(String partialPath) {
+ public Resource findPublicFile(String partialPath) {
if ("onPublicPath.txt".equals(partialPath)) {
- try {
- return new File("").toURL();
- } catch (MalformedURLException e) {
- throw new RuntimeException(e);
- }
+ return new Resource() {
+
+ @Override
+ public String getLocation() {
+ return "/mock/onPublicPath.txt";
+ }
+
+ @Override
+ public String getPath() {
+ return "onPublicPath.txt";
+ }
+
+ @Override
+ public URL getURL() {
+ return null;
+ }
+
+ @Override
+ public InputStream openContents() {
+ return new ByteArrayInputStream(Util.getBytes("w00t!"));
+ }
+ };
}
return null;
}
@@ -112,31 +129,27 @@
}
- private static class MockTypeOracle extends TypeOracle {
- }
-
private final ArtifactSet artifactSet = new ArtifactSet();
+ private final StandardGeneratorContext genCtx;
+ private final CompilationState mockCompilationState = new MockCompilationState();
+ private final TreeLogger mockLogger = TreeLogger.NULL;
+ private final PropertyOracle mockPropOracle = new MockPropertyOracle();
+ private final PublicOracle mockPublicOracle = new MockPublicOracle();
+ private int tempFileCounter;
+ private final File tempGenDir;
+ private final File tempOutDir;
/**
* Stores the File objects to delete in the order they were created. Delete
* them in reverse order.
*/
private final List<File> toDelete = new ArrayList<File>();
- private final TypeOracle mockTypeOracle = new MockTypeOracle();
- private final PropertyOracle mockPropOracle = new MockPropertyOracle();
- private final PublicOracle mockPublicOracle = new MockPublicOracle();
- private final File tempGenDir;
- private final File tempOutDir;
- private final CacheManager mockCacheManager = new MockCacheManager();
- private final TreeLogger mockLogger = TreeLogger.NULL;
- private final StandardGeneratorContext genCtx;
- private int tempFileCounter;
public StandardGeneratorContextTest() {
tempGenDir = createTempDir("gwt-gen-");
tempOutDir = createTempDir("gwt-out-");
- genCtx = new StandardGeneratorContext(mockTypeOracle, mockPropOracle,
- mockPublicOracle, tempGenDir, tempOutDir, mockCacheManager, artifactSet);
+ genCtx = new StandardGeneratorContext(mockCompilationState, mockPropOracle,
+ mockPublicOracle, tempGenDir, tempOutDir, artifactSet);
}
public void testTryCreateResource_badFileName() {
@@ -267,15 +280,6 @@
genCtx.finish(mockLogger);
}
- public void testTryCreateResource_duplicateCreationAttempt()
- throws UnableToCompleteException {
- String path = createTempOutFilename();
- OutputStream os1 = genCtx.tryCreateResource(mockLogger, path);
- assertNotNull(os1);
- OutputStream os2 = genCtx.tryCreateResource(mockLogger, path);
- assertNull(os2);
- }
-
public void testTryCreateResource_duplicateCreationAfterCommit()
throws UnableToCompleteException, UnsupportedEncodingException,
IOException {
@@ -291,6 +295,15 @@
assertNull(os2);
}
+ public void testTryCreateResource_duplicateCreationAttempt()
+ throws UnableToCompleteException {
+ String path = createTempOutFilename();
+ OutputStream os1 = genCtx.tryCreateResource(mockLogger, path);
+ assertNotNull(os1);
+ OutputStream os2 = genCtx.tryCreateResource(mockLogger, path);
+ assertNull(os2);
+ }
+
public void testTryCreateResource_finishCalledTwice()
throws UnableToCompleteException, IOException {
// Borrow impl.
@@ -334,12 +347,6 @@
}
@Override
- protected void setUp() throws Exception {
- mockCacheManager.invalidateVolatileFiles();
- artifactSet.clear();
- }
-
- @Override
protected void tearDown() throws Exception {
for (int i = toDelete.size() - 1; i >= 0; --i) {
File f = toDelete.get(i);
diff --git a/dev/core/test/com/google/gwt/dev/typeinfo/test/InteractiveTypeOracle.java b/dev/core/test/com/google/gwt/dev/typeinfo/test/InteractiveTypeOracle.java
index 66047b2..f20de04 100644
--- a/dev/core/test/com/google/gwt/dev/typeinfo/test/InteractiveTypeOracle.java
+++ b/dev/core/test/com/google/gwt/dev/typeinfo/test/InteractiveTypeOracle.java
@@ -27,7 +27,7 @@
import com.google.gwt.core.ext.typeinfo.ParseException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
+import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
@@ -81,9 +81,9 @@
// Build an oracle.
//
- TypeOracleBuilder builder = new TypeOracleBuilder();
+ TypeOracleMediator mediator = new TypeOracleMediator();
+ TypeOracle oracle = mediator.getTypeOracle();
// TODO: add compilation units
- TypeOracle oracle = builder.build(logger);
// Create an interactive wrapper around the oracle.
//
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java
index c7d1c20..2a89cb9 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiContainer.java
@@ -18,13 +18,13 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.JPackage;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.CacheManager;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
-import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.JdtCompiler;
+import com.google.gwt.dev.javac.TypeOracleMediator;
+import com.google.gwt.dev.javac.impl.FileCompilationUnit;
import java.io.BufferedReader;
import java.io.File;
@@ -33,13 +33,13 @@
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
-import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
+import java.util.Set;
import java.util.Vector;
/**
@@ -47,6 +47,7 @@
*
*/
public class ApiContainer {
+
private HashMap<String, ApiPackage> apiPackages = new HashMap<String, ApiPackage>();
private HashMap<String, String> excludedFiles = null;
private TreeLogger logger = null;
@@ -119,8 +120,8 @@
public TreeLogger getLogger() {
return logger;
}
-
- private void addCompilationUnitsInPath(TypeOracleBuilder builder,
+
+ private void addCompilationUnitsInPath(Set<CompilationUnit> units,
File sourcePathEntry) throws NotFoundException, IOException,
UnableToCompleteException {
File[] files = sourcePathEntry.listFiles();
@@ -130,7 +131,7 @@
}
for (int i = 0; i < files.length; i++) {
- File file = files[i];
+ final File file = files[i];
// Ignore files like .svn and .cvs
if (file.getName().startsWith(".") || file.getName().equals("CVS")) {
continue;
@@ -150,19 +151,15 @@
}
if (isValidPackage(pkgName, sourcePathEntry.toURL().toString())) {
// Add if it's a source file and the package and fileNames are okay
- URL location = file.toURL();
- CompilationUnitProvider cup = new URLCompilationUnitProvider(
- location, pkgName);
- logger.log(TreeLogger.DEBUG, "+ to CompilationUnit" + ", location="
- + location + ", pkgName=" + pkgName, null);
- builder.addCompilationUnit(cup);
+ CompilationUnit unit = new FileCompilationUnit(file, pkgName);
+ units.add(unit);
numFilesCount++;
} else {
logger.log(TreeLogger.SPAM, " not adding file " + file.toURL(), null);
}
} else {
// Recurse into subDirs
- addCompilationUnitsInPath(builder, file);
+ addCompilationUnitsInPath(units, file);
}
}
}
@@ -171,12 +168,14 @@
IOException, UnableToCompleteException {
numFilesCount = 0;
- TypeOracleBuilder builder = new TypeOracleBuilder(new CacheManager(null,
- null, ApiCompatibilityChecker.DISABLE_CHECKS));
+ TypeOracleMediator mediator = new TypeOracleMediator();
+ Set<CompilationUnit> units = new HashSet<CompilationUnit>();
for (Iterator<File> i = sourceTrees.iterator(); i.hasNext();) {
- addCompilationUnitsInPath(builder, i.next());
+ addCompilationUnitsInPath(units, i.next());
}
- typeOracle = builder.build(logger);
+ JdtCompiler.compile(units);
+ mediator.refresh(logger, units);
+ typeOracle = mediator.getTypeOracle();
logger.log(TreeLogger.INFO, "API " + name
+ ", Finished with building typeOracle, added " + numFilesCount
+ " files", null);
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
index f6fdbd9..b643388 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
@@ -19,15 +19,16 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.CacheManager;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.JdtCompiler;
+import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
-import com.google.gwt.dev.jdt.StaticCompilationUnitProvider;
import junit.framework.TestCase;
import java.util.HashSet;
+import java.util.Set;
/**
*
@@ -40,18 +41,49 @@
* test white-list support.
*/
public class ApiCompatibilityTest extends TestCase {
- // These cups are slightly different from the cups in ApiContainerTest
- static StaticCompilationUnitProvider cuApiClass = new StaticCompilationUnitProvider(
- "test.apicontainer", "ApiClass", getSourceForApiClass());
- static StaticCompilationUnitProvider cuNonApiClass = new StaticCompilationUnitProvider(
- "test.apicontainer", "NonApiClass", getSourceForNonApiClass());
- static StaticCompilationUnitProvider cuNonApiPackage = new StaticCompilationUnitProvider(
- "test.nonapipackage", "TestClass", getSourceForTestClass());
- static StaticCompilationUnitProvider cuObject = new StaticCompilationUnitProvider(
- "java.lang", "Object", getSourceForObject());
- static StaticCompilationUnitProvider cuThrowable = new StaticCompilationUnitProvider(
- "java.lang", "Throwable", getSourceForThrowable());
+ static class StaticCompilationUnit extends CompilationUnit {
+
+ private final char[] source;
+ private final String typeName;
+
+ public StaticCompilationUnit(String typeName, char[] source) {
+ this.typeName = typeName;
+ this.source = source;
+ }
+
+ @Override
+ public String getDisplayLocation() {
+ return "/mock/" + typeName;
+ }
+
+ @Override
+ public String getSource() {
+ return String.valueOf(source);
+ }
+
+ @Override
+ public String getTypeName() {
+ return typeName;
+ }
+
+ @Override
+ public boolean isGenerated() {
+ return false;
+ }
+ }
+
+ // These cups are slightly different from the cups in ApiContainerTest
+ static StaticCompilationUnit cuApiClass = new StaticCompilationUnit(
+ "test.apicontainer.ApiClass", getSourceForApiClass());
+ static StaticCompilationUnit cuNonApiClass = new StaticCompilationUnit(
+ "test.apicontainer.NonApiClass", getSourceForNonApiClass());
+ static StaticCompilationUnit cuNonApiPackage = new StaticCompilationUnit(
+ "test.nonapipackage.TestClass", getSourceForTestClass());
+ static StaticCompilationUnit cuObject = new StaticCompilationUnit(
+ "java.lang.Object", getSourceForObject());
+ static StaticCompilationUnit cuThrowable = new StaticCompilationUnit(
+ "java.lang.Throwable", getSourceForThrowable());
private static char[] getSourceForApiClass() {
StringBuffer sb = new StringBuffer();
@@ -115,14 +147,16 @@
public TypeOracle getNewTypeOracleWithCompilationUnitsAdded(
AbstractTreeLogger logger) throws UnableToCompleteException {
- TypeOracleBuilder builder1 = new TypeOracleBuilder(new CacheManager(null,
- null, ApiCompatibilityChecker.DISABLE_CHECKS));
- builder1.addCompilationUnit(cuObject);
- builder1.addCompilationUnit(cuNonApiClass);
- builder1.addCompilationUnit(cuApiClass);
- builder1.addCompilationUnit(cuNonApiPackage);
- builder1.addCompilationUnit(cuThrowable);
- return builder1.build(logger);
+ TypeOracleMediator mediator = new TypeOracleMediator();
+ Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+ units.add(cuObject);
+ units.add(cuNonApiClass);
+ units.add(cuApiClass);
+ units.add(cuNonApiPackage);
+ units.add(cuThrowable);
+ JdtCompiler.compile(units);
+ mediator.refresh(logger, units);
+ return mediator.getTypeOracle();
}
@Override
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
index d3dc300..a390b08 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
@@ -19,14 +19,18 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.CacheManager;
-import com.google.gwt.dev.jdt.StaticCompilationUnitProvider;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.JdtCompiler;
+import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.tools.apichecker.ApiCompatibilityTest.StaticCompilationUnit;
import junit.framework.TestCase;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Test ApiContainer.
*/
@@ -61,19 +65,16 @@
}
}
- static StaticCompilationUnitProvider cuApiClass = new StaticCompilationUnitProvider(
- "test.apicontainer", "ApiClass", getSourceForApiClass());
-
- static StaticCompilationUnitProvider cuNewPackage = new StaticCompilationUnitProvider(
- "java.newpackage", "Test", getSourceForTest());
-
- static StaticCompilationUnitProvider cuNonApiClass = new StaticCompilationUnitProvider(
- "test.apicontainer", "NonApiClass", getSourceForNonApiClass());
- static StaticCompilationUnitProvider cuNonApiPackage = new StaticCompilationUnitProvider(
- "test.nonapipackage", "TestClass", getSourceForTestClass());
-
- static StaticCompilationUnitProvider cuObject = new StaticCompilationUnitProvider(
- "java.lang", "Object", getSourceForObject());
+ static StaticCompilationUnit cuApiClass = new StaticCompilationUnit(
+ "test.apicontainer.ApiClass", getSourceForApiClass());
+ static StaticCompilationUnit cuNonApiClass = new StaticCompilationUnit(
+ "test.apicontainer.NonApiClass", getSourceForNonApiClass());
+ static StaticCompilationUnit cuNonApiPackage = new StaticCompilationUnit(
+ "test.nonapipackage.TestClass", getSourceForTestClass());
+ static StaticCompilationUnit cuObject = new StaticCompilationUnit(
+ "java.lang.Object", getSourceForObject());
+ static StaticCompilationUnit cuNewPackage = new StaticCompilationUnit(
+ "java.newpackage.Test", getSourceForTest());
private static JAbstractMethod getMethodByName(String name, ApiClass apiClass) {
return (apiClass.getApiMethodsByName(name, ApiClass.MethodType.METHOD).toArray(
@@ -142,18 +143,20 @@
public TypeOracle getNewTypeOracleWithCompilationUnitsAdded()
throws UnableToCompleteException {
- // Build onto an empty type oracle.
- TypeOracleBuilder builder1 = new TypeOracleBuilder(new CacheManager(null,
- null, ApiCompatibilityChecker.DISABLE_CHECKS));
- builder1.addCompilationUnit(cuObject);
- builder1.addCompilationUnit(cuNonApiClass);
- builder1.addCompilationUnit(cuApiClass);
- builder1.addCompilationUnit(cuNonApiPackage);
- builder1.addCompilationUnit(cuNewPackage);
AbstractTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.ERROR);
- TypeOracle typeOracle = builder1.build(logger);
- return typeOracle;
+
+ // Build onto an empty type oracle.
+ TypeOracleMediator mediator = new TypeOracleMediator();
+ Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+ units.add(cuObject);
+ units.add(cuNonApiClass);
+ units.add(cuApiClass);
+ units.add(cuNonApiPackage);
+ units.add(cuNewPackage);
+ JdtCompiler.compile(units);
+ mediator.refresh(logger, units);
+ return mediator.getTypeOracle();
}
/**
diff --git a/tools/benchmark-viewer/build.xml b/tools/benchmark-viewer/build.xml
index 8d187fe..3fa38f6 100755
--- a/tools/benchmark-viewer/build.xml
+++ b/tools/benchmark-viewer/build.xml
@@ -96,6 +96,7 @@
</targetfiles>
<sequential>
<java dir="${tools.build}" classname="com.google.gwt.dev.GWTCompiler" classpath="src:${gwt.user.jar}:${gwt.dev.jar}" fork="yes" failonerror="true">
+ <jvmarg value="-Xmx256M"/>
<arg value="-out" />
<arg file="${tools.build}/www" />
<arg value="${tools.module}" />
diff --git a/user/src/com/google/gwt/benchmarks/BenchmarkReport.java b/user/src/com/google/gwt/benchmarks/BenchmarkReport.java
index 7f17f3a..3094d33 100644
--- a/user/src/com/google/gwt/benchmarks/BenchmarkReport.java
+++ b/user/src/com/google/gwt/benchmarks/BenchmarkReport.java
@@ -193,16 +193,8 @@
return source;
}
- try {
- return source.substring(method.getDeclStart(), method.getDeclEnd() + 1);
- } catch (IndexOutOfBoundsException e) {
- logger.log(TreeLogger.WARN, "Unable to parse " + method.getName(), e);
- // Have seen this happen when the compiler read the source using one
- // character encoding, and then this Parser read it in a different
- // encoding. I don't know if there are other cases in which this can
- // occur.
- return null;
- }
+ // TODO: search for the method manually?
+ return null;
}
}
diff --git a/user/src/com/google/gwt/core/client/GWT.java b/user/src/com/google/gwt/core/client/GWT.java
index b4652d7..b00f5b5 100644
--- a/user/src/com/google/gwt/core/client/GWT.java
+++ b/user/src/com/google/gwt/core/client/GWT.java
@@ -42,7 +42,29 @@
void onUncaughtException(Throwable e);
}
- // web mode default is to let the exception go
+ /**
+ * An {@link UncaughtExceptionHandler} that logs errors to
+ * {@link GWT#log(String, Throwable)}. This is the default exception handler
+ * in hosted mode. In web mode, the default exception handler is
+ * <code>null</code>.
+ */
+ private static final class DefaultUncaughtExceptionHandler implements
+ UncaughtExceptionHandler {
+ public void onUncaughtException(Throwable e) {
+ log("Uncaught exception escaped", e);
+ }
+ }
+
+ /**
+ * Always <code>null</code> in web mode; in hosted mode provides the
+ * implementation for certain methods.
+ */
+ private static GWTBridge sGWTBridge = null;
+
+ /**
+ * Defaults to <code>null</code> in web mode and an instance of
+ * {@link DefaultUncaughtExceptionHandler} in hosted mode.
+ */
private static UncaughtExceptionHandler sUncaughtExceptionHandler = null;
/**
@@ -61,16 +83,20 @@
*/
@SuppressWarnings("unused")
public static <T> T create(Class<?> classLiteral) {
- /*
- * In web mode, the compiler directly replaces calls to this method with a
- * new Object() type expression of the correct rebound type.
- */
- throw new UnsupportedOperationException(
- "ERROR: GWT.create() is only usable in client code! It cannot be called, "
- + "for example, from server code. If you are running a unit test, "
- + "check that your test case extends GWTTestCase and that GWT.create() "
- + "is not called from within an initializer, constructor, or "
- + "setUp()/tearDown().");
+ if (sGWTBridge == null) {
+ /*
+ * In web mode, the compiler directly replaces calls to this method with a
+ * new Object() type expression of the correct rebound type.
+ */
+ throw new UnsupportedOperationException(
+ "ERROR: GWT.create() is only usable in client code! It cannot be called, "
+ + "for example, from server code. If you are running a unit test, "
+ + "check that your test case extends GWTTestCase and that GWT.create() "
+ + "is not called from within an initializer, constructor, or "
+ + "setUp()/tearDown().");
+ } else {
+ return sGWTBridge.<T> create(classLiteral);
+ }
}
/**
@@ -126,9 +152,13 @@
return sUncaughtExceptionHandler;
}
- public static native String getVersion() /*-{
- return $gwt_version;
- }-*/;
+ public static String getVersion() {
+ if (sGWTBridge == null) {
+ return getVersion0();
+ } else {
+ return sGWTBridge.getVersion();
+ }
+ }
/**
* Returns <code>true</code> when running inside the normal GWT environment,
@@ -137,16 +167,15 @@
* on the server, or during the bootstrap sequence of a GWTTestCase test.
*/
public static boolean isClient() {
- // Replaced with "true" by compiler and hosted mode.
- return false;
+ // Replaced with "true" by compiler.
+ return sGWTBridge != null;
}
/**
* Determines whether or not the running program is script or bytecode.
*/
public static boolean isScript() {
- // Will return false in hosted mode.
- return isClient() && true;
+ return isClient() && sGWTBridge == null;
}
/**
@@ -155,7 +184,9 @@
*/
@SuppressWarnings("unused")
public static void log(String message, Throwable e) {
- // intentionally empty in web mode.
+ if (sGWTBridge != null) {
+ sGWTBridge.log(message, e);
+ }
}
/**
@@ -170,4 +201,19 @@
UncaughtExceptionHandler handler) {
sUncaughtExceptionHandler = handler;
}
+
+ /**
+ * Called via reflection in hosted mode; do not every call this method in web
+ * mode.
+ */
+ static void setBridge(GWTBridge bridge) {
+ sGWTBridge = bridge;
+ if (bridge != null) {
+ setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler());
+ }
+ }
+
+ private static native String getVersion0() /*-{
+ return $gwt_version;
+ }-*/;
}
diff --git a/user/src/com/google/gwt/core/client/GWT.java-hosted b/user/src/com/google/gwt/core/client/GWT.java-hosted
deleted file mode 100644
index 0c1dc4b..0000000
--- a/user/src/com/google/gwt/core/client/GWT.java-hosted
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.core.client;
-
-import com.google.gwt.core.client.impl.Impl;
-import com.google.gwt.dev.shell.ShellGWT;
-
-/**
- * The hosted mode implementation of the magic GWT class, with different
- * implementations of certain core methods.
- */
-public final class GWT {
- public interface UncaughtExceptionHandler {
- void onUncaughtException(Throwable e);
- }
-
- // hosted mode default is to log the exception to the log window
- private static UncaughtExceptionHandler sUncaughtExceptionHandler = new UncaughtExceptionHandler() {
- public void onUncaughtException(Throwable e) {
- log("Uncaught exception escaped", e);
- }
- };
-
- public static <T> T create(Class<?> classLiteral) {
- // deferred binding at runtime
- return ShellGWT.create(classLiteral);
- }
-
- public static String getHostPageBaseURL() {
- return Impl.getHostPageBaseURL();
- }
-
- public static String getModuleBaseURL() {
- return Impl.getModuleBaseURL();
- }
-
- public static String getModuleName() {
- return Impl.getModuleName();
- }
-
- public static String getTypeName(Object o) {
- // uses reflection in hosted mode
- return ShellGWT.getTypeName(o);
- }
-
- public static UncaughtExceptionHandler getUncaughtExceptionHandler() {
- return sUncaughtExceptionHandler;
- }
-
- public static String getVersion() {
- return ShellGWT.getVersion();
- };
-
- public static boolean isClient() {
- // true in hosted mode
- return true;
- }
-
- public static boolean isScript() {
- // false in hosted mode
- return false;
- }
-
- public static void log(String message, Throwable e) {
- // logs to the shell logger in hosted mode
- ShellGWT.log(message, e);
- }
-
- public static void setUncaughtExceptionHandler(
- UncaughtExceptionHandler handler) {
- sUncaughtExceptionHandler = handler;
- }
-}
diff --git a/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java b/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
index 35f38d5..ea4356d 100644
--- a/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/HTTPRequestImplIE6.java
@@ -18,8 +18,7 @@
import com.google.gwt.core.client.JavaScriptObject;
/**
- * Internet Explorer 6 implementation of
- * {@link com.google.gwt.user.client.impl.HttpRequestImpl}.
+ * Internet Explorer 6 implementation of {@link HTTPRequestImpl}.
*/
class HTTPRequestImplIE6 extends HTTPRequestImpl {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
index faf66dc..41f1653 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
@@ -21,7 +21,7 @@
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jdt.TypeOracleBuilder;
+import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.dev.util.Util;
import java.io.UnsupportedEncodingException;
@@ -144,7 +144,7 @@
}
public String getSerializedTypeName(JType type) {
- return TypeOracleBuilder.computeBinaryClassName(type);
+ return TypeOracleMediator.computeBinaryClassName(type);
}
public String getTypeSerializerQualifiedName(JClassType serviceIntf) {
diff --git a/user/src/com/google/gwt/user/rebind/ui/ImageBundleGenerator.java b/user/src/com/google/gwt/user/rebind/ui/ImageBundleGenerator.java
index 1513790..258d001 100644
--- a/user/src/com/google/gwt/user/rebind/ui/ImageBundleGenerator.java
+++ b/user/src/com/google/gwt/user/rebind/ui/ImageBundleGenerator.java
@@ -19,7 +19,6 @@
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
@@ -190,16 +189,6 @@
return baseName + "_generatedBundle";
}
- private int countLines(char[] source, int declStartIndex) {
- int lineNum = 1;
- for (int i = 0; i < declStartIndex; ++i) {
- if (source[i] == '\n') {
- ++lineNum;
- }
- }
- return lineNum;
- }
-
private void generateImageMethod(ImageBundleBuilder compositeImage,
SourceWriter sw, JMethod method, String imgResName) {
@@ -287,11 +276,8 @@
List<String> imageResNames = new ArrayList<String>();
for (JMethod method : imageMethods) {
- CompilationUnitProvider unit = method.getEnclosingType().getCompilationUnit();
- String sourceFile = unit.getLocation();
- int lineNum = countLines(unit.getSource(), method.getDeclStart());
String branchMsg = "Analyzing method '" + method.getName()
- + "' beginning on line " + lineNum + " of " + sourceFile;
+ + "' in type " + userType.getQualifiedSourceName();
TreeLogger branch = logger.branch(TreeLogger.DEBUG, branchMsg, null);
// Verify that this method is valid on an image bundle.
diff --git a/user/test/com/google/gwt/dev/cfg/PublicTagTest.java b/user/test/com/google/gwt/dev/cfg/PublicTagTest.java
index 1af2ad6..03e189d 100644
--- a/user/test/com/google/gwt/dev/cfg/PublicTagTest.java
+++ b/user/test/com/google/gwt/dev/cfg/PublicTagTest.java
@@ -15,15 +15,13 @@
*/
package com.google.gwt.dev.cfg;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.GWTCompiler;
-import com.google.gwt.dev.util.Util;
-import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
-import java.io.File;
+import java.io.PrintWriter;
/**
* Tests various permutations of the GWT module's &public& tag,
@@ -31,82 +29,50 @@
*/
public class PublicTagTest extends TestCase {
- /**
- * Provides a convenient interface to the {@link GWTCompiler}. This test
- * cannot simply call {@link GWTCompiler#main(String[])} since it always
- * terminates with a call to {@link System#exit(int)}.
- */
- private static class Compiler extends GWTCompiler {
- /**
- * Run the {@link GWTCompiler} with the specified arguments.
- *
- * @param args arguments passed to the compiler.
- */
- static void compile(String[] args) {
- try {
- final Compiler compiler = new Compiler();
- if (compiler.processArgs(args)) {
- final AbstractTreeLogger logger = new PrintWriterTreeLogger();
- logger.setMaxDetail(compiler.getLogLevel());
- compiler.distill(logger, ModuleDefLoader.loadFromClassPath(logger,
- compiler.getModuleName()));
- }
- } catch (UnableToCompleteException e) {
- throw new RuntimeException("Compilation failed.", e);
- }
- }
+ private static TreeLogger getRootLogger() {
+ PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new PrintWriter(
+ System.err, true));
+ logger.setMaxDetail(TreeLogger.ERROR);
+ return logger;
+ }
+
+ private final ModuleDef moduleDef;
+
+ public PublicTagTest() throws UnableToCompleteException {
+ // Module has the same name as this class.
+ String moduleName = getClass().getCanonicalName();
+ moduleDef = ModuleDefLoader.loadFromClassPath(getRootLogger(), moduleName);
}
public void testPublicTag() {
- // Find the current directory
- String userDir = System.getProperty("user.dir");
- assertNotNull(userDir);
- File curDir = new File(userDir);
- assertTrue(curDir.isDirectory());
+ assertNotNull(moduleDef.findPublicFile("good0.html"));
+ assertNotNull(moduleDef.findPublicFile("good1.html"));
+ assertNotNull(moduleDef.findPublicFile("bar/good.html"));
+ assertNotNull(moduleDef.findPublicFile("good2.html"));
+ assertNotNull(moduleDef.findPublicFile("good3.html"));
+ assertNotNull(moduleDef.findPublicFile("good4.html"));
+ assertNotNull(moduleDef.findPublicFile("good5.html"));
+ assertNotNull(moduleDef.findPublicFile("good6.html"));
+ assertNotNull(moduleDef.findPublicFile("good7.html"));
+ assertNotNull(moduleDef.findPublicFile("good8.html"));
+ assertNotNull(moduleDef.findPublicFile("good10.html"));
+ assertNotNull(moduleDef.findPublicFile("good11.html"));
+ assertNotNull(moduleDef.findPublicFile("good9.html"));
+ assertNotNull(moduleDef.findPublicFile("bar/CVS/good.html"));
+ assertNotNull(moduleDef.findPublicFile("CVS/good.html"));
+ assertNotNull(moduleDef.findPublicFile("GOOD/bar/GOOD/good.html"));
+ assertNotNull(moduleDef.findPublicFile("GOOD/good.html"));
- // Our module name is the same as this class's name
- String moduleName = PublicTagTest.class.getName();
-
- // Find our module output directory and delete it
- File moduleDir = new File(curDir, "www/" + moduleName);
- if (moduleDir.exists()) {
- Util.recursiveDelete(moduleDir, false);
- }
- assertFalse(moduleDir.exists());
-
- // Compile the dummy app; suppress output to stdout
- Compiler.compile(new String[] {
- moduleName, "-logLevel", "ERROR", "-out", "www"});
-
- // Check the output folder
- assertTrue(new File(moduleDir, "good0.html").exists());
- assertTrue(new File(moduleDir, "good1.html").exists());
- assertTrue(new File(moduleDir, "bar/good.html").exists());
- assertTrue(new File(moduleDir, "good2.html").exists());
- assertTrue(new File(moduleDir, "good3.html").exists());
- assertTrue(new File(moduleDir, "good4.html").exists());
- assertTrue(new File(moduleDir, "good5.html").exists());
- assertTrue(new File(moduleDir, "good6.html").exists());
- assertTrue(new File(moduleDir, "good7.html").exists());
- assertTrue(new File(moduleDir, "good8.html").exists());
- assertTrue(new File(moduleDir, "good10.html").exists());
- assertTrue(new File(moduleDir, "good11.html").exists());
- assertTrue(new File(moduleDir, "good9.html").exists());
- assertTrue(new File(moduleDir, "bar/CVS/good.html").exists());
- assertTrue(new File(moduleDir, "CVS/good.html").exists());
- assertTrue(new File(moduleDir, "GOOD/bar/GOOD/good.html").exists());
- assertTrue(new File(moduleDir, "GOOD/good.html").exists());
-
- assertFalse(new File(moduleDir, "bad.Html").exists());
- assertFalse(new File(moduleDir, "bar/CVS/bad.html").exists());
- assertFalse(new File(moduleDir, "CVS/bad.html").exists());
- assertFalse(new File(moduleDir, "bad1.html").exists());
- assertFalse(new File(moduleDir, "bad2.html").exists());
- assertFalse(new File(moduleDir, "bad3.html").exists());
- assertFalse(new File(moduleDir, "bad.html").exists());
- assertFalse(new File(moduleDir, "bar/bad.html").exists());
- assertFalse(new File(moduleDir, "GOOD/bar/bad.html").exists());
- assertFalse(new File(moduleDir, "GOOD/bar/GOOD/bar/bad.html").exists());
+ assertNull(moduleDef.findPublicFile("bad.Html"));
+ assertNull(moduleDef.findPublicFile("bar/CVS/bad.html"));
+ assertNull(moduleDef.findPublicFile("CVS/bad.html"));
+ assertNull(moduleDef.findPublicFile("bad1.html"));
+ assertNull(moduleDef.findPublicFile("bad2.html"));
+ assertNull(moduleDef.findPublicFile("bad3.html"));
+ assertNull(moduleDef.findPublicFile("bad.html"));
+ assertNull(moduleDef.findPublicFile("bar/bad.html"));
+ assertNull(moduleDef.findPublicFile("GOOD/bar/bad.html"));
+ assertNull(moduleDef.findPublicFile("GOOD/bar/GOOD/bar/bad.html"));
}
}
diff --git a/user/test/com/google/gwt/dev/cfg/SourceTagTest.java b/user/test/com/google/gwt/dev/cfg/SourceTagTest.java
index 1939a32..70bda16 100644
--- a/user/test/com/google/gwt/dev/cfg/SourceTagTest.java
+++ b/user/test/com/google/gwt/dev/cfg/SourceTagTest.java
@@ -35,6 +35,6 @@
* logical path would be java/lang/Object.
*/
protected String getLogicalPath(Class<?> clazz) {
- return clazz.getCanonicalName().replace('.', '/') + ".java";
+ return clazz.getCanonicalName();
}
}
diff --git a/user/test/com/google/gwt/dev/cfg/SuperSourceTagTest.java b/user/test/com/google/gwt/dev/cfg/SuperSourceTagTest.java
index 7fdc6af..80cedff 100644
--- a/user/test/com/google/gwt/dev/cfg/SuperSourceTagTest.java
+++ b/user/test/com/google/gwt/dev/cfg/SuperSourceTagTest.java
@@ -37,8 +37,7 @@
protected String getLogicalPath(Class<?> clazz) {
String name = clazz.getCanonicalName();
name = name.substring(getClass().getPackage().getName().length() + 1);
- name = name.replace('.', '/') + ".java";
- name = name.replaceFirst("test/\\w+/", "");
+ name = name.replaceFirst("test\\.\\w+\\.", "");
return name;
}
}
diff --git a/user/test/com/google/gwt/dev/cfg/TestSuperAndSourceTags.java b/user/test/com/google/gwt/dev/cfg/TestSuperAndSourceTags.java
index e4c326c..9a76d25 100644
--- a/user/test/com/google/gwt/dev/cfg/TestSuperAndSourceTags.java
+++ b/user/test/com/google/gwt/dev/cfg/TestSuperAndSourceTags.java
@@ -70,8 +70,8 @@
}
/**
- * Returns the logical path for a class. This method is implemented by the
- * subclasses because source and super-source compute logical paths
+ * Returns the logical path for a class. This method is implemented by the
+ * subclasses because source and super-source compute logical paths
* differently.
*/
protected abstract String getLogicalPath(Class<?> clazz);