Remove the pre-GwtAstBuilder compile chain. - WebModeCompilerFrontEnd - BuildTypeMap - GenerateJavaAST http://gwt-code-reviews.appspot.com/1465805/ git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10490 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java b/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java deleted file mode 100644 index 18c66cf..0000000 --- a/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java +++ /dev/null
@@ -1,129 +0,0 @@ -/* - * Copyright 2011 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; - -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.dev.cfg.ModuleDef; -import com.google.gwt.dev.javac.CompilationState; -import com.google.gwt.dev.javac.CompilationUnit; -import com.google.gwt.dev.javac.StandardGeneratorContext; -import com.google.gwt.dev.jdt.RebindPermutationOracle; -import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd; -import com.google.gwt.dev.jjs.CorrelationFactory; -import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory; -import com.google.gwt.dev.jjs.JJSOptionsImpl; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.impl.BuildTypeMap; -import com.google.gwt.dev.jjs.impl.GenerateJavaAST; -import com.google.gwt.dev.jjs.impl.GwtAstBuilder; -import com.google.gwt.dev.jjs.impl.TypeLinker; -import com.google.gwt.dev.jjs.impl.TypeMap; -import com.google.gwt.dev.js.ast.JsProgram; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; - -import java.util.ArrayList; -import java.util.List; - -/** - * Used by GwtAstBuilderTest. - * - * TODO(zundel): remove after GwtAstBuilderTest is obsolete. - */ -public class GwtAstBuilderUtil { - - public static JProgram buildGenerateJavaAst(final TreeLogger logger, ModuleDef module, - final CompilationState compilationState) throws UnableToCompleteException { - final StandardGeneratorContext genCtx = - new StandardGeneratorContext(compilationState, module, null, new ArtifactSet(), true); - RebindPermutationOracle rpo = new RebindPermutationOracle() { - public void clear() { - } - - public String[] getAllPossibleRebindAnswers(TreeLogger logger, String sourceTypeName) - throws UnableToCompleteException { - return new String[0]; - } - - public CompilationState getCompilationState() { - return compilationState; - } - - public StandardGeneratorContext getGeneratorContext() { - return genCtx; - } - }; - - List<String> allRootTypes = new ArrayList<String>(); - for (CompilationUnit unit : compilationState.getCompilationUnits()) { - allRootTypes.add(unit.getTypeName()); - } - CompilationUnitDeclaration[] goldenCuds = - WebModeCompilerFrontEnd.getCompilationUnitDeclarations(logger, allRootTypes - .toArray(new String[allRootTypes.size()]), rpo, TypeLinker.NULL_TYPE_LINKER).compiledUnits; - - CorrelationFactory correlator = DummyCorrelationFactory.INSTANCE; - JsProgram jsProgram = new JsProgram(correlator); - JProgram jprogram = new JProgram(correlator); - TypeMap typeMap = new TypeMap(jprogram); - TypeDeclaration[] allTypeDeclarations = BuildTypeMap.exec(typeMap, goldenCuds, jsProgram); - // BuildTypeMap can uncover syntactic JSNI errors; report & abort - checkForErrors(logger, goldenCuds); - - // Compute all super type/sub type info - jprogram.typeOracle.computeBeforeAST(); - - // (2) Create our own Java AST from the JDT AST. - GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, new JJSOptionsImpl()); - - // GenerateJavaAST can uncover semantic JSNI errors; report & abort - checkForErrors(logger, goldenCuds); - return jprogram; - } - - public static CompilationState buildGwtAst(TreeLogger logger, ModuleDef module) - throws UnableToCompleteException { - boolean gwtAstWasEnabled = GwtAstBuilder.ENABLED; - try { - GwtAstBuilder.ENABLED = true; - // Avoid call to System.currentTimeMillis() if not logging INFO level - long start = logger.isLoggable(TreeLogger.INFO) ? System.currentTimeMillis() : 0L; - final CompilationState compilationState = module.getCompilationState(logger); - if (logger.isLoggable(TreeLogger.INFO)) { - logger.log(TreeLogger.INFO, (System.currentTimeMillis() - start) - + " time to get compilation state"); - } - return compilationState; - } finally { - GwtAstBuilder.ENABLED = gwtAstWasEnabled; - } - } - - private static void checkForErrors(TreeLogger logger, CompilationUnitDeclaration[] goldenCuds) - throws UnableToCompleteException { - for (CompilationUnitDeclaration cud : goldenCuds) { - CompilationResult result = cud.compilationResult(); - if (result.hasErrors()) { - logger.log(TreeLogger.ERROR, "Aborting on '" + String.valueOf(cud.getFileName()) + "'"); - throw new UnableToCompleteException(); - } - } - } -}
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java b/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java index 2aa4957..91bbe05 100644 --- a/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java +++ b/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
@@ -117,11 +117,9 @@ new Dependencies(packageName, unresolvedQualified, unresolvedSimple, apiRefs); List<JDeclaredType> types = Collections.emptyList(); - if (GwtAstBuilder.ENABLED) { - if (!cud.compilationResult().hasErrors()) { - // Make a GWT AST. - types = astBuilder.process(cud, artificialRescues, jsniMethods, jsniRefs); - } + if (!cud.compilationResult().hasErrors()) { + // Make a GWT AST. + types = astBuilder.process(cud, artificialRescues, jsniMethods, jsniRefs); } for (CompiledClass cc : compiledClasses) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java index f07afbb..183b500 100644 --- a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java +++ b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
@@ -494,10 +494,8 @@ if (unit == null) { break; } - if (GwtAstBuilder.ENABLED) { - if (unit.getTypesSerializedVersion() != GwtAstBuilder.getSerializationVersion()) { - continue; - } + if (unit.getTypesSerializedVersion() != GwtAstBuilder.getSerializationVersion()) { + continue; } UnitCacheEntry entry = new UnitCacheEntry(unit, UnitOrigin.PERSISTENT); UnitCacheEntry existingEntry = unitMap.get(unit.getResourcePath());
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java deleted file mode 100644 index d555625..0000000 --- a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java +++ /dev/null
@@ -1,627 +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.TreeLogger.HelpInfo; -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; -import com.google.gwt.dev.javac.Shared; -import com.google.gwt.dev.util.CharArrayComparator; -import com.google.gwt.dev.util.Empty; -import com.google.gwt.dev.util.Util; -import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -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.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.IProblemFactory; -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.AccessRestriction; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -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.lookup.BinaryTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; -import org.eclipse.jdt.internal.compiler.util.Messages; - -import java.net.URL; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -/** - * A facade around the JDT compiler to manage on-demand compilation, caching - * smartly where possible. - */ -public abstract class AbstractCompiler { - - /** - * Contains the results of a compilation run. Includes both the compiled - * source units and the type bindings for binary types that were looked up - * during the compilation. - */ - public static class CompilationResults { - /** - * Bindings for binary types looked up during compilation. - */ - public final Map<String, BinaryTypeBinding> binaryBindings; - - /** - * Compiled source units. - */ - public final CompilationUnitDeclaration[] compiledUnits; - - public CompilationResults(CompilationUnitDeclaration[] compiledUnits, - Map<String, BinaryTypeBinding> binaryBindings) { - this.compiledUnits = compiledUnits; - this.binaryBindings = binaryBindings; - } - } - - /** - * 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; - } - - @SuppressWarnings("deprecation") - public char[] getContents() { - return unit.getSource().toCharArray(); - } - - public char[] getFileName() { - return unit.getResourceLocation().toCharArray(); - } - - public char[] getMainTypeName() { - return Shared.getShortName(unit.getTypeName()).toCharArray(); - } - - public char[][] getPackageName() { - String packageName = Shared.getPackageName(unit.getTypeName()); - return CharOperation.splitOn('.', packageName.toCharArray()); - } - - @Override - public String toString() { - return unit.toString(); - } - } - - /** - * Shields {@link AbstractCompiler} so it can be garbage collected at the end - * of a compile. - */ - private static class Sandbox { - - /** - * 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 - * classes referenced only from JSNI and <code>GWT.create</code>. - */ - private class CompilerImpl extends Compiler { - - private Map<String, BinaryTypeBinding> bindings; - private Set<CompilationUnitDeclaration> cuds; - private long jdtProcessNanos; - - public CompilerImpl(INameEnvironment environment, IErrorHandlingPolicy policy, - CompilerOptions compilerOptions, ICompilerRequestor requestor, - IProblemFactory problemFactory) { - super(environment, policy, compilerOptions, requestor, problemFactory); - } - - @Override - public void accept(IBinaryType binaryType, PackageBinding packageBinding, - AccessRestriction accessRestriction) { - // Do the same thing as super.accept(), but record the BinaryTypeBinding - // that is generated from lookupEnvironment. - if (this.options.verbose) { - out.println(Messages.bind(Messages.compilation_loadBinary, new String(binaryType - .getName()))); - } - BinaryTypeBinding binding = - lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction); - String name = CharOperation.toString(binding.compoundName); - if (bindings != null) { - bindings.put(name, binding); - } - } - - @Override - public void compile(ICompilationUnit[] sourceUnits) { - SpeedTracerLogger.Event compileEvent = - SpeedTracerLogger.start(CompilerEventType.JDT_COMPILER_SANDBOX); - try { - super.compile(sourceUnits); - } finally { - compileEvent.end(); - } - cuds = null; - } - - @Override - public void process(CompilationUnitDeclaration unit, int index) { - - long processBeginNanos = System.nanoTime(); - - // 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 - { - this.lookupEnvironment.unitBeingCompleted = unit; - long parseStart = System.currentTimeMillis(); - - this.parser.getMethodBodies(unit); - - long resolveStart = System.currentTimeMillis(); - this.stats.parseTime += resolveStart - parseStart; - - // fault in fields & methods - if (unit.scope != null) { - unit.scope.faultInTypes(); - } - - // verify inherited methods - if (unit.scope != null) { - unit.scope.verifyMethods(lookupEnvironment.methodVerifier()); - } - - // type checking - unit.resolve(); - - long analyzeStart = System.currentTimeMillis(); - this.stats.resolveTime += analyzeStart - resolveStart; - - // flow analysis - unit.analyseCode(); - - long generateStart = System.currentTimeMillis(); - this.stats.analyzeTime += generateStart - analyzeStart; - - // code generation - if (doGenerateBytes) { - unit.generateCode(); - } - - // reference info - if (options.produceReferenceInfo && unit.scope != null) { - unit.scope.storeDependencyInfo(); - } - - // finalize problems (suppressWarnings) - unit.finalizeProblems(); - - this.stats.generateTime += System.currentTimeMillis() - generateStart; - - // refresh the total number of units known at this stage - unit.compilationResult.totalUnitsKnown = totalUnits; - - this.lookupEnvironment.unitBeingCompleted = null; - } - - ICompilationUnit cu = unit.compilationResult.compilationUnit; - String loc = String.valueOf(cu.getFileName()); - TreeLogger branch = - logger.branch(TreeLogger.SPAM, "Scanning for additional dependencies: " + loc, null); - - // Examine the cud for types outside of the flow of the original Java - // source. - // - String[] typeNames = outer.doFindAdditionalTypesUsingJsni(branch, unit); - addAdditionalTypes(branch, typeNames); - - typeNames = outer.doFindAdditionalTypesUsingArtificialRescues(branch, unit); - addAdditionalTypes(branch, typeNames); - - typeNames = outer.doFindAdditionalTypesUsingRebinds(branch, unit); - addAdditionalTypes(branch, typeNames); - if (typeNames.length > 0) { - refreshPackagesFromCompState(); - } - - // Optionally remember this cud. - // - if (cuds != null) { - cuds.add(unit); - } - - jdtProcessNanos += System.nanoTime() - processBeginNanos; - } - - /** - * Helper method for process() that receives the types found outside the - * flow of the original Java source. This causes the compiler to find the - * additional type, possibly causing the type to be compiled from source. - */ - private void addAdditionalTypes(TreeLogger logger, String[] typeNames) { - for (String typeName : typeNames) { - if (logger.isLoggable(TreeLogger.SPAM)) { - logger.log(TreeLogger.SPAM, "Need additional type '" + typeName + "'", null); - } - - resolvePossiblyNestedType(typeName); - } - } - - private void compile(ICompilationUnit[] units, Set<CompilationUnitDeclaration> cuds, - Map<String, BinaryTypeBinding> bindings) { - this.bindings = bindings; - this.cuds = cuds; - compile(units); - } - - private ReferenceBinding resolvePossiblyNestedType(String typeName) { - return JdtCompiler.resolveType(lookupEnvironment, typeName); - } - } - - private class ICompilerRequestorImpl implements ICompilerRequestor { - - public ICompilerRequestorImpl() { - } - - public void acceptResult(CompilationResult result) { - // Handle compilation errors. - // - IProblem[] errors = result.getErrors(); - - if (errors != null && errors.length > 0) { - // Dump it to disk. - // - String fn = String.valueOf(result.compilationUnit.getFileName()); - String msg = "Errors in '" + fn + "'"; - TreeLogger branch = logger.branch(TreeLogger.ERROR, msg, null); - - for (IProblem error : errors) { - // Strip the initial code from each error. - // - msg = error.toString(); - msg = msg.substring(msg.indexOf(' ')); - - // 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(msg); - - HelpInfo helpInfo = null; - if (error instanceof GWTProblem) { - GWTProblem gwtProblem = (GWTProblem) error; - helpInfo = gwtProblem.getHelpInfo(); - } - branch.log(TreeLogger.ERROR, msgBuf.toString(), null, helpInfo); - } - } - } - } - - private class INameEnvironmentImpl implements INameEnvironment { - - public INameEnvironmentImpl() { - } - - public void cleanup() { - // intentionally blank - } - - public NameEnvironmentAnswer findType(char[] type, char[][] pkg) { - return findType(CharOperation.arrayConcat(pkg, type)); - } - - public NameEnvironmentAnswer findType(char[][] compoundTypeName) { - String qname = CharOperation.toString(compoundTypeName); - TreeLogger branch = - logger.branch(TreeLogger.SPAM, "Compiler is asking about '" + qname + "'", null); - - if (isPackage(qname)) { - branch.log(TreeLogger.SPAM, "Found to be a package", null); - return null; - } - - // Didn't find it in the cache, so let's compile from source. - // Strip off the inner types, if any - // - String className = qname; - int pos = qname.indexOf('$'); - if (pos >= 0) { - qname = qname.substring(0, pos); - } - CompilationUnit unit = findCompilationUnit(qname); - if (unit != null) { - if (branch.isLoggable(TreeLogger.SPAM)) { - branch.log(TreeLogger.SPAM, "Found type in compilation unit: " - + unit.getResourceLocation()); - } - ICompilationUnit icu = new CompilationUnitAdapter(unit); - return new NameEnvironmentAnswer(icu, null); - } 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); - try { - ClassFileReader cfr = new ClassFileReader(classBytes, null); - return new NameEnvironmentAnswer(cfr, null); - } catch (ClassFormatException e) { - // Ignored. - } - } - } - - branch.log(TreeLogger.SPAM, "Not a known type", null); - return null; - } - } - - public boolean isPackage(char[][] parentPkg, char[] pkg) { - // In special cases where class bytes are asserted from the outside, - // a package can exist that the host doesn't know about. We have to - // do a special check for these cases. - // - final char[] pathChars = CharOperation.concatWith(parentPkg, pkg, '.'); - String packageName = String.valueOf(pathChars); - if (isPackage(packageName)) { - return true; - } else if (isPackage(getClassLoader(), packageName)) { - // Grow our own list to spare calls into the host. - // - rememberPackage(packageName); - return true; - } else { - return false; - } - } - - private ClassLoader getClassLoader() { - return Thread.currentThread().getContextClassLoader(); - } - - private boolean isBinaryType(ClassLoader classLoader, String typeName) { - try { - Class.forName(typeName, false, classLoader); - return true; - } catch (ClassNotFoundException e) { - // Ignored. - } catch (LinkageError e) { - // Ignored. - } - - // Assume that it is not a binary type. - return false; - } - - private boolean isPackage(ClassLoader classLoader, String packageName) { - String packageAsPath = packageName.replace('.', '/'); - - // Test the JRE explicitly, because the classloader trick doesn't work. - if (JdtCompiler.JreIndex.contains(packageAsPath)) { - return true; - } - - return classLoader.getResource(packageAsPath) != null; - } - - private boolean isPackage(String packageName) { - return knownPackages.contains(packageName); - } - } - - final CompilerImpl compiler; - final boolean doGenerateBytes; - final Set<String> knownPackages = new HashSet<String>(); - TreeLogger logger = null; - AbstractCompiler outer; - - Sandbox(AbstractCompiler outer, boolean doGenerateBytes) { - this.outer = outer; - this.doGenerateBytes = doGenerateBytes; - rememberPackage(""); - - INameEnvironment env = new INameEnvironmentImpl(); - IErrorHandlingPolicy pol = DefaultErrorHandlingPolicies.proceedWithAllProblems(); - IProblemFactory probFact = new DefaultProblemFactory(Locale.getDefault()); - ICompilerRequestor req = new ICompilerRequestorImpl(); - CompilerOptions options = getCompilerOptions(); - - // This is only needed by TypeOracleBuilder to parse metadata. - options.docCommentSupport = false; - - compiler = new CompilerImpl(env, pol, options, req, probFact); - - // Initialize the packages list. - refreshPackagesFromCompState(); - } - - public void clear() { - outer = null; - logger = TreeLogger.NULL; - compiler.bindings = null; - } - - private CompilationUnit findCompilationUnit(String qname) { - if (outer == null) { - return null; - } - - // Build the initial set of compilation units. - Map<String, CompilationUnit> unitMap = outer.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); - } - return unit; - } - - private void refreshPackagesFromCompState() { - for (CompilationUnit unit : outer.compilationState.getCompilationUnits()) { - String packageName = Shared.getPackageName(unit.getTypeName()); - rememberPackage(packageName); - } - } - - /** - * Causes the compilation service itself to recognize the specified package - * name (and all its parent packages), avoiding a call back into the host. - * This is useful as an optimization, but more importantly, it is useful to - * compile against bytecode that was pre-compiled to which we don't have the - * source. This ability is crucial bridging the gap between user-level and - * "dev" code in Development Mode for classes such as JavaScriptHost and - * ShellJavaScriptHost. - */ - private void rememberPackage(String packageName) { - if (knownPackages.add(packageName)) { - int i = packageName.lastIndexOf('.'); - if (i != -1) { - // Ensure the parent package is also created. - // - rememberPackage(packageName.substring(0, i)); - } - } - } - } - - private static final Comparator<CompilationUnitDeclaration> CUD_COMPARATOR = - new Comparator<CompilationUnitDeclaration>() { - - public int compare(CompilationUnitDeclaration cud1, CompilationUnitDeclaration cud2) { - ICompilationUnit cu1 = cud1.compilationResult().getCompilationUnit(); - ICompilationUnit cu2 = cud2.compilationResult().getCompilationUnit(); - char[][] package1 = cu1.getPackageName(); - char[][] package2 = cu2.getPackageName(); - for (int i = 0, c = Math.min(package1.length, package2.length); i < c; ++i) { - int result = CharArrayComparator.INSTANCE.compare(package1[i], package2[i]); - if (result != 0) { - return result; - } - } - int result = package2.length - package1.length; - if (result != 0) { - return result; - } - return CharArrayComparator.INSTANCE.compare(cu1.getMainTypeName(), cu2.getMainTypeName()); - } - }; - - public static CompilerOptions getCompilerOptions() { - CompilerOptions options = JdtCompiler.getCompilerOptions(); - - // Turn off all debugging for Production Mode. - options.produceDebugAttributes = 0; - options.preserveAllLocalVariables = false; - return options; - } - - protected CompilationState compilationState; - private Sandbox sandbox; - - protected AbstractCompiler(CompilationState compilationState, boolean doGenerateBytes) { - this.compilationState = compilationState; - this.sandbox = new Sandbox(this, doGenerateBytes); - } - - protected final CompilationResults compile(TreeLogger logger, ICompilationUnit[] units) { - - // Any additional compilation units that are found to be needed will be - // pulled in while processing compilation units. See CompilerImpl.process(). - // - sandbox.logger = logger; - try { - Set<CompilationUnitDeclaration> cuds = - new TreeSet<CompilationUnitDeclaration>(CUD_COMPARATOR); - LinkedHashMap<String, BinaryTypeBinding> bindings = - new LinkedHashMap<String, BinaryTypeBinding>(); - sandbox.compiler.compile(units, cuds, bindings); - return new CompilationResults(cuds.toArray(new CompilationUnitDeclaration[cuds.size()]), - bindings); - } finally { - sandbox.clear(); - sandbox = null; - } - } - - /** - * @param logger a {@link TreeLogger} - * @param cud a {@link CompilationUnitDeclaration} - */ - protected String[] doFindAdditionalTypesUsingArtificialRescues(TreeLogger logger, - CompilationUnitDeclaration cud) { - return Empty.STRINGS; - } - - /** - * @param logger a {@link TreeLogger} - * @param cud a {@link CompilationUnitDeclaration} - */ - protected String[] doFindAdditionalTypesUsingJsni(TreeLogger logger, - CompilationUnitDeclaration cud) { - return Empty.STRINGS; - } - - /** - * @param logger a {@link TreeLogger} - * @param cud a {@link CompilationUnitDeclaration} - */ - protected String[] doFindAdditionalTypesUsingRebinds(TreeLogger logger, - CompilationUnitDeclaration cud) { - return Empty.STRINGS; - } - - protected final ReferenceBinding resolvePossiblyNestedType(String typeName) { - return sandbox.compiler.resolvePossiblyNestedType(typeName); - } -}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/BasicWebModeCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/BasicWebModeCompiler.java deleted file mode 100644 index eaf1dee..0000000 --- a/dev/core/src/com/google/gwt/dev/jdt/BasicWebModeCompiler.java +++ /dev/null
@@ -1,142 +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.dev.javac.CompilationState; -import com.google.gwt.dev.javac.CompilationUnit; -import com.google.gwt.dev.javac.CompiledClass; -import com.google.gwt.dev.jjs.impl.TypeLinker; -import com.google.gwt.dev.util.JsniRef; -import com.google.gwt.dev.util.Memory; - -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Provides a basic front-end based on the JDT compiler that incorporates - * GWT-specific concepts such as JSNI. - */ -public class BasicWebModeCompiler extends AbstractCompiler { - - public static CompilationResults getCompilationUnitDeclarations(TreeLogger logger, - CompilationState state, TypeLinker linker, String... seedTypeNames) - throws UnableToCompleteException { - return new BasicWebModeCompiler(state, linker).getCompilationUnitDeclarations(logger, - seedTypeNames); - } - - private final TypeLinker linker; - - /** - * Construct a BasicWebModeCompiler. - */ - public BasicWebModeCompiler(CompilationState compilationState, TypeLinker linker) { - super(compilationState, false); - this.linker = linker; - } - - /** - * Build the initial set of compilation units. - */ - public CompilationResults getCompilationUnitDeclarations(TreeLogger logger, - String[] seedTypeNames, ICompilationUnit... additionalUnits) throws UnableToCompleteException { - - Map<String, CompiledClass> classMapBySource = compilationState.getClassFileMapBySource(); - - /* - * The alreadyAdded set prevents duplicate CompilationUnits from being added - * to the icu list in the case of multiple JSO implementations as inner - * classes in the same top-level class or seed classes as SingleJsoImpls - * (e.g. JSO itself as the SingleImpl for all tag interfaces). - */ - Set<CompilationUnit> alreadyAdded = new HashSet<CompilationUnit>(); - - List<ICompilationUnit> icus = - new ArrayList<ICompilationUnit>(seedTypeNames.length + additionalUnits.length); - - Collections.addAll(icus, additionalUnits); - - for (String seedTypeName : seedTypeNames) { - CompilationUnit unit = getUnitForType(logger, classMapBySource, seedTypeName); - - if (unit == null) { - continue; - } - - if (alreadyAdded.add(unit)) { - icus.add(new CompilationUnitAdapter(unit)); - } - } - - /* - * Compile, which will pull in everything else via the - * doFindAdditionalTypesUsingFoo() methods. - */ - CompilationResults units = compile(logger, icus.toArray(new ICompilationUnit[icus.size()])); - Memory.maybeDumpMemory("WebModeCompiler"); - return units; - } - - /** - * Pull in types referenced only via JSNI. - */ - @Override - protected String[] doFindAdditionalTypesUsingJsni(TreeLogger logger, - CompilationUnitDeclaration cud) { - FindJsniRefVisitor v = new FindJsniRefVisitor(); - cud.traverse(v, cud.scope); - Set<String> jsniRefs = v.getJsniRefs(); - Set<String> dependentTypeNames = new HashSet<String>(); - for (String jsniRef : jsniRefs) { - JsniRef parsed = JsniRef.parse(jsniRef); - if (parsed != null) { - // If we fail to parse, don't add a class reference. - dependentTypeNames.add(parsed.className()); - } - } - return dependentTypeNames.toArray(new String[dependentTypeNames.size()]); - } - - /** - * Get the CompilationUnit for a named type or throw an - * UnableToCompleteException. - */ - private CompilationUnit getUnitForType(TreeLogger logger, - Map<String, CompiledClass> classMapBySource, String typeName) - throws UnableToCompleteException { - - CompiledClass compiledClass = classMapBySource.get(typeName); - if (compiledClass == null) { - if (linker.isExternalType(typeName)) { - return null; - } - logger.log(TreeLogger.ERROR, "Unable to find compilation unit for type '" + typeName + "'"); - throw new UnableToCompleteException(); - } - - assert compiledClass.getUnit() != null; - return compiledClass.getUnit(); - } -}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java deleted file mode 100644 index fe180a1..0000000 --- a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java +++ /dev/null
@@ -1,112 +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.dev.javac.GWTProblem; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Expression; -import org.eclipse.jdt.internal.compiler.ast.MessageSend; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.Scope; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * Walks a - * {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration} to - * find <code>GWT.create()</code> class so that we can eagerly complain about - * deferred binding problems. - */ -public class FindDeferredBindingSitesVisitor extends SafeASTVisitor { - - /** - * Information about the site at which a rebind request was found, used to - * report problems. - */ - public static class MessageSendSite { - public final MessageSend messageSend; - - public final Scope scope; - - public MessageSendSite(MessageSend messageSend, Scope scope) { - this.messageSend = messageSend; - this.scope = scope; - } - } - - public static final String MAGIC_CLASS = "com.google.gwt.core.client.GWT"; - public static final String REBIND_MAGIC_METHOD = "create"; - - public static void reportRebindProblem(MessageSendSite site, String message) { - MessageSend messageSend = site.messageSend; - Scope scope = site.scope; - // Safe since CUS.referenceContext is set in its constructor. - CompilationUnitDeclaration cud = scope.compilationUnitScope().referenceContext; - GWTProblem.recordError(messageSend, cud, message, null); - } - - private final Map<String, MessageSendSite> results = new HashMap<String, MessageSendSite>(); - - @Override - public void endVisit(MessageSend messageSend, BlockScope scope) { - if (messageSend.binding == null) { - // Some sort of problem. - return; - } - - String methodName = String.valueOf(messageSend.selector); - if (!methodName.equals(REBIND_MAGIC_METHOD)) { - // Not the create() method. - return; - } - - char[][] targetClass = messageSend.binding.declaringClass.compoundName; - String targetClassName = CharOperation.toString(targetClass); - if (!targetClassName.equals(MAGIC_CLASS)) { - // Not being called on the Rebind class. - return; - } - - MessageSendSite site = new MessageSendSite(messageSend, scope); - - Expression[] args = messageSend.arguments; - if (args.length != 1) { - reportRebindProblem(site, "GWT.create() should take exactly one argument"); - return; - } - - if (!(args[0] instanceof ClassLiteralAccess)) { - reportRebindProblem(site, "Only class literals may be used as arguments to GWT.create()"); - return; - } - - ClassLiteralAccess cla = (ClassLiteralAccess) args[0]; - String typeName = String.valueOf(cla.targetType.readableName()); - - if (!results.containsKey(typeName)) { - results.put(typeName, site); - } - } - - public Map<String, MessageSendSite> getSites() { - return Collections.unmodifiableMap(results); - } -}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java deleted file mode 100644 index 2fe19cf..0000000 --- a/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java +++ /dev/null
@@ -1,131 +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.dev.javac.JsniCollector; -import com.google.gwt.dev.jjs.InternalCompilerException; -import com.google.gwt.dev.jjs.SourceOrigin; -import com.google.gwt.dev.js.JsParser; -import com.google.gwt.dev.js.JsParserException; -import com.google.gwt.dev.js.ast.JsContext; -import com.google.gwt.dev.js.ast.JsNameRef; -import com.google.gwt.dev.js.ast.JsProgram; -import com.google.gwt.dev.js.ast.JsStatement; -import com.google.gwt.dev.js.ast.JsVisitor; - -import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; - -import java.io.IOException; -import java.io.StringReader; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -/** - * Walks the AST to find references to Java identifiers from within JSNI blocks. - * By default, it does a full JavaScript parse to accurately find JSNI - * references. If {@link #beSloppy()} is called, then it will run much more - * quickly but it will return a superset of the actual JSNI references. - */ -public class FindJsniRefVisitor extends SafeASTVisitor { - private final Set<String> jsniRefs = new LinkedHashSet<String>(); - - public Set<String> getJsniRefs() { - return Collections.unmodifiableSet(jsniRefs); - } - - @Override - public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { - if (!methodDeclaration.isNative()) { - return false; - } - - // Handle JSNI block - String jsniCode = getJSNICode(methodDeclaration); - if (jsniCode == null) { - return false; - } - if (jsniCode.indexOf('@') < 0) { - // short cut: if there are no at signs, there are no JSNI refs - return false; - } - - findJsniRefsAccurately(methodDeclaration, jsniCode); - return false; - } - - private void findJsniRefsAccurately(MethodDeclaration methodDeclaration, String jsniCode) - throws InternalCompilerException { - JsProgram jsProgram = new JsProgram(); - - String syntheticFnHeader = "function("; - boolean first = true; - if (methodDeclaration.arguments != null) { - for (int i = 0, c = methodDeclaration.arguments.length; i < c; ++i) { - Argument arg = methodDeclaration.arguments[i]; - if (first) { - first = false; - } else { - syntheticFnHeader += ','; - } - syntheticFnHeader += String.valueOf(arg.name); - } - } - syntheticFnHeader += ')'; - StringReader sr = new StringReader(syntheticFnHeader + '\n' + jsniCode); - try { - // start at -1 to avoid counting our synthetic header - List<JsStatement> result = JsParser.parse(SourceOrigin.UNKNOWN, jsProgram.getScope(), sr); - new JsVisitor() { - @Override - public void endVisit(JsNameRef x, JsContext ctx) { - String ident = x.getIdent(); - if (ident.charAt(0) == '@') { - jsniRefs.add(ident.substring(1)); - } - } - }.acceptList(result); - } catch (IOException e) { - throw new InternalCompilerException(e.getMessage(), e); - } catch (JsParserException e) { - // ignore, we only care about finding valid references - } - } - - private String getJSNICode(MethodDeclaration methodDeclaration) { - char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents(); - String jsniCode = - String.valueOf(source, methodDeclaration.bodyStart, methodDeclaration.bodyEnd - - methodDeclaration.bodyStart + 1); - int startPos = jsniCode.indexOf(JsniCollector.JSNI_BLOCK_START); - int endPos = jsniCode.lastIndexOf(JsniCollector.JSNI_BLOCK_END); - if (startPos < 0 || endPos < 0) { - return null; // ignore the error - } - - // move up to open brace - startPos += JsniCollector.JSNI_BLOCK_START.length() - 1; - // move past close brace - endPos += 1; - - jsniCode = jsniCode.substring(startPos, endPos); - return jsniCode; - } - -}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java deleted file mode 100644 index 3492108..0000000 --- a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java +++ /dev/null
@@ -1,166 +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.dev.javac.ArtificialRescueChecker; -import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor.MessageSendSite; -import com.google.gwt.dev.jjs.impl.TypeLinker; -import com.google.gwt.dev.util.Empty; -import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; - -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * 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 BasicWebModeCompiler { - - public static CompilationResults getCompilationUnitDeclarations(TreeLogger logger, - String[] seedTypeNames, RebindPermutationOracle rebindPermOracle, TypeLinker linker, - ICompilationUnit... additionalUnits) throws UnableToCompleteException { - Event getCompilationUnitsEvent = - SpeedTracerLogger.start(CompilerEventType.GET_COMPILATION_UNITS); - CompilationResults results = - new WebModeCompilerFrontEnd(rebindPermOracle, linker).getCompilationUnitDeclarations( - logger, seedTypeNames, additionalUnits); - getCompilationUnitsEvent.end(); - return results; - } - - private final RebindPermutationOracle rebindPermOracle; - - /** - * Construct a WebModeCompilerFrontEnd. - */ - private WebModeCompilerFrontEnd(RebindPermutationOracle rebindPermOracle, TypeLinker linker) { - super(rebindPermOracle.getCompilationState(), linker); - this.rebindPermOracle = rebindPermOracle; - } - - @Override - protected String[] doFindAdditionalTypesUsingArtificialRescues(TreeLogger logger, - CompilationUnitDeclaration cud) { - List<String> types = ArtificialRescueChecker.collectReferencedTypes(cud); - return types.isEmpty() ? Empty.STRINGS : types.toArray(new String[types.size()]); - } - - /** - * Pull in types implicitly referenced through rebind answers. - */ - @Override - protected String[] doFindAdditionalTypesUsingRebinds(TreeLogger logger, - CompilationUnitDeclaration cud) { - Set<String> dependentTypeNames = new LinkedHashSet<String>(); - - // Find all the deferred binding request types. - FindDeferredBindingSitesVisitor v = new FindDeferredBindingSitesVisitor(); - cud.traverse(v, cud.scope); - Map<String, MessageSendSite> requestedTypes = v.getSites(); - Map<String, String[]> rebindAnswers = new HashMap<String, String[]>(); - boolean doFinish = false; - - // For each, ask the host for every possible deferred binding answer. - for (Map.Entry<String, MessageSendSite> entry : requestedTypes.entrySet()) { - String reqType = entry.getKey(); - MessageSendSite site = entry.getValue(); - try { - String[] resultTypes = rebindPermOracle.getAllPossibleRebindAnswers(logger, reqType); - rebindAnswers.put(reqType, resultTypes); - Collections.addAll(dependentTypeNames, resultTypes); - doFinish = true; - } catch (UnableToCompleteException e) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Failed to resolve '" + reqType - + "' via deferred binding"); - rebindAnswers.put(reqType, new String[0]); - } - } - - if (doFinish) { - rebindPermOracle.getGeneratorContext().finish(logger); - } - - // Sanity check all rebind answers. - for (Map.Entry<String, MessageSendSite> entry : requestedTypes.entrySet()) { - String reqType = entry.getKey(); - MessageSendSite site = entry.getValue(); - String[] resultTypes = rebindAnswers.get(reqType); - // Check that each result is instantiable. - for (String typeName : resultTypes) { - checkRebindResultInstantiable(site, typeName); - } - } - - return dependentTypeNames.toArray(new String[dependentTypeNames.size()]); - } - - private void checkRebindResultInstantiable(MessageSendSite site, String typeName) { - /* - * This causes the compiler to find the additional type, possibly winding - * its back to ask for the compilation unit from the source oracle. - */ - ReferenceBinding type = resolvePossiblyNestedType(typeName); - - // Sanity check rebind results. - if (type == null) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Rebind result '" + typeName - + "' could not be found"); - return; - } - if (!type.isClass()) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Rebind result '" + typeName - + "' must be a class"); - return; - } - if (type.isAbstract()) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Rebind result '" + typeName - + "' cannot be abstract"); - return; - } - if (type.isNestedType() && !type.isStatic()) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Rebind result '" + typeName - + "' cannot be a non-static nested class"); - return; - } - if (type.isLocalType()) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Rebind result '" + typeName - + "' cannot be a local class"); - return; - } - // Look for a noArg ctor. - MethodBinding noArgCtor = type.getExactConstructor(Binding.NO_PARAMETERS); - if (noArgCtor == null) { - FindDeferredBindingSitesVisitor.reportRebindProblem(site, "Rebind result '" + typeName - + "' has no default (zero argument) constructors"); - return; - } - } -}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java b/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java index 4b4c7f7..8826981 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java +++ b/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java
@@ -20,12 +20,10 @@ import com.google.gwt.dev.javac.CompilationState; import com.google.gwt.dev.javac.StandardGeneratorContext; import com.google.gwt.dev.jdt.RebindPermutationOracle; -import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory; import com.google.gwt.dev.jjs.ast.JProgram; import com.google.gwt.dev.jjs.impl.AssertionNormalizer; import com.google.gwt.dev.jjs.impl.AssertionRemover; import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox; -import com.google.gwt.dev.jjs.impl.GwtAstBuilder; import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields; import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs; import com.google.gwt.dev.jjs.impl.UnifyAst; @@ -66,9 +64,8 @@ } }; - JProgram jprogram = new JProgram(DummyCorrelationFactory.INSTANCE); - JsProgram jsProgram = new JsProgram(DummyCorrelationFactory.INSTANCE); - assert GwtAstBuilder.ENABLED; + JProgram jprogram = new JProgram(); + JsProgram jsProgram = new JsProgram(); UnifyAst unifyAst = new UnifyAst(jprogram, jsProgram, options, rpo); unifyAst.buildEverything(logger);
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 67d86c7..db7f4f7 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java +++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -41,12 +41,8 @@ import com.google.gwt.dev.cfg.ConfigurationProperty; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.javac.CompilationProblemReporter; -import com.google.gwt.dev.javac.CompilationProblemReporter.SourceFetcher; import com.google.gwt.dev.javac.typemodel.TypeOracle; import com.google.gwt.dev.jdt.RebindPermutationOracle; -import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd; -import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory; -import com.google.gwt.dev.jjs.CorrelationFactory.RealCorrelationFactory; import com.google.gwt.dev.jjs.UnifiedAst.AST; import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.JBinaryOperation; @@ -68,7 +64,6 @@ import com.google.gwt.dev.jjs.impl.AssertionNormalizer; import com.google.gwt.dev.jjs.impl.AssertionRemover; import com.google.gwt.dev.jjs.impl.AstDumper; -import com.google.gwt.dev.jjs.impl.BuildTypeMap; import com.google.gwt.dev.jjs.impl.CastNormalizer; import com.google.gwt.dev.jjs.impl.CatchBlockNormalizer; import com.google.gwt.dev.jjs.impl.CodeSplitter; @@ -79,9 +74,7 @@ import com.google.gwt.dev.jjs.impl.EqualityNormalizer; import com.google.gwt.dev.jjs.impl.Finalizer; import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox; -import com.google.gwt.dev.jjs.impl.GenerateJavaAST; import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST; -import com.google.gwt.dev.jjs.impl.GwtAstBuilder; import com.google.gwt.dev.jjs.impl.HandleCrossFragmentReferences; import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields; import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap; @@ -100,13 +93,10 @@ import com.google.gwt.dev.jjs.impl.RecordRebinds; import com.google.gwt.dev.jjs.impl.RemoveEmptySuperCalls; import com.google.gwt.dev.jjs.impl.ReplaceGetClassOverrides; -import com.google.gwt.dev.jjs.impl.ReplaceRebinds; import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs; import com.google.gwt.dev.jjs.impl.ResolveRebinds; import com.google.gwt.dev.jjs.impl.SameParameterValueOptimizer; import com.google.gwt.dev.jjs.impl.SourceInfoCorrelator; -import com.google.gwt.dev.jjs.impl.TypeLinker; -import com.google.gwt.dev.jjs.impl.TypeMap; import com.google.gwt.dev.jjs.impl.TypeTightener; import com.google.gwt.dev.jjs.impl.UnifyAst; import com.google.gwt.dev.jjs.impl.gflow.DataflowOptimizer; @@ -145,9 +135,6 @@ import com.google.gwt.soyc.SoycDashboard; import com.google.gwt.soyc.io.ArtifactsOutputDirectory; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.xml.sax.SAXException; import java.io.ByteArrayOutputStream; @@ -533,94 +520,36 @@ Memory.maybeDumpMemory("CompStateBuilt"); - CorrelationFactory correlator = - options.isSoycExtra() ? RealCorrelationFactory.INSTANCE : DummyCorrelationFactory.INSTANCE; - JProgram jprogram = new JProgram(correlator); - JsProgram jsProgram = new JsProgram(correlator); + JProgram jprogram = new JProgram(); + JsProgram jsProgram = new JsProgram(); try { - if (GwtAstBuilder.ENABLED) { - UnifyAst unifyAst = new UnifyAst(jprogram, jsProgram, options, rpo); - unifyAst.addRootTypes(allRootTypes); - // TODO: errors. - // TODO: move this into UnifyAst. - findEntryPoints(logger, rpo, declEntryPts, jprogram); - unifyAst.exec(logger); - // TODO: errors. + // (2) Assemble the Java AST. + UnifyAst unifyAst = new UnifyAst(jprogram, jsProgram, options, rpo); + unifyAst.addRootTypes(allRootTypes); + // TODO: move this into UnifyAst? + findEntryPoints(logger, rpo, declEntryPts, jprogram); + unifyAst.exec(logger); - List<String> finalTypeOracleTypes = Lists.create(); - if (precompilationMetrics != null) { - for (com.google.gwt.core.ext.typeinfo.JClassType type : typeOracle.getTypes()) { - finalTypeOracleTypes = - Lists.add(finalTypeOracleTypes, type.getPackage().getName() + "." + type.getName()); - } - precompilationMetrics.setFinalTypeOracleTypes(finalTypeOracleTypes); + List<String> finalTypeOracleTypes = Lists.create(); + if (precompilationMetrics != null) { + for (com.google.gwt.core.ext.typeinfo.JClassType type : typeOracle.getTypes()) { + finalTypeOracleTypes = + Lists.add(finalTypeOracleTypes, type.getPackage().getName() + "." + type.getName()); } - - // Free up memory. - rpo.clear(); - - if (options.isSoycEnabled()) { - SourceInfoCorrelator.exec(jprogram); - } - - // Compute all super type/sub type info - jprogram.typeOracle.computeBeforeAST(); - } else { - - // Compile the source and get the compiler so we can get the parse tree - CompilationUnitDeclaration[] goldenCuds = - WebModeCompilerFrontEnd.getCompilationUnitDeclarations(logger, allRootTypes - .toArray(new String[allRootTypes.size()]), rpo, TypeLinker.NULL_TYPE_LINKER).compiledUnits; - - List<String> finalTypeOracleTypes = Lists.create(); - if (precompilationMetrics != null) { - for (com.google.gwt.core.ext.typeinfo.JClassType type : typeOracle.getTypes()) { - finalTypeOracleTypes = - Lists.add(finalTypeOracleTypes, type.getPackage().getName() + "." + type.getName()); - } - precompilationMetrics.setFinalTypeOracleTypes(finalTypeOracleTypes); - } - - // Free up memory. - rpo.clear(); - Memory.maybeDumpMemory("GoldenCudsBuilt"); - - /* - * Check for compilation problems. We don't log here because any - * problems found here will have already been logged by - * AbstractCompiler. - */ - checkForErrors(logger, goldenCuds, false); - - /* - * (1) Build a flattened map of TypeDeclarations => JType. The resulting - * map contains entries for all reference types. BuildTypeMap also - * parses all JSNI. - */ - TypeMap typeMap = new TypeMap(jprogram); - TypeDeclaration[] allTypeDeclarations = BuildTypeMap.exec(typeMap, goldenCuds, jsProgram); - - // BuildTypeMap can uncover syntactic JSNI errors; report & abort - checkForErrors(logger, goldenCuds, true); - - // Compute all super type/sub type info - jprogram.typeOracle.computeBeforeAST(); - - // (2) Create our own Java AST from the JDT AST. - GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, options); - - // GenerateJavaAST can uncover semantic JSNI errors; report & abort - checkForErrors(logger, goldenCuds, true); - - Memory.maybeDumpMemory("AstBuilt"); - - // Allow GC - goldenCuds = null; - typeMap = null; - allTypeDeclarations = null; + precompilationMetrics.setFinalTypeOracleTypes(finalTypeOracleTypes); } + // Free up memory. + rpo.clear(); + + if (options.isSoycEnabled()) { + SourceInfoCorrelator.exec(jprogram); + } + + // Compute all super type/sub type info + jprogram.typeOracle.computeBeforeAST(); + Memory.maybeDumpMemory("AstOnly"); AstDumper.maybeDumpAST(jprogram); @@ -649,22 +578,12 @@ AssertionRemover.exec(jprogram); } - if (!GwtAstBuilder.ENABLED) { - // Replace GWT.create calls with JGwtCreate nodes. - ReplaceRebinds.exec(logger, jprogram, rpo); - } - // Fix up GWT.runAsync() if (module != null && options.isRunAsyncEnabled()) { ReplaceRunAsyncs.exec(logger, jprogram); CodeSplitter.pickInitialLoadSequence(logger, jprogram, module.getProperties()); } - if (!GwtAstBuilder.ENABLED) { - // Resolve entry points, rebinding non-static entry points. - findEntryPoints(logger, rpo, declEntryPts, jprogram); - } - ImplementClassLiteralsAsFields.exec(jprogram); /* @@ -875,48 +794,6 @@ return stats; } - /** - * Look through the list of compiled units for errors and log them to the - * console. - * - * @param logger logger to use for compilation errors - * @param cuds compiled units to analyze for errors. - * @param itemizeErrors log each error or simply log one message if the build - * failed. - * @throws UnableToCompleteException if a compilation error is found in the - * cuds argument. - */ - static void checkForErrors(TreeLogger logger, CompilationUnitDeclaration[] cuds, - boolean itemizeErrors) throws UnableToCompleteException { - Event checkForErrorsEvent = SpeedTracerLogger.start(CompilerEventType.CHECK_FOR_ERRORS); - boolean compilationFailed = false; - if (cuds.length == 0) { - compilationFailed = true; - } - for (CompilationUnitDeclaration cud : cuds) { - final CompilationResult result = cud.compilationResult(); - if (result.hasErrors()) { - compilationFailed = true; - // Early out if we don't need to itemize. - if (!itemizeErrors) { - break; - } - String typeName = new String(cud.getMainTypeName()); - CompilationProblemReporter.reportErrors(logger, result.getErrors(), new String(cud - .getFileName()), true, new SourceFetcher() { - public String getSource() { - return new String(result.getCompilationUnit().getContents()); - } - }, typeName, false); - } - } - checkForErrorsEvent.end(); - if (compilationFailed) { - logger.log(TreeLogger.ERROR, "Cannot proceed due to previous errors", null); - throw new UnableToCompleteException(); - } - } - private static MultipleDependencyGraphRecorder chooseDependencyRecorder(boolean soycEnabled, OutputStream out) { MultipleDependencyGraphRecorder dependencyRecorder = CodeSplitter.NULL_RECORDER;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java index 0ed7343..7b127d2 100755 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -83,15 +83,6 @@ } /** - * TODO: remove me, just for source compatibility. - */ - @Deprecated - public void addField(int index, JField field) { - assert field.getEnclosingType() == this; - fields = Lists.add(fields, index, field); - } - - /** * Adds a field to this type. */ public void addField(JField field) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java index 63351a5..95aba96 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -16,14 +16,10 @@ package com.google.gwt.dev.jjs.ast; import com.google.gwt.dev.jjs.Correlation.Literal; -import com.google.gwt.dev.jjs.CorrelationFactory; -import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory; import com.google.gwt.dev.jjs.InternalCompilerException; import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.SourceOrigin; -import com.google.gwt.dev.jjs.ast.JField.Disposition; import com.google.gwt.dev.jjs.ast.js.JsCastMap; -import com.google.gwt.dev.jjs.ast.js.JsniMethodBody; import com.google.gwt.dev.jjs.impl.CodeSplitter; import com.google.gwt.dev.util.collect.Lists; @@ -333,11 +329,6 @@ private Map<JType, JField> classLiteralFields; - /** - * A factory to create correlations. - */ - private final CorrelationFactory correlator; - private final List<JMethod> entryMethods = new ArrayList<JMethod>(); private final Map<String, JField> indexedFields = new HashMap<String, JField>(); @@ -379,10 +370,6 @@ private JClassType typeString; - public JProgram() { - this(DummyCorrelationFactory.INSTANCE); - } - /** * Constructor. * @@ -391,10 +378,8 @@ * will collect extra data during the compilation cycle, but at a * cost of memory and object allocations. */ - public JProgram(CorrelationFactory correlator) { - super(correlator.makeSourceInfo(SourceOrigin.create(0, JProgram.class.getName()))); - - this.correlator = correlator; + public JProgram() { + super(SourceOrigin.UNKNOWN); } public void addEntryMethod(JMethod entryPoint) { @@ -445,115 +430,6 @@ } } - public JClassType createClass(SourceInfo info, String name, boolean isAbstract, boolean isFinal) { - JClassType x = new JClassType(info, name, isAbstract, isFinal); - addType(x); - return x; - } - - public JConstructor createConstructor(SourceInfo info, JClassType enclosingType) { - JConstructor x = new JConstructor(info, enclosingType); - x.setBody(new JMethodBody(info)); - if (indexedTypes.containsValue(enclosingType)) { - indexedMethods.put(enclosingType.getShortName() + '.' + enclosingType.getShortName(), x); - } - - enclosingType.addMethod(x); - return x; - } - - public JEnumType createEnum(SourceInfo info, String name, boolean isAbstract) { - JEnumType x = new JEnumType(info, name, isAbstract); - x.setSuperClass(getTypeJavaLangEnum()); - - allTypes.add(x); - putIntoTypeMap(name, x); - - return x; - } - - public JField createEnumField(SourceInfo info, String name, JEnumType enclosingType, - JClassType type, int ordinal) { - assert (name != null); - assert (type != null); - assert (ordinal >= 0); - - JEnumField x = new JEnumField(info, name, ordinal, enclosingType, type); - enclosingType.addField(x); - return x; - } - - public JField createField(SourceInfo info, String name, JDeclaredType enclosingType, JType type, - boolean isStatic, Disposition disposition) { - assert (name != null); - assert (enclosingType != null); - assert (type != null); - - JField x = new JField(info, name, enclosingType, type, isStatic, disposition); - - if (indexedTypes.containsValue(enclosingType)) { - indexedFields.put(enclosingType.getShortName() + '.' + name, x); - } - - enclosingType.addField(x); - return x; - } - - public JInterfaceType createInterface(SourceInfo info, String name) { - JInterfaceType x = new JInterfaceType(info, name); - addType(x); - return x; - } - - public JMethod createMethod(SourceInfo info, String name, JDeclaredType enclosingType, - JType returnType, boolean isAbstract, boolean isStatic, boolean isFinal, - AccessModifier access, boolean isNative) { - assert (name != null); - assert (enclosingType != null); - assert (returnType != null); - assert (!isAbstract || !isNative); - JMethod x = - new JMethod(info, name, enclosingType, returnType, isAbstract, isStatic, isFinal, access); - if (isNative) { - x.setBody(new JsniMethodBody(info)); - } else if (!isAbstract) { - x.setBody(new JMethodBody(info)); - } - - if (access != AccessModifier.PRIVATE && indexedTypes.containsValue(enclosingType)) { - indexedMethods.put(enclosingType.getShortName() + '.' + name, x); - } - - enclosingType.addMethod(x); - return x; - } - - /** - * Create a SourceInfo object when the source is derived from a physical - * location. - */ - public SourceInfo createSourceInfo(int startPos, int endPos, int startLine, String fileName) { - return correlator.makeSourceInfo(SourceOrigin.create(startPos, endPos, startLine, fileName)); - } - - /** - * Create a SourceInfo object when the source is derived from a physical - * location. - */ - public SourceInfo createSourceInfo(int startLine, String fileName) { - return correlator.makeSourceInfo(SourceOrigin.create(startLine, fileName)); - } - - /** - * Create a SourceInfo object when the source is created by the compiler - * itself. - */ - public SourceInfo createSourceInfoSynthetic(Class<?> caller) { - // TODO: consider using Java stack frames to discover the caller's file - // and line number. - return createSourceInfo(0, caller.getName()); - } - /** * Return the least upper bound of a set of types. That is, the smallest type * that is a supertype of all the input types.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java deleted file mode 100644 index 83bd75d..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java +++ /dev/null
@@ -1,1010 +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.jjs.impl; - -import com.google.gwt.dev.javac.JsniCollector; -import com.google.gwt.dev.jdt.AbstractCompiler.CompilationResults; -import com.google.gwt.dev.jdt.SafeASTVisitor; -import com.google.gwt.dev.jjs.HasSourceInfo; -import com.google.gwt.dev.jjs.InternalCompilerException; -import com.google.gwt.dev.jjs.SourceInfo; -import com.google.gwt.dev.jjs.SourceOrigin; -import com.google.gwt.dev.jjs.ast.AccessModifier; -import com.google.gwt.dev.jjs.ast.JClassType; -import com.google.gwt.dev.jjs.ast.JConstructor; -import com.google.gwt.dev.jjs.ast.JDeclaredType; -import com.google.gwt.dev.jjs.ast.JEnumType; -import com.google.gwt.dev.jjs.ast.JField; -import com.google.gwt.dev.jjs.ast.JField.Disposition; -import com.google.gwt.dev.jjs.ast.JInterfaceType; -import com.google.gwt.dev.jjs.ast.JLocal; -import com.google.gwt.dev.jjs.ast.JMethod; -import com.google.gwt.dev.jjs.ast.JMethodBody; -import com.google.gwt.dev.jjs.ast.JNullType; -import com.google.gwt.dev.jjs.ast.JParameter; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.ast.JReferenceType; -import com.google.gwt.dev.jjs.ast.JType; -import com.google.gwt.dev.jjs.ast.js.JsniMethodBody; -import com.google.gwt.dev.js.JsAbstractSymbolResolver; -import com.google.gwt.dev.js.ast.JsFunction; -import com.google.gwt.dev.js.ast.JsName; -import com.google.gwt.dev.js.ast.JsNameRef; -import com.google.gwt.dev.js.ast.JsNode; -import com.google.gwt.dev.js.ast.JsParameter; -import com.google.gwt.dev.js.ast.JsProgram; -import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; -import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Expression; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Statement; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -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.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.util.Util; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * This is a Builder for {@link TypeMap}. The whole point of this pass is to - * create raw unfinished, unlinked AST nodes for types, methods, fields, and - * parameters, and to map the original JDT nodes to these AST nodes. That way - * when GenerateJavaDom runs, it just uses the TypeMap output from this Builder - * to retrieve whatever referenceable nodes it needs without worrying about - * whether they need to be created. Building our AST from JDT starts here. - */ -public class BuildTypeMap { - - /** - * Creates JNodes for every method, field, initializer, parameter, and local - * and memorizes the mapping from the JDT Binding to the corresponding JNode - * for each thing created. Note that this pass also 1) sets up the super - * type(s) for any member or local types created in BuildTypeMapVisitor (see - * the comments there about why it had to be deferred). 2) adds each - * user-defined type to a flat list. 3) Creates JNodes for all methods and - * variables and memorizes the mapping from the JDT Binding to the - * corresponding JNode for each created method and variable. 4) Maps all - * synthetic arguments and fields for nested and local classes. 5) Slurps in - * JSNI code for native methods as an opaque string. - * - * Note that methods and fields are not added to their classes here, that - * isn't done until {@link GenerateJavaAST}. - */ - private class BuildDeclMapVisitor extends SafeASTVisitor { - - private String currentFileName; - private int[] currentSeparatorPositions; - private final List<TypeDeclaration> typeDecls = new ArrayList<TypeDeclaration>(); - - public TypeDeclaration[] getTypeDeclarataions() { - return typeDecls.toArray(new TypeDeclaration[typeDecls.size()]); - } - - @Override - public boolean visit(AnnotationMethodDeclaration methodDeclaration, ClassScope scope) { - return visit((MethodDeclaration) methodDeclaration, scope); - } - - @Override - public boolean visit(Argument argument, BlockScope scope) { - try { - if (scope == scope.methodScope()) { - return true; - } - - JMethodBody enclosingBody = findEnclosingMethod(scope); - if (enclosingBody == null) { - // Happens in the case of external types - return true; - } - SourceInfo info = makeSourceInfo(argument, enclosingBody.getMethod()); - LocalVariableBinding b = argument.binding; - JType localType = getType(b.type); - JLocal newLocal = - JProgram.createLocal(info, String.valueOf(argument.name), localType, b.isFinal(), - enclosingBody); - typeMap.put(b, newLocal); - return true; - } catch (Throwable e) { - throw translateException(argument, e); - } - } - - @Override - public boolean visit(ConstructorDeclaration ctorDecl, ClassScope scope) { - try { - MethodBinding b = ctorDecl.binding; - JClassType enclosingType = (JClassType) getType(scope.enclosingSourceType()); - SourceInfo info = makeSourceInfo(ctorDecl, enclosingType); - processConstructor(b, ctorDecl, info); - return true; - } catch (Throwable e) { - throw translateException(ctorDecl, e); - } - } - - @Override - public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) { - try { - FieldBinding b = fieldDeclaration.binding; - JDeclaredType enclosingType = (JDeclaredType) getType(scope.enclosingSourceType()); - SourceInfo info = makeSourceInfo(fieldDeclaration, enclosingType); - Expression initialization = fieldDeclaration.initialization; - if (initialization != null && initialization instanceof AllocationExpression - && ((AllocationExpression) initialization).enumConstant != null) { - createEnumField(info, b, enclosingType); - } else { - createField(info, b, enclosingType); - } - return true; - } catch (Throwable e) { - throw translateException(fieldDeclaration, e); - } - } - - @Override - public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { - try { - LocalVariableBinding b = localDeclaration.binding; - TypeBinding resolvedType = localDeclaration.type.resolvedType; - JType localType; - if (resolvedType.constantPoolName() != null) { - localType = getType(resolvedType); - } else { - // Special case, a statically unreachable local type. - localType = JNullType.INSTANCE; - } - JMethodBody enclosingBody = findEnclosingMethod(scope); - if (enclosingBody == null) { - // Happens in the case of external types - return true; - } - SourceInfo info = makeSourceInfo(localDeclaration, enclosingBody.getMethod()); - JLocal newLocal = - JProgram.createLocal(info, String.valueOf(localDeclaration.name), localType, b - .isFinal(), enclosingBody); - typeMap.put(b, newLocal); - return true; - } catch (Throwable e) { - throw translateException(localDeclaration, e); - } - } - - @Override - public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { - try { - MethodBinding b = methodDeclaration.binding; - JDeclaredType enclosingType = (JDeclaredType) getType(scope.enclosingSourceType()); - SourceInfo info = makeSourceInfo(methodDeclaration, enclosingType); - JMethod newMethod = processMethodBinding(b, enclosingType, info); - SourceInfo methodInfo = makeSourceInfo(methodDeclaration, newMethod); - mapParameters(newMethod, methodDeclaration, methodInfo); - info.addCorrelation(info.getCorrelator().by(newMethod)); - - if (newMethod.isNative()) { - processNativeMethod(methodDeclaration, info, enclosingType, newMethod); - } - - return true; - } catch (Throwable e) { - throw translateException(methodDeclaration, e); - } - } - - @Override - public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { - return process(memberTypeDeclaration); - } - - @Override - public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) { - return process(typeDeclaration); - } - - @Override - public boolean visitValid(TypeDeclaration localTypeDeclaration, BlockScope scope) { - return process(localTypeDeclaration); - } - - private JField createEnumField(SourceInfo info, FieldBinding binding, - JReferenceType enclosingType) { - JType type = getType(binding.type); - JField field = - program.createEnumField(info, String.valueOf(binding.name), (JEnumType) enclosingType, - (JClassType) type, binding.original().id); - info.addCorrelation(info.getCorrelator().by(field)); - typeMap.put(binding, field); - return field; - } - - private JMethodBody findEnclosingMethod(BlockScope scope) { - JMethod method; - MethodScope methodScope = scope.methodScope(); - if (methodScope.isInsideInitializer()) { - JDeclaredType enclosingType = - (JDeclaredType) getType(scope.classScope().referenceContext.binding); - if (methodScope.isStatic) { - // clinit - method = enclosingType.getMethods().get(0); - } else { - // init - assert (enclosingType instanceof JClassType); - method = enclosingType.getMethods().get(1); - } - } else { - AbstractMethodDeclaration referenceMethod = methodScope.referenceMethod(); - method = (JMethod) typeMap.get(referenceMethod.binding); - } - assert !method.isNative() && !method.isAbstract(); - return (JMethodBody) (method.isExternal() ? null : method.getBody()); - } - - private SourceInfo makeSourceInfo(AbstractMethodDeclaration methodDecl, HasSourceInfo enclosing) { - int startLine = - Util.getLineNumber(methodDecl.sourceStart, currentSeparatorPositions, 0, - currentSeparatorPositions.length - 1); - SourceOrigin toReturn = - SourceOrigin.create(methodDecl.sourceStart, methodDecl.bodyEnd, startLine, - currentFileName); - if (enclosing != null) { - return enclosing.getSourceInfo().makeChild(toReturn); - } - return toReturn; - } - - private SourceInfo makeSourceInfo(Statement stmt, HasSourceInfo enclosing) { - int startLine = - Util.getLineNumber(stmt.sourceStart, currentSeparatorPositions, 0, - currentSeparatorPositions.length - 1); - SourceOrigin toReturn = - SourceOrigin.create(stmt.sourceStart, stmt.sourceEnd, startLine, currentFileName); - if (enclosing != null) { - return enclosing.getSourceInfo().makeChild(toReturn); - } - return toReturn; - } - - /** - * Add synthetic fields, setup super types. You'll notice that we DON'T have - * any concept of "inner" or "outer" types in our AST. Truth is, we found it - * easier to simply model everything as flat classes and emulate the nesting - * behavior (and final local access on local classes). It's much closer to - * how we'll eventually be generating JavaScript code (code generation is - * more straightforward), it makes for fewer kinds of things to worry about - * when optimizing (more aggressive optimizations), and it's how Java - * actually implements the stuff under the hood anyway. - */ - private boolean process(TypeDeclaration typeDeclaration) { - CompilationResult compResult = typeDeclaration.compilationResult; - currentSeparatorPositions = compResult.lineSeparatorPositions; - currentFileName = String.valueOf(compResult.fileName); - - if (BuildTypeMap.this.process(typeDeclaration.binding)) { - if (!linker.isExternalType(dotify(typeDeclaration.binding.compoundName))) { - typeDecls.add(typeDeclaration); - } - return true; - } - - return false; - } - - private void processNativeMethod(MethodDeclaration methodDeclaration, SourceInfo info, - JDeclaredType enclosingType, JMethod newMethod) { - // TODO: use existing parsed JSNI functions from CompilationState. - // Handle JSNI block - char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents(); - String unitSource = String.valueOf(source); - JsFunction jsFunction = - JsniCollector.parseJsniFunction(methodDeclaration, unitSource, enclosingType.getName(), - info, jsProgram.getScope()); - if (jsFunction != null) { - jsFunction.setFromJava(true); - ((JsniMethodBody) newMethod.getBody()).setFunc(jsFunction); - // Ensure that we've resolved the parameter and local references within - // the JSNI method for later pruning. - JsParameterResolver localResolver = new JsParameterResolver(jsFunction); - localResolver.accept(jsFunction); - } - } - - private InternalCompilerException translateException(AbstractMethodDeclaration amd, Throwable e) { - if (e instanceof VirtualMachineError) { - // Always rethrow VM errors (an attempt to wrap may fail). - throw (VirtualMachineError) e; - } - InternalCompilerException ice; - if (e instanceof InternalCompilerException) { - ice = (InternalCompilerException) e; - } else { - ice = new InternalCompilerException("Error building type map", e); - } - ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd, null)); - return ice; - } - - private InternalCompilerException translateException(Statement stmt, Throwable e) { - if (e instanceof VirtualMachineError) { - // Always rethrow VM errors (an attempt to wrap may fail). - throw (VirtualMachineError) e; - } - InternalCompilerException ice; - if (e instanceof InternalCompilerException) { - ice = (InternalCompilerException) e; - } else { - ice = new InternalCompilerException("Error building type map", e); - } - ice.addNode(stmt.getClass().getName(), stmt.toString(), makeSourceInfo(stmt, null)); - return ice; - } - } - - /** - * Creates JNodes for every type and memorizes the mapping from the JDT - * Binding to the corresponding JNode for each created type. Note that since - * there could be forward references, it is not possible to set up super - * types; it must be done is a subsequent pass. - */ - private class BuildTypeMapVisitor extends SafeASTVisitor { - - @Override - public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { - return process(memberTypeDeclaration); - } - - @Override - public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) { - return process(typeDeclaration); - } - - @Override - public boolean visitValid(TypeDeclaration localTypeDeclaration, BlockScope scope) { - assert (TypeDeclaration.kind(localTypeDeclaration.modifiers) != TypeDeclaration.INTERFACE_DECL); - return process(localTypeDeclaration); - } - - private SourceInfo makeSourceInfo(TypeDeclaration typeDecl) { - CompilationResult compResult = typeDecl.compilationResult; - int[] indexes = compResult.lineSeparatorPositions; - String fileName = String.valueOf(compResult.fileName); - int startLine = Util.getLineNumber(typeDecl.sourceStart, indexes, 0, indexes.length - 1); - return program.createSourceInfo(typeDecl.sourceStart, typeDecl.bodyEnd, startLine, fileName); - } - - private boolean process(TypeDeclaration typeDeclaration) { - try { - SourceTypeBinding binding = typeDeclaration.binding; - String name = dotify(binding.compoundName); - if (binding instanceof LocalTypeBinding) { - char[] localName = binding.constantPoolName(); - name = new String(localName).replace('/', '.'); - } - - SourceInfo info = makeSourceInfo(typeDeclaration); - typeMap.put(binding, createType(name, info, binding)); - return true; - } catch (Throwable e) { - throw translateException(typeDeclaration, e); - } - } - - private InternalCompilerException translateException(TypeDeclaration typeDecl, Throwable e) { - if (e instanceof VirtualMachineError) { - // Always rethrow VM errors (an attempt to wrap may fail). - throw (VirtualMachineError) e; - } - InternalCompilerException ice; - if (e instanceof InternalCompilerException) { - ice = (InternalCompilerException) e; - } else { - ice = new InternalCompilerException("Error building type map", e); - } - ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(), makeSourceInfo(typeDecl)); - return ice; - } - } - - private class ExternalTypeCreator implements ExternalTypeTask { - - public void process(String klass, BinaryTypeBinding binding) { - if (program.getFromTypeMap(klass) == null) { - // NB(tobyr) There are a few cases where certain compiler intrinsic - // types are only needed if the program references them - // (e.g. boxed numeric types). If we don't have the binding for those - // types, we can safely ignore it. - createExternalType(klass, binding); - } - } - } - - private class ExternalTypeResolver implements ExternalTypeTask { - - public void process(String klass, BinaryTypeBinding binding) { - if (binding != null) { - JDeclaredType type = program.getFromTypeMap(klass); - resolve(type, binding); - } - } - } - - private interface ExternalTypeTask { - - void process(String klass, BinaryTypeBinding binding); - } - - /** - * Resolves the scope of JS identifiers solely within the scope of a method. - */ - private static class JsParameterResolver extends JsAbstractSymbolResolver { - private final JsFunction jsFunction; - - public JsParameterResolver(JsFunction jsFunction) { - this.jsFunction = jsFunction; - } - - @Override - public void resolve(JsNameRef x) { - // Only resolve unqualified names - if (x.getQualifier() == null) { - JsName name = getScope().findExistingName(x.getIdent()); - - // Ensure that we're resolving a name from the function's parameters - JsNode node = name == null ? null : name.getStaticRef(); - if (node instanceof JsParameter) { - JsParameter param = (JsParameter) node; - if (jsFunction.getParameters().contains(param)) { - x.resolve(name); - } - } - } - } - } - - // TODO: Remove this overload altogether at some point. - - public static TypeDeclaration[] exec(TypeMap typeMap, CompilationResults results, - JsProgram jsProgram, TypeLinker linker) { - BuildTypeMap btm = new BuildTypeMap(typeMap, jsProgram, linker, results.compiledUnits); - Event buildTypeMapEvent = SpeedTracerLogger.start(CompilerEventType.BUILD_TYPE_MAP_FOR_AST); - btm.createPeersForUnits(); - btm.resolveExternalTypes(results.binaryBindings); - TypeDeclaration[] result = btm.createPeersForNonTypeDecls(); - buildTypeMapEvent.end(); - return result; - } - - public static TypeDeclaration[] exec(TypeMap typeMap, CompilationUnitDeclaration[] unitDecls, - JsProgram jsProgram) { - CompilationResults results = - new CompilationResults(unitDecls, new HashMap<String, BinaryTypeBinding>(0)); - return exec(typeMap, results, jsProgram, TypeLinker.NULL_TYPE_LINKER); - } - - static String dotify(char[][] name) { - StringBuffer result = new StringBuffer(); - for (int i = 0; i < name.length; ++i) { - if (i > 0) { - result.append('.'); - } - - result.append(name[i]); - } - return result.toString(); - } - - private final JsProgram jsProgram; - private final TypeLinker linker; - private final JProgram program; - private final TypeMap typeMap; - private final CompilationUnitDeclaration[] unitDecls; - - private BuildTypeMap(TypeMap typeMap, JsProgram jsProgram, TypeLinker linker, - CompilationUnitDeclaration[] unitDecls) { - this.typeMap = typeMap; - this.program = typeMap.getProgram(); - this.jsProgram = jsProgram; - this.linker = linker; - this.unitDecls = unitDecls; - } - - private void addThrownExceptions(MethodBinding methodBinding, JMethod method) { - for (ReferenceBinding thrownBinding : methodBinding.thrownExceptions) { - JClassType type = (JClassType) getType(thrownBinding.erasure()); - method.addThrownException(type); - } - } - - private JDeclaredType createExternalType(String name, ReferenceBinding binding) { - char[] chars = binding.getFileName(); - String fileName = chars == null ? "" : String.valueOf(chars); - SourceInfo sourceInfo = SourceOrigin.create(0, fileName); - JDeclaredType type = createType(name, sourceInfo, binding); - typeMap.put(binding, type); - return type; - } - - private JField createField(SourceInfo info, FieldBinding binding, JDeclaredType enclosingType) { - JType type = getType(binding.type); - JField field = - program.createField(info, String.valueOf(binding.name), enclosingType, type, binding - .isStatic(), GwtAstBuilder.getFieldDisposition(binding)); - typeMap.put(binding, field); - info.addCorrelation(info.getCorrelator().by(field)); - return field; - } - - private JField createField(SyntheticArgumentBinding binding, JDeclaredType enclosingType, - Disposition disposition) { - JType type = getType(binding.type); - SourceInfo info = enclosingType.getSourceInfo().makeChild(); - JField field = - program.createField(info, String.valueOf(binding.name), enclosingType, type, false, - disposition); - info.addCorrelation(info.getCorrelator().by(field)); - if (binding.matchingField != null) { - typeMap.put(binding.matchingField, field); - } - typeMap.put(binding, field); - return field; - } - - private void createMethod(MethodBinding binding, SourceInfo info) { - JDeclaredType enclosingType = (JDeclaredType) getType(binding.declaringClass); - JMethod newMethod = processMethodBinding(binding, enclosingType, info); - mapParameters(newMethod, binding, info); - } - - private JParameter createParameter(LocalVariableBinding binding, JMethod enclosingMethod, - SourceInfo info) { - JType type = getType(binding.type); - JParameter param = - JProgram.createParameter(info, String.valueOf(binding.name), type, binding.isFinal(), - false, enclosingMethod); - typeMap.put(binding, param); - return param; - } - - private JParameter createParameter(SyntheticArgumentBinding arg, String argName, - JMethod enclosingMethod) { - JType type = getType(arg.type); - JParameter param = - JProgram.createParameter(enclosingMethod.getSourceInfo(), argName, type, true, false, - enclosingMethod); - return param; - } - - private JParameter createParameter(TypeBinding paramType, JMethod enclosingMethod, - SourceInfo info, int argPosition) { - JType type = getType(paramType); - // TODO(tobyr) Get the actual param name if it's present in debug info - // or otherwise. - String syntheticParamName = "arg" + argPosition; - JParameter param = - JProgram.createParameter(info, syntheticParamName, type, true, false, enclosingMethod); - // Don't need to put the parameter in the TypeMap as it won't be looked - // up for binary types. - return param; - } - - private TypeDeclaration[] createPeersForNonTypeDecls() { - // Traverse to create our JNode peers for each method, field, - // parameter, and local - BuildDeclMapVisitor v = new BuildDeclMapVisitor(); - for (CompilationUnitDeclaration unitDecl : unitDecls) { - unitDecl.traverse(v, unitDecl.scope); - } - return v.getTypeDeclarataions(); - } - - private void createPeersForUnits() { - // Traverse to create our JNode peers for each type - BuildTypeMapVisitor v = new BuildTypeMapVisitor(); - for (CompilationUnitDeclaration unitDecl : unitDecls) { - unitDecl.traverse(v, unitDecl.scope); - } - } - - private JDeclaredType createType(String name, SourceInfo info, ReferenceBinding binding) { - - JDeclaredType newType; - if (binding.isClass()) { - newType = program.createClass(info, name, binding.isAbstract(), binding.isFinal()); - } else if (binding.isInterface() || binding.isAnnotationType()) { - newType = program.createInterface(info, name); - } else if (binding.isEnum()) { - if (binding.isAnonymousType()) { - // Don't model an enum subclass as a JEnumType. - newType = program.createClass(info, name, false, true); - } else { - newType = program.createEnum(info, name, binding.isAbstract()); - } - } else { - throw new InternalCompilerException("ReferenceBinding is not a class, interface, or enum."); - } - - info.addCorrelation(info.getCorrelator().by(newType)); - - /** - * We emulate static initializers and instance initializers as methods. As - * in other cases, this gives us: simpler AST, easier to optimize, more like - * output JavaScript. Clinit is always in slot 0, init (if it exists) is - * always in slot 1. - */ - SourceInfo child = info.makeChild(); - JMethod clinit = - program.createMethod(child, "$clinit", newType, program.getTypeVoid(), false, true, true, - AccessModifier.PRIVATE, false); - clinit.freezeParamTypes(); - clinit.setSynthetic(); - child.addCorrelation(info.getCorrelator().by(clinit)); - - if (newType instanceof JClassType) { - child = info.makeChild(); - JMethod init = - program.createMethod(child, "$init", newType, program.getTypeVoid(), false, false, true, - AccessModifier.PRIVATE, false); - init.freezeParamTypes(); - init.setSynthetic(); - child.addCorrelation(info.getCorrelator().by(init)); - } - - newType.setExternal(linker.isExternalType(newType.getName())); - return newType; - } - - private void forEachExternalType(Map<String, BinaryTypeBinding> bindings, ExternalTypeTask task) { - for (Map.Entry<String, BinaryTypeBinding> entry : bindings.entrySet()) { - String klass = entry.getKey(); - if (linker.isExternalType(klass)) { - BinaryTypeBinding binding = bindings.get(klass); - if (binding != null) { - task.process(klass, binding); - } - } - } - } - - private JType getType(TypeBinding binding) { - JType type = (JType) typeMap.tryGet(binding); - - if (type != null) { - return type; - } - - if (binding instanceof ArrayBinding) { - binding = ((ArrayBinding) binding).leafComponentType; - } - - if (!(binding instanceof ReferenceBinding)) { - throw new InternalCompilerException("Expected a ReferenceBinding but received a " - + binding.getClass()); - } - - ReferenceBinding refBinding = (ReferenceBinding) binding; - String name = dotify(refBinding.compoundName); - if (!linker.isExternalType(name)) { - // typeMap.get() will fail with an appropriate exception - return (JType) typeMap.get(binding); - } - - type = createExternalType(name, refBinding); - resolve((JDeclaredType) type, refBinding); - return type; - } - - private void mapParameters(JMethod method, AbstractMethodDeclaration x, SourceInfo info) { - MethodBinding b = x.binding; - int paramCount = (b.parameters != null ? b.parameters.length : 0); - if (paramCount > 0) { - for (int i = 0, n = x.arguments.length; i < n; ++i) { - createParameter(x.arguments[i].binding, method, info); - } - } - method.freezeParamTypes(); - } - - private void mapParameters(JMethod method, MethodBinding binding, SourceInfo info) { - int paramCount = binding.parameters != null ? binding.parameters.length : 0; - if (paramCount > 0) { - int counter = 0; - for (TypeBinding argType : binding.parameters) { - createParameter(argType, method, info, counter++); - } - } - method.freezeParamTypes(); - } - - private boolean process(ReferenceBinding binding) { - JDeclaredType type = (JDeclaredType) getType(binding); - - try { - // Create an override for getClass(). - if (type instanceof JClassType && type != program.getTypeJavaLangObject()) { - - SourceInfo info = type.getSourceInfo().makeChild(); - JMethod getClassMethod = - program.createMethod(info, "getClass", type, program.getTypeJavaLangClass(), false, - false, false, AccessModifier.PUBLIC, false); - assert (type.getMethods().get(2) == getClassMethod); - getClassMethod.freezeParamTypes(); - getClassMethod.setSynthetic(); - info.addCorrelation(info.getCorrelator().by(getClassMethod)); - } - - if (binding.isNestedType() && !binding.isStatic() && !(binding instanceof BinaryTypeBinding)) { - // TODO(tobyr) Do something here for binary types? - - // add synthetic fields for outer this and locals - assert (type instanceof JClassType); - NestedTypeBinding nestedBinding = (NestedTypeBinding) binding; - if (nestedBinding.enclosingInstances != null) { - for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { - SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; - createField(arg, type, Disposition.THIS_REF); - } - } - - if (nestedBinding.outerLocalVariables != null) { - for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) { - SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i]; - // See InnerClassTest.testOuterThisFromSuperCall(). - boolean isReallyThisRef = false; - if (arg.actualOuterLocalVariable instanceof SyntheticArgumentBinding) { - SyntheticArgumentBinding outer = - (SyntheticArgumentBinding) arg.actualOuterLocalVariable; - if (outer.matchingField != null) { - JField field = (JField) typeMap.get(outer.matchingField); - if (field.isThisRef()) { - isReallyThisRef = true; - } - } - } - createField(arg, type, isReallyThisRef ? Disposition.THIS_REF : Disposition.FINAL); - } - } - } - - ReferenceBinding superClassBinding = binding.superclass(); - if (type instanceof JClassType && superClassBinding != null) { - // TODO: handle separately? - assert (binding.superclass().isClass() || binding.superclass().isEnum()); - JClassType superClass = (JClassType) getType(superClassBinding); - ((JClassType) type).setSuperClass(superClass); - } - - ReferenceBinding[] superInterfaces = binding.superInterfaces(); - for (ReferenceBinding superInterfaceBinding : superInterfaces) { - assert (superInterfaceBinding.isInterface()); - JInterfaceType superInterface = (JInterfaceType) getType(superInterfaceBinding); - type.addImplements(superInterface); - } - - ReferenceBinding enclosingBinding = binding.enclosingType(); - if (enclosingBinding != null) { - type.setEnclosingType((JDeclaredType) getType(enclosingBinding)); - } - - if (type instanceof JEnumType) { - processEnumType(binding, (JEnumType) type); - } - - return true; - } catch (VirtualMachineError e) { - // Always rethrow VM errors (an attempt to wrap may fail). - throw e; - } catch (InternalCompilerException ice) { - ice.addNode(type); - throw ice; - } catch (Throwable e) { - throw new InternalCompilerException(type, "Error building type map", e); - } - } - - private JConstructor processConstructor(MethodBinding b, ConstructorDeclaration decl, - SourceInfo info) { - JClassType enclosingType = (JClassType) getType(b.declaringClass); - JConstructor newCtor = program.createConstructor(info, enclosingType); - - // Enums have hidden arguments for name and value - if (enclosingType.isEnumOrSubclass() != null) { - JProgram.createParameter(info, "enum$name", program.getTypeJavaLangString(), true, false, - newCtor); - JProgram.createParameter(info, "enum$ordinal", program.getTypePrimitiveInt(), true, false, - newCtor); - } - - ReferenceBinding declaringClass = b.declaringClass; - Set<String> alreadyNamedVariables = new HashSet<String>(); - if (declaringClass.isNestedType() && !declaringClass.isStatic()) { - // TODO(tobyr) Do we have to do the equivalent for binary types here - // or will this just fall out correctly? - - // add synthetic args for outer this - NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass; - if (nestedBinding.enclosingInstances != null) { - for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { - SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; - String argName = String.valueOf(arg.name); - if (alreadyNamedVariables.contains(argName)) { - argName += "_" + i; - } - createParameter(arg, argName, newCtor); - alreadyNamedVariables.add(argName); - } - } - } - - // user args - if (decl == null) { - mapParameters(newCtor, b, info); - } else { - mapParameters(newCtor, decl, info); - } - // original params are now frozen - - addThrownExceptions(b, newCtor); - - info.addCorrelation(info.getCorrelator().by(newCtor)); - - if (declaringClass.isNestedType() && !declaringClass.isStatic()) { - // add synthetic args for locals - NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass; - // add synthetic args for outer this and locals - if (nestedBinding.outerLocalVariables != null) { - for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) { - SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i]; - String argName = String.valueOf(arg.name); - if (alreadyNamedVariables.contains(argName)) { - argName += "_" + i; - } - createParameter(arg, argName, newCtor); - alreadyNamedVariables.add(argName); - } - } - } - - if (enclosingType.isExternal()) { - newCtor.setBody(null); - } - - typeMap.put(b, newCtor); - return newCtor; - } - - private void processEnumType(ReferenceBinding binding, JEnumType type) { - // Visit the synthetic values() and valueOf() methods. - for (MethodBinding methodBinding : binding.methods()) { - if (methodBinding instanceof SyntheticMethodBinding) { - JMethod newMethod = processMethodBinding(methodBinding, type, type.getSourceInfo()); - TypeBinding[] parameters = methodBinding.parameters; - if (parameters.length == 0) { - assert newMethod.getName().equals("values"); - } else if (parameters.length == 1) { - assert newMethod.getName().equals("valueOf"); - assert typeMap.get(parameters[0]) == program.getTypeJavaLangString(); - JProgram.createParameter(newMethod.getSourceInfo(), "name", program - .getTypeJavaLangString(), true, false, newMethod); - } else { - assert false; - } - newMethod.freezeParamTypes(); - } - } - } - - private void processExternalMethod(MethodBinding binding, JDeclaredType type) { - if (binding.isPrivate() - || (type.getName().startsWith("java.") && !binding.isPublic() && !binding.isProtected())) { - return; - } - if (binding.isConstructor()) { - processConstructor(binding, null, type.getSourceInfo()); - } else { - createMethod(binding, type.getSourceInfo()); - } - } - - private JMethod processMethodBinding(MethodBinding b, JDeclaredType enclosingType, SourceInfo info) { - JType returnType = getType(b.returnType); - JMethod newMethod = - program.createMethod(info, String.valueOf(b.selector), enclosingType, returnType, b - .isAbstract(), b.isStatic(), b.isFinal(), AccessModifier.fromMethodBinding(b), b - .isNative()); - addThrownExceptions(b, newMethod); - if (b.isSynthetic()) { - newMethod.setSynthetic(); - } - - if (enclosingType.isExternal()) { - newMethod.setBody(null); - } - typeMap.put(b, newMethod); - return newMethod; - } - - private void resolve(JDeclaredType type, ReferenceBinding binding) { - process(binding); - - for (FieldBinding fieldBinding : binding.fields()) { - if (fieldBinding.isPrivate() - || (type.getName().startsWith("java.") && !fieldBinding.isPublic() && !fieldBinding - .isProtected())) { - continue; - } - - createField(type.getSourceInfo(), fieldBinding, type); - } - - for (MethodBinding methodBinding : binding.methods()) { - processExternalMethod(methodBinding, type); - } - - if (binding instanceof BinaryTypeBinding) { - // Unlike SourceTypeBindings, we have to explicitly ask for bridge methods - // for BinaryTypeBindings. - try { - // TODO(tobyr) Fix so we don't have to use reflection. - Method m = BinaryTypeBinding.class.getDeclaredMethod("bridgeMethods"); - MethodBinding[] bridgeMethods = (MethodBinding[]) m.invoke(binding); - - for (MethodBinding methodBinding : bridgeMethods) { - processExternalMethod(methodBinding, type); - } - } catch (Exception e) { - throw new InternalCompilerException("Unexpected failure", e); - } - } - } - - /** - * Creates and resolves all external types. - */ - private void resolveExternalTypes(Map<String, BinaryTypeBinding> bindings) { - forEachExternalType(bindings, new ExternalTypeCreator()); - forEachExternalType(bindings, new ExternalTypeResolver()); - } -}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java deleted file mode 100644 index 3c4883f..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java +++ /dev/null
@@ -1,3010 +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.jjs.impl; - -import com.google.gwt.dev.javac.ArtificialRescueChecker.RescueData; -import com.google.gwt.dev.javac.JsniCollector; -import com.google.gwt.dev.jjs.InternalCompilerException; -import com.google.gwt.dev.jjs.JJSOptions; -import com.google.gwt.dev.jjs.SourceInfo; -import com.google.gwt.dev.jjs.SourceOrigin; -import com.google.gwt.dev.jjs.ast.AccessModifier; -import com.google.gwt.dev.jjs.ast.Context; -import com.google.gwt.dev.jjs.ast.JArrayLength; -import com.google.gwt.dev.jjs.ast.JArrayRef; -import com.google.gwt.dev.jjs.ast.JArrayType; -import com.google.gwt.dev.jjs.ast.JAssertStatement; -import com.google.gwt.dev.jjs.ast.JBinaryOperation; -import com.google.gwt.dev.jjs.ast.JBinaryOperator; -import com.google.gwt.dev.jjs.ast.JBlock; -import com.google.gwt.dev.jjs.ast.JBooleanLiteral; -import com.google.gwt.dev.jjs.ast.JBreakStatement; -import com.google.gwt.dev.jjs.ast.JCaseStatement; -import com.google.gwt.dev.jjs.ast.JCastOperation; -import com.google.gwt.dev.jjs.ast.JCharLiteral; -import com.google.gwt.dev.jjs.ast.JClassLiteral; -import com.google.gwt.dev.jjs.ast.JClassType; -import com.google.gwt.dev.jjs.ast.JConditional; -import com.google.gwt.dev.jjs.ast.JConstructor; -import com.google.gwt.dev.jjs.ast.JContinueStatement; -import com.google.gwt.dev.jjs.ast.JDeclarationStatement; -import com.google.gwt.dev.jjs.ast.JDeclaredType; -import com.google.gwt.dev.jjs.ast.JDoStatement; -import com.google.gwt.dev.jjs.ast.JDoubleLiteral; -import com.google.gwt.dev.jjs.ast.JEnumField; -import com.google.gwt.dev.jjs.ast.JEnumType; -import com.google.gwt.dev.jjs.ast.JExpression; -import com.google.gwt.dev.jjs.ast.JExpressionStatement; -import com.google.gwt.dev.jjs.ast.JField; -import com.google.gwt.dev.jjs.ast.JField.Disposition; -import com.google.gwt.dev.jjs.ast.JFieldRef; -import com.google.gwt.dev.jjs.ast.JFloatLiteral; -import com.google.gwt.dev.jjs.ast.JForStatement; -import com.google.gwt.dev.jjs.ast.JIfStatement; -import com.google.gwt.dev.jjs.ast.JInstanceOf; -import com.google.gwt.dev.jjs.ast.JIntLiteral; -import com.google.gwt.dev.jjs.ast.JInterfaceType; -import com.google.gwt.dev.jjs.ast.JLabel; -import com.google.gwt.dev.jjs.ast.JLabeledStatement; -import com.google.gwt.dev.jjs.ast.JLiteral; -import com.google.gwt.dev.jjs.ast.JLocal; -import com.google.gwt.dev.jjs.ast.JLocalRef; -import com.google.gwt.dev.jjs.ast.JLongLiteral; -import com.google.gwt.dev.jjs.ast.JMethod; -import com.google.gwt.dev.jjs.ast.JMethodBody; -import com.google.gwt.dev.jjs.ast.JMethodCall; -import com.google.gwt.dev.jjs.ast.JModVisitor; -import com.google.gwt.dev.jjs.ast.JNewArray; -import com.google.gwt.dev.jjs.ast.JNewInstance; -import com.google.gwt.dev.jjs.ast.JNode; -import com.google.gwt.dev.jjs.ast.JNonNullType; -import com.google.gwt.dev.jjs.ast.JParameter; -import com.google.gwt.dev.jjs.ast.JParameterRef; -import com.google.gwt.dev.jjs.ast.JPostfixOperation; -import com.google.gwt.dev.jjs.ast.JPrefixOperation; -import com.google.gwt.dev.jjs.ast.JPrimitiveType; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.ast.JReferenceType; -import com.google.gwt.dev.jjs.ast.JReturnStatement; -import com.google.gwt.dev.jjs.ast.JStatement; -import com.google.gwt.dev.jjs.ast.JStringLiteral; -import com.google.gwt.dev.jjs.ast.JSwitchStatement; -import com.google.gwt.dev.jjs.ast.JThisRef; -import com.google.gwt.dev.jjs.ast.JThrowStatement; -import com.google.gwt.dev.jjs.ast.JTryStatement; -import com.google.gwt.dev.jjs.ast.JType; -import com.google.gwt.dev.jjs.ast.JTypeOracle; -import com.google.gwt.dev.jjs.ast.JUnaryOperator; -import com.google.gwt.dev.jjs.ast.JVariable; -import com.google.gwt.dev.jjs.ast.JVariableRef; -import com.google.gwt.dev.jjs.ast.JWhileStatement; -import com.google.gwt.dev.jjs.ast.js.JsniClassLiteral; -import com.google.gwt.dev.jjs.ast.js.JsniFieldRef; -import com.google.gwt.dev.jjs.ast.js.JsniMethodBody; -import com.google.gwt.dev.jjs.ast.js.JsniMethodRef; -import com.google.gwt.dev.js.ast.JsContext; -import com.google.gwt.dev.js.ast.JsExpression; -import com.google.gwt.dev.js.ast.JsModVisitor; -import com.google.gwt.dev.js.ast.JsNameRef; -import com.google.gwt.dev.util.JsniRef; -import com.google.gwt.dev.util.collect.Maps; -import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; - -import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression; -import org.eclipse.jdt.internal.compiler.ast.ASTNode; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; -import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; -import org.eclipse.jdt.internal.compiler.ast.ArrayReference; -import org.eclipse.jdt.internal.compiler.ast.AssertStatement; -import org.eclipse.jdt.internal.compiler.ast.Assignment; -import org.eclipse.jdt.internal.compiler.ast.BinaryExpression; -import org.eclipse.jdt.internal.compiler.ast.Block; -import org.eclipse.jdt.internal.compiler.ast.BreakStatement; -import org.eclipse.jdt.internal.compiler.ast.CaseStatement; -import org.eclipse.jdt.internal.compiler.ast.CastExpression; -import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; -import org.eclipse.jdt.internal.compiler.ast.CombinedBinaryExpression; -import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment; -import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; -import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ContinueStatement; -import org.eclipse.jdt.internal.compiler.ast.DoStatement; -import org.eclipse.jdt.internal.compiler.ast.EmptyStatement; -import org.eclipse.jdt.internal.compiler.ast.EqualExpression; -import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; -import org.eclipse.jdt.internal.compiler.ast.Expression; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.FieldReference; -import org.eclipse.jdt.internal.compiler.ast.ForStatement; -import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; -import org.eclipse.jdt.internal.compiler.ast.IfStatement; -import org.eclipse.jdt.internal.compiler.ast.Initializer; -import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression; -import org.eclipse.jdt.internal.compiler.ast.LabeledStatement; -import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MessageSend; -import org.eclipse.jdt.internal.compiler.ast.NullLiteral; -import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression; -import org.eclipse.jdt.internal.compiler.ast.OperatorIds; -import org.eclipse.jdt.internal.compiler.ast.PostfixExpression; -import org.eclipse.jdt.internal.compiler.ast.PrefixExpression; -import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; -import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; -import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference; -import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference; -import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; -import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; -import org.eclipse.jdt.internal.compiler.ast.Statement; -import org.eclipse.jdt.internal.compiler.ast.SuperReference; -import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; -import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; -import org.eclipse.jdt.internal.compiler.ast.ThisReference; -import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; -import org.eclipse.jdt.internal.compiler.ast.TryStatement; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.ast.UnaryExpression; -import org.eclipse.jdt.internal.compiler.ast.WhileStatement; -import org.eclipse.jdt.internal.compiler.impl.BooleanConstant; -import org.eclipse.jdt.internal.compiler.impl.ByteConstant; -import org.eclipse.jdt.internal.compiler.impl.CharConstant; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.DoubleConstant; -import org.eclipse.jdt.internal.compiler.impl.FloatConstant; -import org.eclipse.jdt.internal.compiler.impl.IntConstant; -import org.eclipse.jdt.internal.compiler.impl.LongConstant; -import org.eclipse.jdt.internal.compiler.impl.ShortConstant; -import org.eclipse.jdt.internal.compiler.impl.StringConstant; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.util.Util; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * This is the big kahuna where most of the nitty gritty of creating our AST - * happens. BuildTypeMap must have already run so we have valid mappings between - * JDT nodes and our already-created AST nodes. - */ -public class GenerateJavaAST { - - /** - * Visit the JDT AST and produce our own AST into the passed-in TypeMap's - * JProgram. By the end of this pass, the produced AST should contain every - * piece of information we'll ever need about the code. The JDT nodes should - * never again be referenced after this. - * - * This is implemented as a reflective visitor for JDT's AST. The advantage of - * doing it reflectively is that if we run into any JDT nodes we can't handle, - * we'll automatically throw an exception. If we had subclassed - * {@link org.eclipse.jdt.internal.compiler.ast.ASTNode} we'd have to override - * every single method and explicitly throw an exception to get the same - * behavior. - * - * NOTE ON JDT FORCED OPTIMIZATIONS - If JDT statically determines that a - * section of code in unreachable, it won't fully resolve that section of - * code. This invalid-state code causes us major problems. As a result, we - * have to optimize out those dead blocks early and never try to translate - * them to our AST. - */ - // Reflective invocation causes unused warnings. - @SuppressWarnings("unused") - private static class JavaASTGenerationVisitor { - - /** - * Used to cache {@link Method} lookups. - */ - private static class MethodKey { - private final Class<? extends Object> childClass; - private final String name; - - public MethodKey(String name, Class<? extends Object> childClass) { - this.name = name; - this.childClass = childClass; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof MethodKey) { - MethodKey otherKey = (MethodKey) obj; - return name.equals(otherKey.name) && childClass.equals(otherKey.childClass); - } - return super.equals(obj); - } - - @Override - public int hashCode() { - return name.hashCode() + (101 * childClass.hashCode()); - } - } - - /** - * Used to cache {@link Method} lookups. - */ - private static class MethodValue { - private final NoSuchMethodException ex; - private final Method method; - - public MethodValue(Method method) { - this.method = method; - this.ex = null; - } - - public MethodValue(NoSuchMethodException ex) { - this.ex = ex; - this.method = null; - } - - public Method getMethod() throws NoSuchMethodException { - if (this.ex != null) { - throw (ex); - } - return method; - } - } - - /** - * The literal for the JLS identifier that represents the length field on an - * array. - */ - private static final String ARRAY_LENGTH_FIELD = "length"; - - private static InternalCompilerException translateException(JNode node, Throwable e) { - if (e instanceof VirtualMachineError) { - // Always rethrow VM errors (an attempt to wrap may fail). - throw (VirtualMachineError) e; - } - InternalCompilerException ice; - if (e instanceof InternalCompilerException) { - ice = (InternalCompilerException) e; - ice.addNode(node); - } else { - ice = new InternalCompilerException(node, "Error constructing Java AST", e); - } - return ice; - } - - private final AutoboxUtils autoboxUtils; - - private JDeclaredType currentClass; - - private ClassScope currentClassScope; - - private String currentFileName; - - private JMethod currentMethod; - - private JMethodBody currentMethodBody; - - private MethodScope currentMethodScope; - - private Map<JField, JParameter> currentOuterThisRefParams; - - private int[] currentSeparatorPositions; - - private final boolean disableClassMetadata; - - private final boolean enableAsserts; - - private final Map<JsniMethodBody, AbstractMethodDeclaration> jsniMethodMap = - new HashMap<JsniMethodBody, AbstractMethodDeclaration>(); - - private final Map<JMethod, Map<String, JLabel>> labelMap = - new IdentityHashMap<JMethod, Map<String, JLabel>>(); - - private final Map<MethodKey, MethodValue> methodCache = new HashMap<MethodKey, MethodValue>(); - - private final JProgram program; - - private final TypeMap typeMap; - - public JavaASTGenerationVisitor(TypeMap typeMap, JProgram program, JJSOptions options) { - this.typeMap = typeMap; - this.program = program; - this.enableAsserts = options.isEnableAssertions(); - - /* - * TODO: Determine if this should be controlled by a compiler flag or a - * module property. - */ - this.disableClassMetadata = options.isClassMetadataDisabled(); - autoboxUtils = new AutoboxUtils(program); - } - - /** - * <p> - * Add a bridge method to <code>clazzBinding</code> for any method it - * inherits that implements an interface method but that has a different - * erased signature from the interface method. - * </p> - * - * <p> - * The need for these bridges was pointed out in issue 3064. The goal is - * that virtual method calls through an interface type are translated to - * JavaScript that will function correctly. If the interface signature - * matches the signature of the implementing method, then nothing special - * needs to be done. If they are different, due to the use of generics, then - * GenerateJavaScriptAST is careful to do the right thing. There is a - * remaining case, though, that GenerateJavaScriptAST is not in a good - * position to fix: a method could be inherited from a superclass, used to - * implement an interface method that has a different type signature, and - * does not have the interface method in its list of overrides. In that - * case, a bridge method should be added that overrides the interface method - * and then calls the implementation method. - * </p> - * - * <p> - * This method should only be called once all regular, non-bridge methods - * have been installed on the GWT types. - * </p> - */ - public void addBridgeMethods(SourceTypeBinding clazzBinding) { - if (clazzBinding.isInterface()) { - // Only add bridges in classes, to simplify matters. - return; - } - - JClassType clazz = (JClassType) typeMap.get(clazzBinding); - - /* - * The JDT adds bridge methods in all the places GWT needs them. Look - * through the bridge methods the JDT added. - */ - if (clazzBinding.syntheticMethods() != null) { - for (SyntheticMethodBinding synthmeth : clazzBinding.syntheticMethods()) { - if (synthmeth.purpose == SyntheticMethodBinding.BridgeMethod && !synthmeth.isStatic()) { - JMethod implmeth = (JMethod) typeMap.get(synthmeth.targetMethod); - - createBridgeMethod(clazz, synthmeth, implmeth); - } - } - } - } - - public void processEnumType(JEnumType type) { - // Generate the synthetic values() method. - JField valuesField = null; - for (JMethod method : type.getMethods()) { - currentMethod = method; - if ("values".equals(method.getName())) { - if (method.getParams().size() != 0) { - continue; - } - currentMethodBody = (JMethodBody) method.getBody(); - valuesField = writeEnumValuesMethod(type); - } - currentMethodBody = null; - currentMethod = null; - } - // Generate the synthetic valueOf() method. - if (isScript(program)) { - for (JMethod method : type.getMethods()) { - currentMethod = method; - if ("valueOf".equals(method.getName())) { - if (method.getParams().size() != 1) { - continue; - } - if (method.getParams().get(0).getType() != program.getTypeJavaLangString()) { - continue; - } - currentMethodBody = (JMethodBody) method.getBody(); - writeEnumValueOfMethod(type, valuesField); - } - currentMethodBody = null; - currentMethod = null; - } - } - } - - /** - * We emulate static initializers and instance initializers as methods. As - * in other cases, this gives us: simpler AST, easier to optimize, more like - * output JavaScript. - */ - public void processType(TypeDeclaration x) { - currentClass = (JDeclaredType) typeMap.get(x.binding); - processArtificialRescues(x.annotations); - try { - currentClassScope = x.scope; - currentSeparatorPositions = x.compilationResult.lineSeparatorPositions; - currentFileName = String.valueOf(x.compilationResult.fileName); - - /* - * Make clinits chain to super class (JDT doesn't write code to do - * this). Call super class $clinit; $clinit is always in position 0. - */ - if (currentClass.getSuperClass() != null) { - JMethod myClinit = currentClass.getMethods().get(0); - JMethod superClinit = currentClass.getSuperClass().getMethods().get(0); - JMethodCall superClinitCall = - new JMethodCall(myClinit.getSourceInfo(), null, superClinit); - JMethodBody body = (JMethodBody) myClinit.getBody(); - body.getBlock().addStmt(0, superClinitCall.makeStatement()); - } - - if (x.fields != null) { - // Process fields - for (int i = 0, n = x.fields.length; i < n; ++i) { - FieldDeclaration fieldDeclaration = x.fields[i]; - if (fieldDeclaration.isStatic()) { - // clinit - currentMethod = currentClass.getMethods().get(0); - currentMethodBody = (JMethodBody) currentMethod.getBody(); - currentMethodScope = x.staticInitializerScope; - } else { - // init - currentMethod = currentClass.getMethods().get(1); - currentMethodBody = (JMethodBody) currentMethod.getBody(); - currentMethodScope = x.initializerScope; - } - - if (fieldDeclaration instanceof Initializer) { - assert (currentClass instanceof JClassType); - processInitializer((Initializer) fieldDeclaration); - } else { - processField(fieldDeclaration); - } - } - } - - currentMethodScope = null; - currentMethod = null; - - if (x.methods != null) { - // Process methods - for (int i = 0, n = x.methods.length; i < n; ++i) { - if (x.methods[i].isConstructor()) { - assert (currentClass instanceof JClassType); - processConstructor((ConstructorDeclaration) x.methods[i]); - } else if (x.methods[i].isClinit()) { - // nothing to do - } else { - processMethod(x.methods[i]); - } - } - } - - // Write the body of the getClass() override. - if (currentClass instanceof JClassType && currentClass != program.getTypeJavaLangObject()) { - JMethod method = currentClass.getMethods().get(2); - assert ("getClass".equals(method.getName())); - - if (program.isJavaScriptObject(currentClass) - && currentClass != program.getJavaScriptObject()) { - // Just use JavaScriptObject's implementation for all subclasses. - currentClass.getMethods().remove(2); - } else { - if (currentClass == program.getIndexedType("Array")) { - /* - * Don't implement, fall through to Object.getClass(). Array emulation code - * in com.google.gwt.lang.Array invokes Array.getClass() and expects to get the - * class literal for the actual runtime type of the array (e.g. Foo[].class) and - * not Array.class. - */ - currentClass.getMethods().remove(2); - } else { - tryFindUpRefs(method); - SourceInfo info = method.getSourceInfo(); - implementMethod(method, new JClassLiteral(info.makeChild(), currentClass)); - } - } - } - - // Reimplement GWT.isClient(), GWT.isProdMode(), GWT.isScript(). - if (currentClass == program.getIndexedType("GWT")) { - JMethod method = program.getIndexedMethod("GWT.isClient"); - implementMethod(method, program.getLiteralBoolean(true)); - - method = program.getIndexedMethod("GWT.isProdMode"); - implementMethod(method, program.getLiteralBoolean(true)); - - method = program.getIndexedMethod("GWT.isScript"); - implementMethod(method, program.getLiteralBoolean(isScript(program))); - } - - // Implement various methods on Class - if (currentClass == program.getTypeJavaLangClass()) { - JMethod method = program.getIndexedMethod("Class.desiredAssertionStatus"); - implementMethod(method, program.getLiteralBoolean(enableAsserts)); - - if (disableClassMetadata) { - JMethod isMetadataEnabledMethod = - program.getIndexedMethod("Class.isClassMetadataEnabled"); - implementMethod(isMetadataEnabledMethod, program.getLiteralBoolean(false)); - } - } - - if (currentClass instanceof JEnumType) { - processEnumType((JEnumType) currentClass); - } - - currentClassScope = null; - currentClass = null; - currentSeparatorPositions = null; - currentFileName = null; - } catch (Throwable e) { - throw translateException(currentClass, e); - } - } - - /** - * This is the guts of the "reflective" part of this visitor. Try to find a - * "process" method that exactly matches the run-time type of the argument. - */ - protected JNode dispatch(String name, Object child) { - if (child == null) { - return null; - } - - try { - Method method = getCachedMethod(name, child.getClass()); - return (JNode) method.invoke(this, child); - } catch (Throwable e) { - if (e instanceof InvocationTargetException) { - e = ((InvocationTargetException) e).getTargetException(); - } - throw translateException(child, e); - } - } - - /** - * Process an Expression type node reflectively; must return a JExpression. - */ - protected JExpression dispProcessExpression(Expression x) { - /* - * Note that we always prefer a JDT-computed constant value to the actual - * written expression. (Let's hope JDT is always right.) This means we - * don't have to write processExpression methods for the numerous JDT - * literal nodes because they ALWAYS have a constant value. - */ - JExpression result = null; - if (x != null && x.constant != null && x.constant != Constant.NotAConstant) { - result = (JExpression) dispatch("processConstant", x.constant); - } - - if (result == null) { - // The expression was not a constant, so use the general logic. - result = (JExpression) dispatch("processExpression", x); - } - - // Check if we need to box the resulting expression. - if (x != null) { - if ((x.implicitConversion & TypeIds.BOXING) != 0) { - result = autoboxUtils.box(result, implicitConversionTargetType(x)); - } else if ((x.implicitConversion & TypeIds.UNBOXING) != 0) { - // This code can actually leave an unbox operation in - // an lvalue position, for example ++(x.intValue()). - // Such trees are cleaned up in FixAssignmentToUnbox. - JType typeToUnbox = (JType) typeMap.get(x.resolvedType); - if (!(typeToUnbox instanceof JClassType)) { - throw new InternalCompilerException(result, "Attempt to unbox a non-class type: " - + typeToUnbox.getName(), null); - } - - result = unbox(result, (JClassType) typeToUnbox); - } - } - return result; - } - - /** - * Process an Statement type node reflectively; must return a JStatement. - */ - protected JStatement dispProcessStatement(Statement x) { - JStatement stmt; - if (x instanceof Expression) { - JExpression expr = dispProcessExpression((Expression) x); - if (expr == null) { - return null; - } - stmt = expr.makeStatement(); - } else { - stmt = (JStatement) dispatch("processStatement", x); - } - return stmt; - } - - Map<JsniMethodBody, AbstractMethodDeclaration> getJsniMethodMap() { - return jsniMethodMap; - } - - JBooleanLiteral processConstant(BooleanConstant x) { - return program.getLiteralBoolean(x.booleanValue()); - } - - JIntLiteral processConstant(ByteConstant x) { - return program.getLiteralInt(x.byteValue()); - } - - JCharLiteral processConstant(CharConstant x) { - return program.getLiteralChar(x.charValue()); - } - - JDoubleLiteral processConstant(DoubleConstant x) { - return program.getLiteralDouble(x.doubleValue()); - } - - JFloatLiteral processConstant(FloatConstant x) { - return program.getLiteralFloat(x.floatValue()); - } - - JIntLiteral processConstant(IntConstant x) { - return program.getLiteralInt(x.intValue()); - } - - JLongLiteral processConstant(LongConstant x) { - return program.getLiteralLong(x.longValue()); - } - - JIntLiteral processConstant(ShortConstant x) { - return program.getLiteralInt(x.shortValue()); - } - - JStringLiteral processConstant(StringConstant x) { - // May be processing an annotation - SourceInfo info = - currentMethod == null ? currentClass.getSourceInfo() : currentMethod.getSourceInfo(); - return program.getLiteralString(info.makeChild(), x.stringValue().toCharArray()); - } - - /** - * This is slightly different from the normal Java language. Specifically, - * we explicitly handle synthetic fields that are part of nested/local - * classes. It boils down to the fact that we really HAVE to assign - * synthetic arguments to synthetic fields BEFORE calling the superclass - * constructor (because it might call you back polymorphically). In straight - * Java that glue code is a semantic error, because a this/super call must - * be the first statement of your constructor. On the upside, optimizations - * work the same on our synthetic fields as with any user fields. - * - * The order of emulation is: - assign all synthetic fields from synthetic - * args - call our super constructor emulation method - call our instance - * initializer emulation method - run user code - */ - void processConstructor(ConstructorDeclaration x) { - JConstructor ctor = (JConstructor) typeMap.get(x.binding); - try { - SourceInfo info = ctor.getSourceInfo(); - - currentMethod = ctor; - currentMethodBody = ctor.getBody(); - currentMethodScope = x.scope; - - /* - * Determine if we have an explicit this call. The presence of an - * explicit this call indicates we can skip certain initialization steps - * (as the callee will perform those steps for us). These skippable - * steps are 1) assigning synthetic args to fields and 2) running - * initializers. - */ - boolean hasExplicitThis = (x.constructorCall != null) && !x.constructorCall.isSuperAccess(); - - JClassType enclosingType = ctor.getEnclosingType(); - JBlock block = currentMethodBody.getBlock(); - currentOuterThisRefParams = Maps.create(); - - /* - * All synthetic fields must be assigned, unless we have an explicit - * this constructor call, in which case the callee will assign them for - * us. - */ - ReferenceBinding declaringClass = x.binding.declaringClass; - if (declaringClass instanceof NestedTypeBinding) { - Iterator<JParameter> paramIt = currentMethod.getParams().iterator(); - NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass; - if (nestedBinding.enclosingInstances != null) { - for (SyntheticArgumentBinding arg : nestedBinding.enclosingInstances) { - JParameter param = paramIt.next(); - JField field = (JField) typeMap.get(arg); - if (!hasExplicitThis) { - block.addStmt(JProgram.createAssignmentStmt(info, createVariableRef(info, field), - createVariableRef(info, param))); - } - currentOuterThisRefParams = Maps.put(currentOuterThisRefParams, field, param); - } - } - - if (!hasExplicitThis) { - paramIt = getSyntheticLocalsIterator(); - if (nestedBinding.outerLocalVariables != null) { - for (SyntheticArgumentBinding arg : nestedBinding.outerLocalVariables) { - JParameter param = paramIt.next(); - JField field = (JField) typeMap.get(arg); - block.addStmt(JProgram.createAssignmentStmt(info, createVariableRef(info, field), - createVariableRef(info, param))); - } - } - } - } - - // optional this or super constructor call - if (x.constructorCall != null) { - JMethodCall superOrThisCall = - (JMethodCall) dispatch("processExpression", x.constructorCall); - // Enums: wire up synthetic name/ordinal params to the super method. - if (enclosingType.isEnumOrSubclass() != null) { - JVariableRef enumNameRef = - createVariableRef(superOrThisCall.getSourceInfo(), ctor.getParams().get(0)); - superOrThisCall.addArg(0, enumNameRef); - JVariableRef enumOrdinalRef = - createVariableRef(superOrThisCall.getSourceInfo(), ctor.getParams().get(1)); - superOrThisCall.addArg(1, enumOrdinalRef); - } - - superOrThisCall.setStaticDispatchOnly(); - block.addStmt(superOrThisCall.makeStatement()); - } - - JExpression thisRef = createThisRef(info, enclosingType); - - /* - * Call the synthetic instance initializer method, unless we have an - * explicit this constructor call, in which case the callee will. - */ - if (!hasExplicitThis) { - // $init is always in position 1 (clinit is in 0) - JMethod initMethod = enclosingType.getMethods().get(1); - JMethodCall initCall = new JMethodCall(info, thisRef, initMethod); - block.addStmt(initCall.makeStatement()); - } - - // user code (finally!) - block.addStmts(processStatements(x.statements)); - - currentOuterThisRefParams = null; - currentMethodScope = null; - currentMethod = null; - } catch (Throwable e) { - throw translateException(ctor, e); - } - } - - JExpression processExpression(AllocationExpression x) { - SourceInfo info = makeSourceInfo(x); - TypeBinding typeBinding = erasure(x.resolvedType); - if (typeBinding.constantPoolName() == null) { - /* - * Weird case: if JDT determines that this local class is totally - * uninstantiable, it won't bother allocating a local name. - */ - return program.getLiteralNull(); - } - JClassType newType = (JClassType) typeMap.get(typeBinding); - MethodBinding b = x.binding; - JConstructor ctor = (JConstructor) typeMap.get(b); - JMethodCall call; - JClassType javaLangString = program.getTypeJavaLangString(); - if (newType == javaLangString && !newType.isExternal()) { - /* - * MAGIC: java.lang.String is implemented as a JavaScript String - * primitive with a modified prototype. This requires funky handling of - * constructor calls. We find a method named _String() whose signature - * matches the requested constructor - */ - int ctorArgc = ctor.getParams().size(); - JMethod targetMethod = null; - outer : for (JMethod method : javaLangString.getMethods()) { - if (method.getName().equals("_String") && method.getParams().size() == ctorArgc) { - for (int i = 0; i < ctorArgc; ++i) { - JParameter mparam = method.getParams().get(i); - JParameter cparam = ctor.getParams().get(i); - if (mparam.getType() != cparam.getType()) { - continue outer; - } - } - targetMethod = method; - break; - } - } - if (targetMethod == null) { - throw new InternalCompilerException( - "String constructor error; no matching implementation."); - } - call = new JMethodCall(makeSourceInfo(x), null, targetMethod); - } else { - call = new JNewInstance(info, ctor, currentClass); - } - - // Enums: hidden arguments for the name and id. - if (x.enumConstant != null) { - call.addArgs(program.getLiteralString(info, x.enumConstant.name), program - .getLiteralInt(x.enumConstant.binding.original().id)); - } - - // Synthetic args for inner classes - ReferenceBinding targetBinding = b.declaringClass; - if (targetBinding.isNestedType() && !targetBinding.isStatic()) { - NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(targetBinding); - // Synthetic this args for inner classes - if (nestedBinding.enclosingInstances != null) { - for (SyntheticArgumentBinding arg : nestedBinding.enclosingInstances) { - JClassType syntheticThisType = (JClassType) typeMap.get(arg.type); - call.addArg(createThisRef(info, syntheticThisType)); - } - } - } - - // Plain old regular user arguments - addCallArgs(x.arguments, call, b); - - // Synthetic args for inner classes - if (targetBinding.isNestedType() && !targetBinding.isStatic()) { - NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(targetBinding); - // Synthetic locals for local classes - if (nestedBinding.outerLocalVariables != null) { - for (SyntheticArgumentBinding arg : nestedBinding.outerLocalVariables) { - JVariable variable = (JVariable) typeMap.get(arg.actualOuterLocalVariable); - call.addArg(createVariableRef(info, variable, arg.actualOuterLocalVariable)); - } - } - } - - return call; - } - - JExpression processExpression(AND_AND_Expression x) { - JType type = (JType) typeMap.get(x.resolvedType); - SourceInfo info = makeSourceInfo(x); - return processBinaryOperation(info, JBinaryOperator.AND, type, x.left, x.right); - } - - JExpression processExpression(ArrayAllocationExpression x) { - SourceInfo info = makeSourceInfo(x); - JArrayType type = (JArrayType) typeMap.get(x.resolvedType); - - if (x.initializer != null) { - List<JExpression> initializers = new ArrayList<JExpression>(); - if (x.initializer.expressions != null) { - for (Expression expression : x.initializer.expressions) { - initializers.add(dispProcessExpression(expression)); - } - } - return JNewArray.createInitializers(info, type, initializers); - } else { - List<JExpression> dims = new ArrayList<JExpression>(); - for (Expression dimension : x.dimensions) { - // can be null if index expression was empty - if (dimension == null) { - dims.add(program.getLiteralAbsentArrayDimension()); - } else { - dims.add(dispProcessExpression(dimension)); - } - } - return JNewArray.createDims(info, type, dims); - } - } - - JExpression processExpression(ArrayInitializer x) { - SourceInfo info = makeSourceInfo(x); - JArrayType type = (JArrayType) typeMap.get(x.resolvedType); - - List<JExpression> initializers = new ArrayList<JExpression>(); - if (x.expressions != null) { - for (Expression expression : x.expressions) { - initializers.add(dispProcessExpression(expression)); - } - } - return JNewArray.createInitializers(info, type, initializers); - } - - JExpression processExpression(ArrayReference x) { - SourceInfo info = makeSourceInfo(x); - JArrayRef arrayRef = - new JArrayRef(info, dispProcessExpression(x.receiver), dispProcessExpression(x.position)); - return arrayRef; - } - - JExpression processExpression(Assignment x) { - JType type = (JType) typeMap.get(x.resolvedType); - SourceInfo info = makeSourceInfo(x); - return processBinaryOperation(info, JBinaryOperator.ASG, type, x.lhs, x.expression); - } - - JExpression processExpression(BinaryExpression x) { - JBinaryOperator op; - - int binOp = (x.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; - switch (binOp) { - case OperatorIds.LEFT_SHIFT: - op = JBinaryOperator.SHL; - break; - case OperatorIds.RIGHT_SHIFT: - op = JBinaryOperator.SHR; - break; - case OperatorIds.UNSIGNED_RIGHT_SHIFT: - op = JBinaryOperator.SHRU; - break; - case OperatorIds.PLUS: - if (program.isJavaLangString((JType) typeMap.get(x.resolvedType))) { - op = JBinaryOperator.CONCAT; - } else { - op = JBinaryOperator.ADD; - } - break; - case OperatorIds.MINUS: - op = JBinaryOperator.SUB; - break; - case OperatorIds.REMAINDER: - op = JBinaryOperator.MOD; - break; - case OperatorIds.XOR: - op = JBinaryOperator.BIT_XOR; - break; - case OperatorIds.AND: - op = JBinaryOperator.BIT_AND; - break; - case OperatorIds.MULTIPLY: - op = JBinaryOperator.MUL; - break; - case OperatorIds.OR: - op = JBinaryOperator.BIT_OR; - break; - case OperatorIds.DIVIDE: - op = JBinaryOperator.DIV; - break; - case OperatorIds.LESS_EQUAL: - op = JBinaryOperator.LTE; - break; - case OperatorIds.GREATER_EQUAL: - op = JBinaryOperator.GTE; - break; - case OperatorIds.GREATER: - op = JBinaryOperator.GT; - break; - case OperatorIds.LESS: - op = JBinaryOperator.LT; - break; - default: - throw new InternalCompilerException("Unexpected operator for BinaryExpression"); - } - - JType type = (JType) typeMap.get(x.resolvedType); - SourceInfo info = makeSourceInfo(x); - return processBinaryOperation(info, op, type, x.left, x.right); - } - - JExpression processExpression(CastExpression x) { - SourceInfo info = makeSourceInfo(x); - JType type = (JType) typeMap.get(x.resolvedType); - JCastOperation cast = new JCastOperation(info, type, dispProcessExpression(x.expression)); - return cast; - } - - JExpression processExpression(ClassLiteralAccess x) { - SourceInfo info = makeSourceInfo(x); - JType type = (JType) typeMap.get(x.targetType); - return new JClassLiteral(info, type); - } - - JExpression processExpression(CombinedBinaryExpression x) { - return processExpression((BinaryExpression) x); - } - - JExpression processExpression(CompoundAssignment x) { - JBinaryOperator op; - - switch (x.operator) { - case OperatorIds.PLUS: - if (program.isJavaLangString((JType) typeMap.get(x.resolvedType))) { - op = JBinaryOperator.ASG_CONCAT; - } else { - op = JBinaryOperator.ASG_ADD; - } - break; - case OperatorIds.MINUS: - op = JBinaryOperator.ASG_SUB; - break; - case OperatorIds.MULTIPLY: - op = JBinaryOperator.ASG_MUL; - break; - case OperatorIds.DIVIDE: - op = JBinaryOperator.ASG_DIV; - break; - case OperatorIds.AND: - op = JBinaryOperator.ASG_BIT_AND; - break; - case OperatorIds.OR: - op = JBinaryOperator.ASG_BIT_OR; - break; - case OperatorIds.XOR: - op = JBinaryOperator.ASG_BIT_XOR; - break; - case OperatorIds.REMAINDER: - op = JBinaryOperator.ASG_MOD; - break; - case OperatorIds.LEFT_SHIFT: - op = JBinaryOperator.ASG_SHL; - break; - case OperatorIds.RIGHT_SHIFT: - op = JBinaryOperator.ASG_SHR; - break; - case CompoundAssignment.UNSIGNED_RIGHT_SHIFT: - op = JBinaryOperator.ASG_SHRU; - break; - default: - throw new InternalCompilerException("Unexpected operator for CompoundAssignment"); - } - - JType type = (JType) typeMap.get(x.resolvedType); - SourceInfo info = makeSourceInfo(x); - return processBinaryOperation(info, op, type, x.lhs, x.expression); - } - - JExpression processExpression(ConditionalExpression x) { - SourceInfo info = makeSourceInfo(x); - JType type = (JType) typeMap.get(x.resolvedType); - JExpression ifTest = dispProcessExpression(x.condition); - JExpression thenExpr = dispProcessExpression(x.valueIfTrue); - JExpression elseExpr = dispProcessExpression(x.valueIfFalse); - JConditional conditional = new JConditional(info, type, ifTest, thenExpr, elseExpr); - return conditional; - } - - JExpression processExpression(EqualExpression x) { - JBinaryOperator op; - switch ((x.bits & BinaryExpression.OperatorMASK) >> BinaryExpression.OperatorSHIFT) { - case BinaryExpression.EQUAL_EQUAL: - op = JBinaryOperator.EQ; - break; - case BinaryExpression.NOT_EQUAL: - op = JBinaryOperator.NEQ; - break; - default: - throw new InternalCompilerException("Unexpected operator for EqualExpression"); - } - - JType type = (JType) typeMap.get(x.resolvedType); - SourceInfo info = makeSourceInfo(x); - return processBinaryOperation(info, op, type, x.left, x.right); - } - - /** - * How we have to treat super calls vs. this calls is so different, they may - * as well have been two different JDT nodes. - */ - JMethodCall processExpression(ExplicitConstructorCall x) { - if (x.isSuperAccess()) { - return processSuperConstructorCall(x); - } else { - return processThisConstructorCall(x); - } - } - - JExpression processExpression(FieldReference x) { - FieldBinding fieldBinding = x.binding; - SourceInfo info = makeSourceInfo(x); - JExpression instance = dispProcessExpression(x.receiver); - JExpression expr; - if (fieldBinding.declaringClass == null) { - if (!ARRAY_LENGTH_FIELD.equals(String.valueOf(fieldBinding.name))) { - throw new InternalCompilerException("Expected [array].length."); - } - expr = new JArrayLength(info, instance); - } else { - JField field = (JField) typeMap.get(fieldBinding); - expr = new JFieldRef(info, instance, field, currentClass); - } - - if (x.genericCast != null) { - JType castType = (JType) typeMap.get(x.genericCast); - /* - * Note, this may result in an invalid AST due to an LHS cast operation. - * We fix this up in FixAssignmentToUnbox. - */ - return maybeCast(castType, expr); - } - return expr; - } - - JExpression processExpression(InstanceOfExpression x) { - SourceInfo info = makeSourceInfo(x); - JExpression expr = dispProcessExpression(x.expression); - JReferenceType testType = (JReferenceType) typeMap.get(x.type.resolvedType); - return new JInstanceOf(info, testType, expr); - } - - JExpression processExpression(MessageSend x) { - SourceInfo info = makeSourceInfo(x); - JMethod method = (JMethod) typeMap.get(x.binding); - - JExpression qualifier; - if (x.receiver instanceof ThisReference) { - if (method.isStatic()) { - // don't bother qualifying it, it's a no-op - qualifier = null; - } else if (x.receiver instanceof QualifiedThisReference) { - // use the supplied qualifier - qualifier = dispProcessExpression(x.receiver); - } else { - /* - * In cases where JDT had to synthesize a this ref for us, it could - * actually be the wrong type, if the target method is in an enclosing - * class. We have to synthesize our own ref of the correct type. - */ - qualifier = createThisRef(info, method.getEnclosingType()); - } - } else { - qualifier = dispProcessExpression(x.receiver); - } - - JMethodCall call = new JMethodCall(info, qualifier, method); - - // On a super ref, don't allow polymorphic dispatch. Oddly enough, - // QualifiedSuperReference not derived from SuperReference! - boolean isSuperRef = - x.receiver instanceof SuperReference || x.receiver instanceof QualifiedSuperReference; - if (isSuperRef) { - call.setStaticDispatchOnly(); - } - - // The arguments come first... - addCallArgs(x.arguments, call, x.binding); - - if (x.valueCast != null) { - JType castType = (JType) typeMap.get(x.valueCast); - return maybeCast(castType, call); - } - return call; - } - - JExpression processExpression(NullLiteral x) { - return program.getLiteralNull(); - } - - JExpression processExpression(OR_OR_Expression x) { - JType type = (JType) typeMap.get(x.resolvedType); - SourceInfo info = makeSourceInfo(x); - return processBinaryOperation(info, JBinaryOperator.OR, type, x.left, x.right); - } - - JExpression processExpression(PostfixExpression x) { - SourceInfo info = makeSourceInfo(x); - JUnaryOperator op; - - switch (x.operator) { - case PostfixExpression.MINUS: - op = JUnaryOperator.DEC; - break; - - case PostfixExpression.PLUS: - op = JUnaryOperator.INC; - break; - - default: - throw new InternalCompilerException("Unexpected postfix operator"); - } - - JPostfixOperation postOp = new JPostfixOperation(info, op, dispProcessExpression(x.lhs)); - return postOp; - } - - JExpression processExpression(PrefixExpression x) { - SourceInfo info = makeSourceInfo(x); - JUnaryOperator op; - - switch (x.operator) { - case PrefixExpression.MINUS: - op = JUnaryOperator.DEC; - break; - - case PrefixExpression.PLUS: - op = JUnaryOperator.INC; - break; - - default: - throw new InternalCompilerException("Unexpected prefix operator"); - } - - JPrefixOperation preOp = new JPrefixOperation(info, op, dispProcessExpression(x.lhs)); - return preOp; - } - - JExpression processExpression(QualifiedAllocationExpression x) { - /* - * Weird: sometimes JDT will create a QualifiedAllocationExpression with - * no qualifier. I guess this is supposed to let us know that we need to - * synthesize a synthetic this arg based on our own current "this"? But - * plain old regular AllocationExpression also must be treated as if it - * might be be implicitly qualified, so I'm not sure what the point is. - * Let's just defer to the AllocationExpression logic if there's no - * qualifier. - */ - if (x.enclosingInstance() == null) { - return processExpression((AllocationExpression) x); - } - - SourceInfo info = makeSourceInfo(x); - MethodBinding b = x.binding; - JConstructor ctor = (JConstructor) typeMap.get(b); - JNewInstance newInstance = new JNewInstance(info, ctor, currentClass); - JExpression qualifier = dispProcessExpression(x.enclosingInstance); - List<JExpression> qualList = new ArrayList<JExpression>(); - qualList.add(qualifier); - - /* - * Really weird: Sometimes an allocation expression needs both its - * explicit qualifier AND its implicit enclosing class! We add this second - * because the explicit qualifier takes precedence. - */ - if (!currentMethod.isStatic()) { - JExpression implicitOuter = new JThisRef(info, (JClassType) currentClass); - qualList.add(implicitOuter); - } - - // Synthetic this args for inner classes - ReferenceBinding targetBinding = b.declaringClass; - if (targetBinding.isNestedType() && !targetBinding.isStatic()) { - NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(targetBinding); - if (nestedBinding.enclosingInstances != null) { - for (SyntheticArgumentBinding arg : nestedBinding.enclosingInstances) { - JClassType syntheticThisType = (JClassType) typeMap.get(arg.type); - newInstance.addArg(createThisRef(syntheticThisType, qualList)); - } - } - } - - // Plain old regular arguments - addCallArgs(x.arguments, newInstance, b); - - // Synthetic locals for local classes - if (targetBinding.isNestedType() && !targetBinding.isStatic()) { - NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(targetBinding); - if (nestedBinding.outerLocalVariables != null) { - for (SyntheticArgumentBinding arg : nestedBinding.outerLocalVariables) { - JVariable variable = (JVariable) typeMap.get(arg.actualOuterLocalVariable); - newInstance.addArg(createVariableRef(info, variable, arg.actualOuterLocalVariable)); - } - } - } - - return newInstance; - } - - JExpression processExpression(QualifiedNameReference x) { - SourceInfo info = makeSourceInfo(x); - Binding binding = x.binding; - JNode node = typeMap.get(binding); - if (!(node instanceof JVariable)) { - return null; - } - JVariable variable = (JVariable) node; - - JExpression curRef = createVariableRef(info, variable, binding); - if (x.genericCast != null) { - JType castType = (JType) typeMap.get(x.genericCast); - curRef = maybeCast(castType, curRef); - } - - /* - * Wackiness: JDT represents multiple field access as an array of fields, - * each qualified by everything to the left. So each subsequent item in - * otherBindings takes the current expression as a qualifier. - */ - if (x.otherBindings != null) { - for (int i = 0; i < x.otherBindings.length; ++i) { - FieldBinding fieldBinding = x.otherBindings[i]; - if (fieldBinding.declaringClass == null) { - // probably array.length - if (!ARRAY_LENGTH_FIELD.equals(String.valueOf(fieldBinding.name))) { - throw new InternalCompilerException("Expected [array].length."); - } - curRef = new JArrayLength(info, curRef); - } else { - JField field = (JField) typeMap.get(fieldBinding); - curRef = new JFieldRef(info, curRef, field, currentClass); - } - if (x.otherGenericCasts != null && x.otherGenericCasts[i] != null) { - JType castType = (JType) typeMap.get(x.otherGenericCasts[i]); - curRef = maybeCast(castType, curRef); - } - } - } - - return curRef; - } - - JExpression processExpression(QualifiedSuperReference x) { - JClassType refType = (JClassType) typeMap.get(x.resolvedType); - JClassType qualType = (JClassType) typeMap.get(x.qualification.resolvedType); - assert (refType == qualType.getSuperClass()); - // Oddly enough, super refs can be modeled as this refs, because whatever - // expression they qualify has already been resolved. - return processQualifiedThisOrSuperRef(x, qualType); - } - - JExpression processExpression(QualifiedThisReference x) { - JClassType refType = (JClassType) typeMap.get(x.resolvedType); - JClassType qualType = (JClassType) typeMap.get(x.qualification.resolvedType); - assert (refType == qualType); - return processQualifiedThisOrSuperRef(x, qualType); - } - - JExpression processExpression(SingleNameReference x) { - SourceInfo info = makeSourceInfo(x); - Binding binding = x.binding; - Object target = typeMap.get(binding); - if (!(target instanceof JVariable)) { - return null; - } - JVariable variable = (JVariable) target; - - /* - * Wackiness: if a field happens to have synthetic accessors (only fields - * can have them, apparently), this is a ref to a field in an enclosing - * instance. CreateThisRef should compute a "this" access of the - * appropriate type, unless the field is static. - */ - JExpression result = null; - if (x.syntheticAccessors != null) { - JField field = (JField) variable; - if (!field.isStatic()) { - JExpression instance = createThisRef(info, field.getEnclosingType()); - result = new JFieldRef(info, instance, field, currentClass); - } - } - if (result == null) { - result = createVariableRef(info, variable, binding); - } - if (x.genericCast != null) { - JType castType = (JType) typeMap.get(x.genericCast); - result = maybeCast(castType, result); - } - return result; - } - - JExpression processExpression(SuperReference x) { - JClassType type = (JClassType) typeMap.get(x.resolvedType); - assert (type == currentClass.getSuperClass()); - SourceInfo info = makeSourceInfo(x); - // Oddly enough, super refs can be modeled as a this refs. - JExpression superRef = createThisRef(info, currentClass); - return superRef; - } - - JExpression processExpression(ThisReference x) { - JClassType type = (JClassType) typeMap.get(x.resolvedType); - assert (type == currentClass); - SourceInfo info = makeSourceInfo(x); - JExpression thisRef = createThisRef(info, currentClass); - return thisRef; - } - - JExpression processExpression(UnaryExpression x) { - SourceInfo info = makeSourceInfo(x); - JUnaryOperator op; - int operator = ((x.bits & UnaryExpression.OperatorMASK) >> UnaryExpression.OperatorSHIFT); - - switch (operator) { - case UnaryExpression.MINUS: - op = JUnaryOperator.NEG; - break; - - case UnaryExpression.NOT: - op = JUnaryOperator.NOT; - break; - - case UnaryExpression.PLUS: - // Odd case.. a useless + operator; just return the operand - return dispProcessExpression(x.expression); - - case UnaryExpression.TWIDDLE: - op = JUnaryOperator.BIT_NOT; - break; - - default: - throw new InternalCompilerException("Unexpected operator for unary expression"); - } - - JPrefixOperation preOp = new JPrefixOperation(info, op, dispProcessExpression(x.expression)); - return preOp; - } - - List<JExpressionStatement> processExpressionStatements(Statement[] statements) { - List<JExpressionStatement> jstatements = new ArrayList<JExpressionStatement>(); - if (statements != null) { - for (int i = 0, n = statements.length; i < n; ++i) { - JStatement jstmt = dispProcessStatement(statements[i]); - if (jstmt != null) { - jstatements.add((JExpressionStatement) jstmt); - } - } - } - return jstatements; - } - - void processField(FieldDeclaration declaration) { - JField field = (JField) typeMap.tryGet(declaration.binding); - if (field == null) { - /* - * When anonymous classes declare constant fields, the field declaration - * is not visited by JDT. Just bail since any references to that field - * are guaranteed to be replaced with literals. - */ - return; - } - try { - JExpression initializer = null; - if (declaration.initialization != null) { - initializer = dispProcessExpression(declaration.initialization); - } - - if (field instanceof JEnumField) { - // An enum field must be initialized! - assert (initializer instanceof JMethodCall); - } - - if (initializer != null) { - SourceInfo info = makeSourceInfo(declaration); - // JDeclarationStatement's ctor sets up the field's initializer. - JStatement decl = - new JDeclarationStatement(info, createVariableRef(info, field), initializer); - // will either be init or clinit - currentMethodBody.getBlock().addStmt(decl); - } - } catch (Throwable e) { - throw translateException(field, e); - } - } - - void processInitializer(Initializer initializer) { - JBlock block = (JBlock) dispProcessStatement(initializer.block); - try { - // will either be init or clinit - currentMethodBody.getBlock().addStmt(block); - } catch (Throwable e) { - throw translateException(initializer, e); - } - } - - void processMethod(AbstractMethodDeclaration x) { - MethodBinding b = x.binding; - JMethod method = (JMethod) typeMap.get(b); - try { - if (!b.isStatic() && (b.isImplementing() || b.isOverriding())) { - tryFindUpRefs(method, b); - } - - if (x.isNative()) { - processNativeMethod(x, (JsniMethodBody) method.getBody()); - return; - } - - currentMethod = method; - currentMethodBody = (JMethodBody) method.getBody(); - currentMethodScope = x.scope; - - if (currentMethodBody != null) { - currentMethodBody.getBlock().addStmts(processStatements(x.statements)); - } - currentMethodScope = null; - currentMethodBody = null; - currentMethod = null; - } catch (Throwable e) { - throw translateException(method, e); - } - } - - void processNativeMethod(AbstractMethodDeclaration x, JsniMethodBody nativeMethodBody) { - // Squirrel away a reference to the JDT node to enable error reporting. - jsniMethodMap.put(nativeMethodBody, x); - } - - JStatement processStatement(AssertStatement x) { - SourceInfo info = makeSourceInfo(x); - JExpression expr = dispProcessExpression(x.assertExpression); - JExpression arg = dispProcessExpression(x.exceptionArgument); - return new JAssertStatement(info, expr, arg); - } - - JBlock processStatement(Block x) { - if (x == null) { - return null; - } - - SourceInfo info = makeSourceInfo(x); - JBlock block = new JBlock(info); - block.addStmts(processStatements(x.statements)); - return block; - } - - JStatement processStatement(BreakStatement x) { - SourceInfo info = makeSourceInfo(x); - return new JBreakStatement(info, getOrCreateLabel(info, currentMethod, x.label)); - } - - JStatement processStatement(CaseStatement x) { - SourceInfo info = makeSourceInfo(x); - JExpression expression = dispProcessExpression(x.constantExpression); - if (expression != null && x.constantExpression.resolvedType.isEnum()) { - // TODO: propagate enum information? - assert (expression instanceof JFieldRef); - JFieldRef fieldRef = (JFieldRef) expression; - JEnumField field = (JEnumField) fieldRef.getField(); - return new JCaseStatement(info, program.getLiteralInt(field.ordinal())); - } else { - return new JCaseStatement(info, (JLiteral) expression); - } - } - - JStatement processStatement(ContinueStatement x) { - SourceInfo info = makeSourceInfo(x); - return new JContinueStatement(info, getOrCreateLabel(info, currentMethod, x.label)); - } - - JStatement processStatement(DoStatement x) { - SourceInfo info = makeSourceInfo(x); - JExpression loopTest = dispProcessExpression(x.condition); - JStatement loopBody = dispProcessStatement(x.action); - JDoStatement stmt = new JDoStatement(info, loopTest, loopBody); - return stmt; - } - - JStatement processStatement(EmptyStatement x) { - return null; - } - - JStatement processStatement(ForeachStatement x) { - SourceInfo info = makeSourceInfo(x); - - JBlock body; - JStatement action = dispProcessStatement(x.action); - if (action instanceof JBlock) { - body = (JBlock) action; - } else { - body = new JBlock(info); - if (action != null) { - body.addStmt(action); - } - } - - JLocal elementVar = (JLocal) typeMap.get(x.elementVariable.binding); - String elementVarName = elementVar.getName(); - - JDeclarationStatement elementDecl = - (JDeclarationStatement) processStatement(x.elementVariable); - assert (elementDecl.initializer == null); - - JForStatement result; - if (x.collectionVariable != null) { - /** - * <pre> - * for (final T[] i$array = collection, - * int i$index = 0, - * final int i$max = i$array.length; - * i$index < i$max; ++i$index) { - * T elementVar = i$array[i$index]; - * // user action - * } - * </pre> - */ - JLocal arrayVar = - JProgram.createLocal(info, elementVarName + "$array", ((JType) typeMap - .get(x.collection.resolvedType)), true, currentMethodBody); - JLocal indexVar = - JProgram.createLocal(info, elementVarName + "$index", program.getTypePrimitiveInt(), - false, currentMethodBody); - JLocal maxVar = - JProgram.createLocal(info, elementVarName + "$max", program.getTypePrimitiveInt(), - true, currentMethodBody); - - List<JStatement> initializers = new ArrayList<JStatement>(3); - // T[] i$array = arr - initializers.add(createDeclaration(info, arrayVar, dispProcessExpression(x.collection))); - // int i$index = 0 - initializers.add(createDeclaration(info, indexVar, program.getLiteralInt(0))); - // int i$max = i$array.length - initializers.add(createDeclaration(info, maxVar, new JArrayLength(info, new JLocalRef(info, - arrayVar)))); - - // i$index < i$max - JExpression condition = - new JBinaryOperation(info, program.getTypePrimitiveBoolean(), JBinaryOperator.LT, - createVariableRef(info, indexVar), createVariableRef(info, maxVar)); - - // ++i$index - List<JExpressionStatement> increments = new ArrayList<JExpressionStatement>(1); - increments.add(new JPrefixOperation(info, JUnaryOperator.INC, createVariableRef(info, - indexVar)).makeStatement()); - - // T elementVar = i$array[i$index]; - elementDecl.initializer = - new JArrayRef(info, createVariableRef(info, arrayVar), - createVariableRef(info, indexVar)); - body.addStmt(0, elementDecl); - - result = new JForStatement(info, initializers, condition, increments, body); - } else { - /** - * <pre> - * for (Iterator<T> i$iterator = collection.iterator(); i$iterator.hasNext();) { - * T elementVar = i$iterator.next(); - * // user action - * } - * </pre> - */ - JLocal iteratorVar = - JProgram.createLocal(info, (elementVarName + "$iterator"), program - .getIndexedType("Iterator"), false, currentMethodBody); - - List<JStatement> initializers = new ArrayList<JStatement>(1); - // Iterator<T> i$iterator = collection.iterator() - initializers.add(createDeclaration(info, iteratorVar, new JMethodCall(info, - dispProcessExpression(x.collection), program.getIndexedMethod("Iterable.iterator")))); - - // i$iterator.hasNext() - JExpression condition = - new JMethodCall(info, createVariableRef(info, iteratorVar), program - .getIndexedMethod("Iterator.hasNext")); - - // T elementVar = (T) i$iterator.next(); - elementDecl.initializer = - new JMethodCall(info, createVariableRef(info, iteratorVar), program - .getIndexedMethod("Iterator.next")); - - // Perform any implicit reference type casts (due to generics). - // Note this occurs before potential unboxing. - if (elementVar.getType() != program.getTypeJavaLangObject()) { - TypeBinding collectionType; - try { - // TODO: This is slow! Cache lookup. - Field privateField = ForeachStatement.class.getDeclaredField("collectionElementType"); - privateField.setAccessible(true); - collectionType = (TypeBinding) privateField.get(x); - } catch (Exception e) { - throw new InternalCompilerException(elementDecl, - "Failed to retreive collectionElementType through reflection", e); - } - JType toType = (JType) typeMap.get(collectionType); - assert (toType instanceof JReferenceType); - elementDecl.initializer = maybeCast(toType, elementDecl.initializer); - } - - body.addStmt(0, elementDecl); - - result = - new JForStatement(info, initializers, condition, Collections - .<JExpressionStatement> emptyList(), body); - } - - // May need to box or unbox the element assignment. - if (x.elementVariableImplicitWidening != -1) { - if ((x.elementVariableImplicitWidening & TypeIds.BOXING) != 0) { - /* - * Boxing is necessary. In this special case of autoboxing, the boxed - * expression cannot be a constant, so the box type must be exactly - * that associated with the expression. - */ - elementDecl.initializer = - autoboxUtils.box(elementDecl.initializer, ((JPrimitiveType) elementDecl.initializer - .getType())); - } else if ((x.elementVariableImplicitWidening & TypeIds.UNBOXING) != 0) { - elementDecl.initializer = - unbox(elementDecl.initializer, (JClassType) elementDecl.initializer.getType()); - } - } - return result; - } - - JStatement processStatement(ForStatement x) { - SourceInfo info = makeSourceInfo(x); - // SEE NOTE ON JDT FORCED OPTIMIZATIONS - // If the condition is false, don't process the body - boolean removeBody = isOptimizedFalse(x.condition); - - List<JStatement> init = processStatements(x.initializations); - JExpression expr = dispProcessExpression(x.condition); - List<JExpressionStatement> incr = processExpressionStatements(x.increments); - JStatement body = removeBody ? null : dispProcessStatement(x.action); - return new JForStatement(info, init, expr, incr, body); - } - - JStatement processStatement(IfStatement x) { - // SEE NOTE ON JDT FORCED OPTIMIZATIONS - // If the condition is false, don't process the then statement - // If the condition is false, don't process the else statement - boolean removeThen = isOptimizedFalse(x.condition); - boolean removeElse = isOptimizedTrue(x.condition); - - SourceInfo info = makeSourceInfo(x); - JExpression expr = dispProcessExpression(x.condition); - JStatement thenStmt = removeThen ? null : dispProcessStatement(x.thenStatement); - JStatement elseStmt = removeElse ? null : dispProcessStatement(x.elseStatement); - JIfStatement ifStmt = new JIfStatement(info, expr, thenStmt, elseStmt); - return ifStmt; - } - - JStatement processStatement(LabeledStatement x) { - JStatement body = dispProcessStatement(x.statement); - if (body == null) { - return null; - } - SourceInfo info = makeSourceInfo(x); - return new JLabeledStatement(info, getOrCreateLabel(info, currentMethod, x.label), body); - } - - JStatement processStatement(LocalDeclaration x) { - SourceInfo info = makeSourceInfo(x); - JLocal local = (JLocal) typeMap.get(x.binding); - JLocalRef localRef = new JLocalRef(info, local); - JExpression initializer = dispProcessExpression(x.initialization); - return new JDeclarationStatement(info, localRef, initializer); - } - - JStatement processStatement(ReturnStatement x) { - SourceInfo info = makeSourceInfo(x); - return new JReturnStatement(info, dispProcessExpression(x.expression)); - } - - JStatement processStatement(SwitchStatement x) { - SourceInfo info = makeSourceInfo(x); - JExpression expression = dispProcessExpression(x.expression); - if (isEnumType(expression.getType())) { - // Must be an enum; synthesize a call to ordinal(). - expression = new JMethodCall(info, expression, program.getIndexedMethod("Enum.ordinal")); - } - JBlock block = new JBlock(info); - // Don't use processStatements here, because it stops at control breaks - if (x.statements != null) { - for (Statement stmt : x.statements) { - JStatement jstmt = dispProcessStatement(stmt); - if (jstmt != null) { - block.addStmt(jstmt); - } - } - } - return new JSwitchStatement(info, expression, block); - } - - JStatement processStatement(SynchronizedStatement x) { - JBlock block = (JBlock) dispProcessStatement(x.block); - JExpression expr = dispProcessExpression(x.expression); - block.addStmt(0, expr.makeStatement()); - return block; - } - - JStatement processStatement(ThrowStatement x) { - SourceInfo info = makeSourceInfo(x); - JExpression toThrow = dispProcessExpression(x.exception); - return new JThrowStatement(info, toThrow); - } - - JStatement processStatement(TryStatement x) { - SourceInfo info = makeSourceInfo(x); - JBlock tryBlock = (JBlock) dispProcessStatement(x.tryBlock); - List<JLocalRef> catchArgs = new ArrayList<JLocalRef>(); - List<JBlock> catchBlocks = new ArrayList<JBlock>(); - if (x.catchBlocks != null) { - for (int i = 0, c = x.catchArguments.length; i < c; ++i) { - JLocal local = (JLocal) typeMap.get(x.catchArguments[i].binding); - catchArgs.add((JLocalRef) createVariableRef(info, local)); - } - for (int i = 0, c = x.catchBlocks.length; i < c; ++i) { - catchBlocks.add((JBlock) dispProcessStatement(x.catchBlocks[i])); - } - } - JBlock finallyBlock = (JBlock) dispProcessStatement(x.finallyBlock); - return new JTryStatement(info, tryBlock, catchArgs, catchBlocks, finallyBlock); - } - - JStatement processStatement(TypeDeclaration x) { - // do nothing -- the local class is treated at the program level - return null; - } - - JStatement processStatement(WhileStatement x) { - // SEE NOTE ON JDT FORCED OPTIMIZATIONS - // If the condition is false, don't process the body - boolean removeBody = isOptimizedFalse(x.condition); - - SourceInfo info = makeSourceInfo(x); - JExpression loopTest = dispProcessExpression(x.condition); - JStatement loopBody = removeBody ? null : dispProcessStatement(x.action); - JWhileStatement stmt = new JWhileStatement(info, loopTest, loopBody); - return stmt; - } - - List<JStatement> processStatements(Statement[] statements) { - List<JStatement> jstatements = new ArrayList<JStatement>(); - if (statements != null) { - for (Statement stmt : statements) { - JStatement jstmt = dispProcessStatement(stmt); - if (jstmt != null) { - jstatements.add(jstmt); - if (jstmt.unconditionalControlBreak()) { - /* - * Stop processing statements, because the remaining ones are - * unreachable. The JDT compiler might not have fully fleshed out - * the unreachable statements. - */ - break; - } - } - } - } - - return jstatements; - } - - JMethodCall processSuperConstructorCall(ExplicitConstructorCall x) { - SourceInfo info = makeSourceInfo(x); - JMethod ctor = (JMethod) typeMap.get(x.binding); - JExpression trueQualifier = createThisRef(info, currentClass); - JMethodCall call = new JMethodCall(info, trueQualifier, ctor); - - // We have to find and pass through any synthetics our supertype needs - ReferenceBinding superClass = x.binding.declaringClass; - if (superClass.isNestedType() && !superClass.isStatic()) { - ReferenceBinding myBinding = currentClassScope.referenceType().binding; - ReferenceBinding superBinding = superClass; - - // enclosing types - if (superBinding.syntheticEnclosingInstanceTypes() != null) { - JExpression qualifier = dispProcessExpression(x.qualification); - for (ReferenceBinding arg : superBinding.syntheticEnclosingInstanceTypes()) { - JClassType classType = (JClassType) typeMap.get(arg); - if (qualifier == null) { - /* - * Got to be one of my params; it would be illegal to use a this - * ref at this moment-- we would most likely be passing in a - * supertype field that HASN'T BEEN INITIALIZED YET. - * - * Unfortunately, my params might not work as-is, so we have to - * check each one to see if any will make a suitable this ref. - */ - List<JExpression> workList = new ArrayList<JExpression>(); - Iterator<JParameter> paramIt = currentMethod.getParams().iterator(); - for (ReferenceBinding b : myBinding.syntheticEnclosingInstanceTypes()) { - workList.add(createVariableRef(info, paramIt.next())); - } - call.addArg(createThisRef(classType, workList)); - } else { - call.addArg(createThisRef(classType, qualifier)); - } - } - } - } - - addCallArgs(x.arguments, call, x.binding); - - // We have to find and pass through any synthetics our supertype needs - if (superClass.isNestedType() && !superClass.isStatic()) { - ReferenceBinding superBinding = superClass; - - // outer locals - if (superBinding.syntheticOuterLocalVariables() != null) { - for (SyntheticArgumentBinding arg : superBinding.syntheticOuterLocalVariables()) { - // Got to be one of my params - JType varType = (JType) typeMap.get(arg.type); - String varName = String.valueOf(arg.name); - JParameter param = null; - for (JParameter paramIt : currentMethod.getParams()) { - if (varType == paramIt.getType() && varName.equals(paramIt.getName())) { - param = paramIt; - } - } - if (param == null) { - throw new InternalCompilerException( - "Could not find matching local arg for explicit super ctor call."); - } - call.addArg(createVariableRef(info, param)); - } - } - } - - return call; - } - - JMethodCall processThisConstructorCall(ExplicitConstructorCall x) { - SourceInfo info = makeSourceInfo(x); - JMethod ctor = (JMethod) typeMap.get(x.binding); - JExpression trueQualifier = createThisRef(info, currentClass); - JMethodCall call = new JMethodCall(info, trueQualifier, ctor); - - assert (x.qualification == null); - - // All synthetic this args must be passed through to the target ctor - ReferenceBinding declaringClass = x.binding.declaringClass; - if (declaringClass.isNestedType() && !declaringClass.isStatic()) { - Iterator<JParameter> paramIt = currentMethod.getParams().iterator(); - NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(declaringClass); - if (nestedBinding.enclosingInstances != null) { - for (SyntheticArgumentBinding unused : nestedBinding.enclosingInstances) { - call.addArg(createVariableRef(info, paramIt.next())); - } - } - } - - addCallArgs(x.arguments, call, x.binding); - - // All synthetic locals must be passed through to the target ctor - if (declaringClass.isNestedType() && !declaringClass.isStatic()) { - Iterator<JParameter> paramIt = getSyntheticLocalsIterator(); - NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(declaringClass); - if (nestedBinding.outerLocalVariables != null) { - for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) { - call.addArg(createVariableRef(info, paramIt.next())); - } - } - } - - return call; - } - - private void addAllOuterThisRefs(List<? super JVariableRef> list, JExpression expr, - JClassType classType) { - for (JField field : classType.getFields()) { - // This fields are always first. - if (!field.isThisRef()) { - break; - } - // In a constructor, use the local param instead of the field. - JParameter param = null; - if (currentOuterThisRefParams != null && expr instanceof JThisRef) { - param = currentOuterThisRefParams.get(field); - } - if (param != null) { - list.add(new JParameterRef(expr.getSourceInfo(), param)); - } else { - list.add(new JFieldRef(expr.getSourceInfo(), expr, field, currentClass)); - } - } - } - - private void addAllOuterThisRefsPlusSuperChain(List<? super JVariableRef> workList, - JExpression expr, JClassType classType) { - for (; classType != null; classType = classType.getSuperClass()) { - addAllOuterThisRefs(workList, expr, classType); - } - } - - private void addCallArgs(Expression[] jdtArgs, JMethodCall call, MethodBinding binding) { - JExpression[] args = new JExpression[jdtArgs == null ? 0 : jdtArgs.length]; - for (int i = 0; i < args.length; ++i) { - args[i] = dispProcessExpression(jdtArgs[i]); - } - if (!binding.isVarargs()) { - call.addArgs(args); - return; - } - - // Handle the odd var-arg case. - TypeBinding[] params = binding.parameters; - int varArg = params.length - 1; - - // Everything but the last arg. - for (int i = 0; i < varArg; ++i) { - call.addArg(args[i]); - } - - // Handle the last arg. - - // See if there's a single varArg which is already an array. - if (args.length == params.length) { - if (jdtArgs[varArg].resolvedType.isCompatibleWith(params[varArg])) { - // Already the correct array type. - call.addArg(args[varArg]); - return; - } - } - - // Need to synthesize an appropriately-typed array. - List<JExpression> initializers = new ArrayList<JExpression>(); - for (int i = varArg; i < args.length; ++i) { - initializers.add(args[i]); - } - JArrayType lastParamType = (JArrayType) typeMap.get(params[varArg]); - JNewArray newArray = - JNewArray.createInitializers(call.getSourceInfo(), lastParamType, initializers); - call.addArg(newArray); - } - - private void addThrownExceptions(MethodBinding methodBinding, JMethod method) { - for (ReferenceBinding exceptionReference : methodBinding.thrownExceptions) { - method.addThrownException((JClassType) typeMap.get(exceptionReference.erasure())); - } - } - - /** - * Create a bridge method. It calls a same-named method with the same - * arguments, but with a different type signature. - * - * @param clazz The class to put the bridge method in - * @param jdtBridgeMethod The corresponding bridge method added in the JDT - * @param implmeth The implementation method to bridge to - */ - private void createBridgeMethod(JClassType clazz, SyntheticMethodBinding jdtBridgeMethod, - JMethod implmeth) { - SourceInfo info = implmeth.getSourceInfo().makeChild(); - // create the method itself - JMethod bridgeMethod = - program.createMethod(info, String.valueOf(jdtBridgeMethod.selector), clazz, - (JType) typeMap.get(jdtBridgeMethod.returnType.erasure()), false, false, implmeth - .isFinal(), implmeth.getAccess(), false); - bridgeMethod.setSynthetic(); - int paramIdx = 0; - List<JParameter> implParams = implmeth.getParams(); - for (TypeBinding jdtParamType : jdtBridgeMethod.parameters) { - JParameter param = implParams.get(paramIdx++); - JType paramType = (JType) typeMap.get(jdtParamType.erasure()); - JParameter newParam = - new JParameter(info.makeChild(param.getSourceInfo().getOrigin()), param.getName(), - paramType, true, false, bridgeMethod); - bridgeMethod.addParam(newParam); - } - addThrownExceptions(jdtBridgeMethod, bridgeMethod); - bridgeMethod.freezeParamTypes(); - info.addCorrelation(info.getCorrelator().by(bridgeMethod)); - - // create a call - JMethodCall call = new JMethodCall(info, new JThisRef(info, clazz), implmeth); - - for (int i = 0; i < bridgeMethod.getParams().size(); i++) { - JParameter param = bridgeMethod.getParams().get(i); - JParameterRef paramRef = new JParameterRef(info, param); - call.addArg(maybeCast(implParams.get(i).getType(), paramRef)); - } - - // wrap it in a return if necessary - JStatement callOrReturn; - if (bridgeMethod.getType() == program.getTypeVoid()) { - callOrReturn = call.makeStatement(); - } else { - callOrReturn = new JReturnStatement(info, call); - } - - // create a body that is just that call - JMethodBody body = (JMethodBody) bridgeMethod.getBody(); - body.getBlock().addStmt(callOrReturn); - - // Add overrides. - List<JMethod> overrides = new ArrayList<JMethod>(); - tryFindUpRefs(bridgeMethod, overrides); - assert !overrides.isEmpty(); - for (JMethod over : overrides) { - bridgeMethod.addOverride(over); - /* - * TODO(scottb): with a diamond-shape inheritance hierarchy, it may be - * possible to get dups in this way. Really, method.overrides should - * probably just be an IdentitySet to avoid having to check contains in - * various places. Left as a todo because I don't think dups is super - * harmful. - */ - bridgeMethod.addOverrides(over.getOverrides()); - } - } - - private JDeclarationStatement createDeclaration(SourceInfo info, JLocal local, JExpression value) { - return new JDeclarationStatement(info, new JLocalRef(info, local), value); - } - - /** - * Helper to create a qualified "this" ref (really a synthetic this field - * access) of the appropriate type. Always use this method instead of - * creating a naked JThisRef or you won't get the synthetic accesses right. - */ - private JExpression createQualifiedThisRef(SourceInfo info, JClassType targetType) { - assert (currentClass instanceof JClassType); - JExpression expr = new JThisRef(info, ((JClassType) currentClass)); - List<JExpression> list = new ArrayList<JExpression>(); - addAllOuterThisRefsPlusSuperChain(list, expr, (JClassType) currentClass); - return createThisRef(targetType, list); - } - - /** - * Helper to create an expression of the target type, possibly by accessing - * synthetic this fields on the passed-in expression. This is needed by a - * QualifiedAllocationExpression, because the qualifier may not be the - * correct type, and we may need use one of its fields. - */ - private JExpression createThisRef(JReferenceType qualType, JExpression expr) { - List<JExpression> list = new ArrayList<JExpression>(); - list.add(expr); - return createThisRef(qualType, list); - } - - /** - * Helper to create an expression of the target type, possibly by accessing - * synthetic this fields on ANY of several passed-in expressions. Why in the - * world would we need to do this? It turns out that when making an - * unqualified explicit super constructor call to something that needs a - * synthetic outer this arg, the correct value to pass in can be one of - * several of the calling constructor's own synthetic args. The catch is, - * it's possible none of the args are exactly the right type-- we have to - * make one of them the right type by following each of their synthetic this - * refs up an arbitrarily big tree of enclosing classes and - * supertypes-with-enclosing-classes until we find something that's the - * right type. - * - * We have this implemented as a Breadth-First Search to minimize the number - * of derefs required, and this seems to be correct. Note that we explicitly - * prefer the current expression as one of its supertypes over a synthetic - * this ref rooted off the current expression that happens to be the correct - * type. We have observed this to be consistent with how Java handles it. - * - * TODO(scottb): could we get this info directly from JDT? - */ - private JExpression createThisRef(JReferenceType qualType, List<JExpression> list) { - LinkedList<JExpression> workList = new LinkedList<JExpression>(); - workList.addAll(list); - while (!workList.isEmpty()) { - JExpression expr = workList.removeFirst(); - JClassType classType = (JClassType) ((JReferenceType) expr.getType()).getUnderlyingType(); - for (; classType != null; classType = classType.getSuperClass()) { - // prefer myself or myself-as-supertype over any of my this$ fields - // that may have already been added to the work list - if (program.typeOracle.canTriviallyCast(classType, qualType)) { - return expr; - } - addAllOuterThisRefs(workList, expr, classType); - } - } - - throw new InternalCompilerException("Cannot create a ThisRef of the appropriate type."); - } - - /** - * Helper to creates this ref (or maybe a synthetic this field access) of - * the appropriate type. Always use this method instead of creating a naked - * JThisRef or you won't get the synthetic accesses right. - */ - private JExpression createThisRef(SourceInfo info, JReferenceType targetType) { - assert (currentClass instanceof JClassType); - return createThisRef(targetType, new JThisRef(info, ((JClassType) currentClass))); - } - - /** - * Creates an appropriate JVariableRef for the polymorphic type of the - * requested JVariable. - */ - private JVariableRef createVariableRef(SourceInfo info, JVariable variable) { - if (variable instanceof JLocal) { - JLocal local = (JLocal) variable; - if (local.getEnclosingMethod() != currentMethod) { - throw new InternalCompilerException("LocalRef referencing local in a different method."); - } - return new JLocalRef(info, local); - } else if (variable instanceof JParameter) { - JParameter parameter = (JParameter) variable; - if (parameter.getEnclosingMethod() != currentMethod) { - throw new InternalCompilerException( - "ParameterRef referencing param in a different method."); - } - return new JParameterRef(info, parameter); - } else if (variable instanceof JField) { - JField field = (JField) variable; - JExpression instance = null; - if (!field.isStatic()) { - JClassType fieldEnclosingType = (JClassType) field.getEnclosingType(); - instance = createThisRef(info, fieldEnclosingType); - if (!program.typeOracle.canTriviallyCast((JReferenceType) instance.getType(), - fieldEnclosingType)) { - throw new InternalCompilerException("FieldRef referencing field in a different type."); - } - } - return new JFieldRef(info, instance, field, currentClass); - } - throw new InternalCompilerException("Unknown JVariable subclass."); - } - - /** - * Creates an appropriate JVariableRef for the polymorphic type of the - * requested JVariable. - */ - private JVariableRef createVariableRef(SourceInfo info, JVariable variable, Binding binding) { - // Fix up the reference if it's to an outer local/param - variable = possiblyReferenceOuterLocal(variable, binding); - if (variable == null) { - /* - * Strange case: in certain circumstances, JDT will fail to provide an - * emulation path to an outer local variable. In the case I know of, the - * reference is a spurious qualifier to a static method call. Let's just - * return null and ditch the expression. - */ - return null; - } - return createVariableRef(info, variable); - } - - private TypeBinding erasure(TypeBinding typeBinding) { - if (typeBinding instanceof ParameterizedTypeBinding) { - typeBinding = typeBinding.erasure(); - } - return typeBinding; - } - - private Method getCachedMethod(String name, Class<? extends Object> childClass) - throws NoSuchMethodException { - MethodKey key = new MethodKey(name, childClass); - MethodValue value = methodCache.get(key); - if (value == null) { - try { - Method method = getClass().getDeclaredMethod(name, childClass); - value = new MethodValue(method); - } catch (NoSuchMethodException ex) { - value = new MethodValue(ex); - } - methodCache.put(key, value); - } - // Might throw an exception here. - return value.getMethod(); - } - - private JInterfaceType getOrCreateExternalType(SourceInfo info, char[][] compoundName) { - String name = BuildTypeMap.dotify(compoundName); - JInterfaceType external = (JInterfaceType) program.getFromTypeMap(name); - if (external == null) { - external = program.createInterface(info, name); - external.setExternal(true); - } - return external; - } - - /** - * Get a new label of a particular name, or create a new one if it doesn't - * exist already. - */ - private JLabel getOrCreateLabel(SourceInfo info, JMethod enclosingMethod, char[] name) { - if (name == null) { - return null; - } - String sname = String.valueOf(name); - Map<String, JLabel> lblMap = this.labelMap.get(enclosingMethod); - if (lblMap == null) { - lblMap = new HashMap<String, JLabel>(); - this.labelMap.put(enclosingMethod, lblMap); - } - JLabel jlabel = lblMap.get(sname); - if (jlabel == null) { - jlabel = new JLabel(info, sname); - lblMap.put(sname, jlabel); - } - return jlabel; - } - - private JPrimitiveType getPrimitiveTypeForWrapperType(JClassType wrapperType) { - String wrapperTypeName = wrapperType.getName(); - if ("java.lang.Integer".equals(wrapperTypeName)) { - return program.getTypePrimitiveInt(); - } else if ("java.lang.Boolean".equals(wrapperTypeName)) { - return program.getTypePrimitiveBoolean(); - } else if ("java.lang.Character".equals(wrapperTypeName)) { - return program.getTypePrimitiveChar(); - } else if ("java.lang.Long".equals(wrapperTypeName)) { - return program.getTypePrimitiveLong(); - } else if ("java.lang.Short".equals(wrapperTypeName)) { - return program.getTypePrimitiveShort(); - } else if ("java.lang.Byte".equals(wrapperTypeName)) { - return program.getTypePrimitiveByte(); - } else if ("java.lang.Double".equals(wrapperTypeName)) { - return program.getTypePrimitiveDouble(); - } else if ("java.lang.Float".equals(wrapperTypeName)) { - return program.getTypePrimitiveFloat(); - } else { - return null; - } - } - - /** - * Gets a JParameter iterator for a constructor method over its synthetic - * local parameters. - */ - private Iterator<JParameter> getSyntheticLocalsIterator() { - return currentMethod.getParams().listIterator(currentMethod.getOriginalParamTypes().size()); - } - - private void implementMethod(JMethod method, JExpression returnValue) { - assert method != null; - JMethodBody body = (JMethodBody) method.getBody(); - JBlock block = body.getBlock(); - - SourceInfo info; - if (block.getStatements().size() > 0) { - info = block.getStatements().get(0).getSourceInfo(); - } else { - info = method.getSourceInfo(); - } - - block.clear(); - block.addStmt(new JReturnStatement(info, returnValue)); - } - - /* - * Determine the destination type for an implicit conversion of the given - * expression. Beware that when autoboxing, the type of the expression is - * not necessarily the same as the type of the box to be created. The JDT - * figures out what the necessary conversion is, depending on the context - * the expression appears in, and stores it in - * <code>x.implicitConversion</code>, so extract it from there. - */ - private JPrimitiveType implicitConversionTargetType(Expression x) - throws InternalCompilerException { - /* - * This algorithm for finding the target type is copied from - * org.eclipse.jdt - * .internal.compiler.codegen.CodeStream.generateReturnBytecode() . - */ - switch ((x.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { - case TypeIds.T_boolean: - return program.getTypePrimitiveBoolean(); - case TypeIds.T_byte: - return program.getTypePrimitiveByte(); - case TypeIds.T_char: - return program.getTypePrimitiveChar(); - case TypeIds.T_double: - return program.getTypePrimitiveDouble(); - case TypeIds.T_float: - return program.getTypePrimitiveFloat(); - case TypeIds.T_int: - return program.getTypePrimitiveInt(); - case TypeIds.T_long: - return program.getTypePrimitiveLong(); - case TypeIds.T_short: - return program.getTypePrimitiveShort(); - default: - throw new InternalCompilerException("Could not determine the desired box type"); - } - } - - /** - * Check whether the specified type is definitely for an enum class. - * - * @param type The type being tested - * @return whether it is certainly an enum - */ - private boolean isEnumType(JType type) { - if (type instanceof JClassType) { - return ((JClassType) type).isEnumOrSubclass() != null; - } - - if (type instanceof JNonNullType) { - return isEnumType(((JNonNullType) type).getUnderlyingType()); - } - - return false; - } - - private SourceInfo makeSourceInfo(Statement x) { - int startLine = - Util.getLineNumber(x.sourceStart, currentSeparatorPositions, 0, - currentSeparatorPositions.length - 1); - SourceOrigin toReturn = - SourceOrigin.create(x.sourceStart, x.sourceEnd, startLine, currentFileName); - if (currentMethod != null) { - return currentMethod.getSourceInfo().makeChild(toReturn); - } - return toReturn; - } - - private JExpression maybeCast(JType expected, JExpression expression) { - if (expected != expression.getType()) { - // Must be a generic; insert a cast operation. - JReferenceType toType = (JReferenceType) expected; - return new JCastOperation(expression.getSourceInfo(), toType, expression); - } else { - return expression; - } - } - - /** - * Sometimes a variable reference can be to a local or parameter in an an - * enclosing method. This is a tricky situation to detect. There's no - * obvious way to tell, but the clue we can get from JDT is that the local's - * containing method won't be the same as the method we're currently - * processing. - * - * Once we have this clue, we can use getEmulationPath to compute the - * current class's binding for that field. - */ - private JVariable possiblyReferenceOuterLocal(JVariable variable, Binding binding) { - - if (variable instanceof JLocal || variable instanceof JParameter) { - LocalVariableBinding localBinding = (LocalVariableBinding) binding; - if (localBinding.declaringScope.methodScope() != currentMethodScope) { - variable = null; - VariableBinding[] vars = currentMethodScope.getEmulationPath(localBinding); - if (vars == null) { - return null; - } - assert (vars.length == 1); - VariableBinding varBinding = vars[0]; - - // See if there's an available parameter - if (varBinding instanceof SyntheticArgumentBinding) { - JType type = (JType) typeMap.get(varBinding.type); - String name = String.valueOf(varBinding.name); - for (int i = 0; i < currentMethod.getParams().size(); ++i) { - JParameter param = currentMethod.getParams().get(i); - if (type == param.getType() && name.equals(param.getName())) { - variable = param; - break; - } - } - } - - // just use the field - if (variable == null) { - variable = (JField) typeMap.get(varBinding); - } - - // now we have an updated variable that we can create our ref from - } - } else { - assert variable instanceof JField; - // In a constructor, prefer the ctor arg rather than the field. - if (currentOuterThisRefParams != null) { - JParameter ctorArg = currentOuterThisRefParams.get(variable); - if (ctorArg != null) { - variable = ctorArg; - } - } - } - return variable; - } - - /** - * Process a {@link ArtificialRescue.Rescue} element. - */ - private void processArtificialRescue(RescueData rescue) { - JReferenceType classType = (JReferenceType) program.getTypeFromJsniRef(rescue.getClassName()); - assert classType != null; - if (rescue.isInstantiable()) { - currentClass.addArtificialRescue(classType); - } - - if (classType instanceof JDeclaredType) { - List<String> toRescue = new ArrayList<String>(); - Collections.addAll(toRescue, rescue.getFields()); - Collections.addAll(toRescue, rescue.getMethods()); - - for (String name : toRescue) { - JsniRef ref = JsniRef.parse("@" + classType.getName() + "::" + name); - final String[] errors = {null}; - JNode node = - JsniRefLookup.findJsniRefTarget(ref, program, new JsniRefLookup.ErrorReporter() { - public void reportError(String error) { - errors[0] = error; - } - }); - if (errors[0] != null) { - // Should have been caught by ArtificialRescueChecker - throw new InternalCompilerException("Unable to artificially rescue " + name + ": " - + errors[0]); - } - - if (node instanceof JType) { - // Already added the type above. - } else { - currentClass.addArtificialRescue(node); - } - if (node instanceof JField) { - JField field = (JField) node; - if (!field.isFinal()) { - field.setVolatile(); - } - } - } - } - } - - private void processArtificialRescues(Annotation[] annotations) { - if (annotations == null) { - return; - } - RescueData[] rescues = RescueData.createFromAnnotations(annotations); - for (RescueData rescue : rescues) { - processArtificialRescue(rescue); - } - } - - /** - * Helper for creating all JBinaryOperation. Several different JDT nodes can - * result in binary operations: AND_AND_Expression, Assignment, - * BinaryExpresion, CompoundAssignment, EqualExpression, and - * OR_OR_Expression. Hopefully the specific operators that can result in - * each different JDT type won't change between releases, because we only - * look for the specific operators that we think should match each JDT node, - * and throw an error if there's a mismatch. - */ - private JExpression processBinaryOperation(SourceInfo info, JBinaryOperator op, JType type, - Expression arg1, Expression arg2) { - JExpression exprArg1 = dispProcessExpression(arg1); - JExpression exprArg2 = dispProcessExpression(arg2); - JBinaryOperation binaryOperation = new JBinaryOperation(info, type, op, exprArg1, exprArg2); - return binaryOperation; - } - - private JExpression processQualifiedThisOrSuperRef(QualifiedThisReference x, JClassType qualType) { - /* - * WEIRD: If a thisref or superref is qualified with the EXACT type of the - * innermost type (in other words, a needless qualifier), it must refer to - * that innermost type, because a class can never be nested inside of - * itself. In this case, we must treat it as if it were not qualified. - * - * In all other cases, the qualified thisref or superref cannot possibly - * refer to the innermost type (even if the innermost type could be cast - * to a compatible type), so we must create a reference to some outer - * type. - */ - SourceInfo info = makeSourceInfo(x); - if (qualType == currentClass) { - return createThisRef(info, qualType); - } else { - return createQualifiedThisRef(info, qualType); - } - } - - private InternalCompilerException translateException(Object node, Throwable e) { - if (e instanceof VirtualMachineError) { - // Always rethrow VM errors (an attempt to wrap may fail). - throw (VirtualMachineError) e; - } - InternalCompilerException ice; - if (e instanceof InternalCompilerException) { - ice = (InternalCompilerException) e; - } else { - ice = new InternalCompilerException("Error constructing Java AST", e); - } - String className = node.getClass().getName(); - String description = node.toString(); - SourceInfo sourceInfo = null; - if (node instanceof Statement) { - sourceInfo = makeSourceInfo((Statement) node); - } - ice.addNode(className, description, sourceInfo); - return ice; - } - - /** - * For a given method, try to find all methods that it overrides/implements. - * This version does not use JDT. - */ - private void tryFindUpRefs(JMethod method) { - List<JMethod> overrides = new ArrayList<JMethod>(); - tryFindUpRefs(method, overrides); - method.addOverrides(overrides); - } - - private void tryFindUpRefs(JMethod method, List<JMethod> overrides) { - if (method.getEnclosingType() != null) { - tryFindUpRefsRecursive(method, method.getEnclosingType(), overrides); - } - } - - /** - * For a given method(and method binding), try to find all methods that it - * overrides/implements. - */ - private void tryFindUpRefs(JMethod method, MethodBinding binding) { - // Should never get a parameterized instance here. - assert binding == binding.original(); - tryFindUpRefsRecursive(method, binding, binding.declaringClass); - } - - /** - * For a given method(and method binding), recursively try to find all - * methods that it overrides/implements. - */ - private void tryFindUpRefsRecursive(JMethod method, JDeclaredType searchThisType, - List<JMethod> overrides) { - - // See if this class has any uprefs, unless this class is myself - if (method.getEnclosingType() != searchThisType) { - for (JMethod upRef : searchThisType.getMethods()) { - if (JTypeOracle.methodsDoMatch(method, upRef) && !overrides.contains(upRef)) { - overrides.add(upRef); - break; - } - } - } - - // recurse super class - if (searchThisType.getSuperClass() != null) { - tryFindUpRefsRecursive(method, searchThisType.getSuperClass(), overrides); - } - - // recurse super interfaces - for (JInterfaceType intf : searchThisType.getImplements()) { - tryFindUpRefsRecursive(method, intf, overrides); - } - } - - /** - * For a given method(and method binding), recursively try to find all - * methods that it overrides/implements. - */ - private void tryFindUpRefsRecursive(JMethod method, MethodBinding binding, - ReferenceBinding searchThisType) { - /* - * Always look for uprefs in the original, so we can correctly compare - * erased signatures. The general design for uprefs is to model what the - * JVM does in terms of matching up overrides based on binary match. - */ - searchThisType = (ReferenceBinding) searchThisType.original(); - - // See if this class has any uprefs, unless this class is myself - if (binding.declaringClass != searchThisType) { - for (MethodBinding tryMethod : searchThisType.getMethods(binding.selector)) { - if (binding.returnType.erasure() == tryMethod.returnType.erasure() - && binding.areParameterErasuresEqual(tryMethod)) { - JMethod upRef = (JMethod) typeMap.get(tryMethod); - if (!method.getOverrides().contains(upRef)) { - method.addOverride(upRef); - break; - } - } - } - } - - // recurse super class - if (searchThisType.superclass() != null) { - tryFindUpRefsRecursive(method, binding, searchThisType.superclass()); - } - - // recurse super interfaces - if (searchThisType.superInterfaces() != null) { - for (int i = 0; i < searchThisType.superInterfaces().length; i++) { - ReferenceBinding intf = searchThisType.superInterfaces()[i]; - tryFindUpRefsRecursive(method, binding, intf); - } - } - } - - private JExpression unbox(JExpression toUnbox, JClassType wrapperType) { - JPrimitiveType primitiveType = getPrimitiveTypeForWrapperType(wrapperType); - if (primitiveType == null) { - throw new InternalCompilerException(toUnbox, "Attempt to unbox unexpected type '" - + wrapperType.getName() + "'", null); - } - - String valueMethodName = primitiveType.getName() + "Value"; - JMethod valueMethod = null; - for (Object element : wrapperType.getMethods()) { - JMethod method = (JMethod) element; - if (method.getName().equals(valueMethodName)) { - if (method.getParams().isEmpty()) { - // It's a match! - valueMethod = method; - break; - } - } - } - - if (valueMethod == null) { - throw new InternalCompilerException(toUnbox, "Expected to find a method on '" - + wrapperType.getName() + "' whose signature matches 'public " - + primitiveType.getName() + " " + valueMethodName + "()'", null); - } - - JMethodCall unboxCall = new JMethodCall(toUnbox.getSourceInfo(), toUnbox, valueMethod); - return unboxCall; - } - - private void writeEnumValueOfMethod(JEnumType type, JField valuesField) { - JField mapField; - { - /* - * Make an inner class to hold a lazy-init name-value map. We use a - * class to take advantage of its clinit. - * - * class Map { $MAP = Enum.createValueOfMap($VALUES); } - */ - SourceInfo typeInfo = type.getSourceInfo().makeChild(); - JClassType mapClass = program.createClass(typeInfo, type.getName() + "$Map", false, true); - typeInfo.addCorrelation(typeInfo.getCorrelator().by(mapClass)); - mapClass.setSuperClass(program.getTypeJavaLangObject()); - SourceInfo fieldInfo = typeInfo.makeChild(); - mapField = - program.createField(fieldInfo, "$MAP", mapClass, program.getJavaScriptObject(), true, - Disposition.FINAL); - fieldInfo.addCorrelation(fieldInfo.getCorrelator().by(mapField)); - - SourceInfo methodInfo = typeInfo.makeChild(); - JMethodCall call = - new JMethodCall(methodInfo, null, program.getIndexedMethod("Enum.createValueOfMap")); - call.addArg(new JFieldRef(methodInfo, null, valuesField, type)); - JFieldRef mapRef = new JFieldRef(methodInfo, null, mapField, type); - JDeclarationStatement declStmt = new JDeclarationStatement(methodInfo, mapRef, call); - JMethod clinit = - program.createMethod(methodInfo, "$clinit", mapClass, program.getTypeVoid(), false, - true, true, AccessModifier.PRIVATE, false); - clinit.freezeParamTypes(); - methodInfo.addCorrelation(methodInfo.getCorrelator().by(clinit)); - JBlock clinitBlock = ((JMethodBody) clinit.getBody()).getBlock(); - clinitBlock.addStmt(declStmt); - mapField.setInitializer(declStmt); - } - - /* - * return Enum.valueOf(Enum$Map.Map.$MAP, name); - */ - { - SourceInfo sourceInfo = currentMethodBody.getSourceInfo(); - JFieldRef mapRef = new JFieldRef(sourceInfo, null, mapField, type); - JVariableRef nameRef = createVariableRef(sourceInfo, currentMethod.getParams().get(0)); - JMethod delegateTo = program.getIndexedMethod("Enum.valueOf"); - JMethodCall call = new JMethodCall(sourceInfo, null, delegateTo); - call.addArgs(mapRef, nameRef); - - currentMethodBody.getBlock().addStmt(new JReturnStatement(sourceInfo, call)); - } - } - - private JField writeEnumValuesMethod(JEnumType type) { - JField valuesField; - { - // $VALUES = new E[]{A,B,B}; - SourceInfo fieldInfo = type.getSourceInfo().makeChild(); - JArrayType enumArrayType = program.getTypeArray(type); - valuesField = - program.createField(fieldInfo, "$VALUES", type, enumArrayType, true, Disposition.FINAL); - fieldInfo.addCorrelation(fieldInfo.getCorrelator().by(valuesField)); - List<JExpression> initializers = new ArrayList<JExpression>(); - for (JEnumField field : type.getEnumList()) { - JFieldRef fieldRef = new JFieldRef(fieldInfo, null, field, type); - initializers.add(fieldRef); - } - JNewArray newExpr = JNewArray.createInitializers(fieldInfo, enumArrayType, initializers); - JFieldRef valuesRef = new JFieldRef(fieldInfo, null, valuesField, type); - JDeclarationStatement declStmt = new JDeclarationStatement(fieldInfo, valuesRef, newExpr); - JBlock clinitBlock = ((JMethodBody) type.getMethods().get(0).getBody()).getBlock(); - - /* - * HACKY: the $VALUES array must be initialized immediately after all of - * the enum fields, but before any user initialization (which might rely - * on $VALUES). The "1 + " is the statement containing the call to - * Enum.$clinit(). - */ - int insertionPoint = 1 + initializers.size(); - assert clinitBlock.getStatements().size() >= initializers.size() + 1; - clinitBlock.addStmt(insertionPoint, declStmt); - valuesField.setInitializer(declStmt); - } - { - // return $VALUES; - SourceInfo sourceInfo = currentMethod.getSourceInfo(); - JFieldRef valuesRef = new JFieldRef(sourceInfo, null, valuesField, type); - currentMethodBody.getBlock().addStmt(new JReturnStatement(sourceInfo, valuesRef)); - } - return valuesField; - } - } - - /** - * Resolve JSNI refs; replace with compile-time constants where appropriate. - */ - private static class JsniRefGenerationVisitor extends JModVisitor { - - private class JsniRefResolver extends JsModVisitor { - private final AbstractMethodDeclaration methodDecl; - private final JsniMethodBody nativeMethodBody; - - private JsniRefResolver(AbstractMethodDeclaration methodDecl, JsniMethodBody nativeMethodBody) { - this.methodDecl = methodDecl; - this.nativeMethodBody = nativeMethodBody; - } - - @Override - public void endVisit(JsNameRef x, JsContext ctx) { - String ident = x.getIdent(); - if (ident.charAt(0) == '@') { - processNameRef(x, ctx); - } - } - - private JNode findJsniRefTarget(final SourceInfo info, String ident) { - JsniRef parsed = JsniRef.parse(ident); - if (parsed == null) { - JsniCollector.reportJsniError(info, methodDecl, "Badly formatted native reference '" - + ident + "'"); - return null; - } - - JProgram prog = program; - - return JsniRefLookup.findJsniRefTarget(parsed, prog, new JsniRefLookup.ErrorReporter() { - public void reportError(String error) { - JsniCollector.reportJsniError(info, methodDecl, error); - } - }); - } - - private void processClassLiteral(JsNameRef nameRef, SourceInfo info, JType type, JsContext ctx) { - assert !ctx.isLvalue(); - JsniClassLiteral classLiteral = new JsniClassLiteral(info, nameRef.getIdent(), type); - nativeMethodBody.addClassRef(classLiteral); - } - - private void processField(JsNameRef nameRef, SourceInfo info, JField field, JsContext ctx) { - /* - * We must replace any compile-time constants with the constant value of - * the field. - */ - if (field.isCompileTimeConstant()) { - assert !ctx.isLvalue(); - JLiteral initializer = field.getConstInitializer(); - JType type = initializer.getType(); - if (type instanceof JPrimitiveType || program.isJavaLangString(type)) { - GenerateJavaScriptLiterals generator = new GenerateJavaScriptLiterals(); - generator.accept(initializer); - JsExpression result = generator.peek(); - assert (result != null); - ctx.replaceMe(result); - return; - } - } - - // Normal: create a jsniRef. - JsniFieldRef fieldRef = - new JsniFieldRef(info, nameRef.getIdent(), field, currentClass, ctx.isLvalue()); - nativeMethodBody.addJsniRef(fieldRef); - } - - private void processMethod(JsNameRef nameRef, SourceInfo info, JMethod method, JsContext ctx) { - assert !ctx.isLvalue(); - JsniMethodRef methodRef = - new JsniMethodRef(info, nameRef.getIdent(), method, program.getJavaScriptObject()); - nativeMethodBody.addJsniRef(methodRef); - } - - private void processNameRef(JsNameRef nameRef, JsContext ctx) { - SourceInfo info = nativeMethodBody.getSourceInfo(); - // TODO: make this tighter when we have real source info - // JSourceInfo info = translateInfo(nameRef.getInfo()); - String ident = nameRef.getIdent(); - JNode node = jsniMap.get(ident); - if (node == null) { - node = findJsniRefTarget(info, ident); - if (node == null) { - return; // already reported error - } - jsniMap.put(ident, node); - } - - if (node instanceof JField) { - processField(nameRef, info, (JField) node, ctx); - } else if (node instanceof JMethod) { - processMethod(nameRef, info, (JMethod) node, ctx); - } else if (node instanceof JType) { - processClassLiteral(nameRef, info, (JType) node, ctx); - } else { - throw new InternalCompilerException(node, - "JSNI reference to something other than a class, field, or method?", null); - } - } - } - - private JDeclaredType currentClass; - - private final Map<String, JNode> jsniMap = new HashMap<String, JNode>(); - - private final Map<JsniMethodBody, AbstractMethodDeclaration> jsniMethodMap; - - private final JProgram program; - - public JsniRefGenerationVisitor(JProgram program, - Map<JsniMethodBody, AbstractMethodDeclaration> jsniMethodMap) { - this.program = program; - this.jsniMethodMap = jsniMethodMap; - } - - @Override - public void endVisit(JClassType x, Context ctx) { - currentClass = null; - } - - @Override - public void endVisit(JsniMethodBody x, Context ctx) { - new JsniRefResolver(jsniMethodMap.get(x), x).accept(x.getFunc()); - } - - @Override - public boolean visit(JClassType x, Context ctx) { - currentClass = x; - return true; - } - - @Override - public boolean visit(JMethodBody x, Context ctx) { - return false; - } - } - - /** - * Combines the information from the JDT type nodes and the type map to create - * a JProgram structure. - */ - public static void exec(TypeDeclaration[] types, TypeMap typeMap, JProgram jprogram, - JJSOptions options) { - Event generateJavaAstEvent = SpeedTracerLogger.start(CompilerEventType.GENERATE_JAVA_AST); - // Construct the basic AST. - JavaASTGenerationVisitor v = new JavaASTGenerationVisitor(typeMap, jprogram, options); - for (TypeDeclaration type : types) { - v.processType(type); - } - for (TypeDeclaration type : types) { - v.addBridgeMethods(type.binding); - } - Collections.sort(jprogram.getDeclaredTypes(), new HasNameSort()); - - // Process JSNI. - Map<JsniMethodBody, AbstractMethodDeclaration> jsniMethodMap = v.getJsniMethodMap(); - new JsniRefGenerationVisitor(jprogram, jsniMethodMap).accept(jprogram); - generateJavaAstEvent.end(); - } - - /** - * Returns <code>true</code> if JDT optimized the condition to - * <code>false</code>. - */ - private static boolean isOptimizedFalse(Expression condition) { - if (condition != null) { - Constant cst = condition.optimizedBooleanConstant(); - if (cst != Constant.NotAConstant) { - if (cst.booleanValue() == false) { - return true; - } - } - } - return false; - } - - /** - * Returns <code>true</code> if JDT optimized the condition to - * <code>true</code>. - */ - private static boolean isOptimizedTrue(Expression condition) { - if (condition != null) { - Constant cst = condition.optimizedBooleanConstant(); - if (cst != Constant.NotAConstant) { - if (cst.booleanValue()) { - return true; - } - } - } - return false; - } - - private static boolean isScript(JProgram program) { - return !program.getTypeJavaLangObject().isExternal(); - } -}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java index c599720..b059bd8 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -1746,7 +1746,7 @@ * } * </pre> */ - SourceInfo sourceInfo = program.createSourceInfoSynthetic(GenerateJavaScriptAST.class); + SourceInfo sourceInfo = SourceOrigin.UNKNOWN; JsName entryName = topScope.declareName("$entry"); JsVar entryVar = new JsVar(sourceInfo, entryName);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java index 80fb3a3..1a8410c 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -1880,7 +1880,6 @@ * It's okay to defer creation of synthetic fields, they can't be * referenced until we analyze the code. */ - int index = 0; SourceTypeBinding binding = x.binding; if (isNested(binding)) { // add synthetic fields for outer this and locals @@ -1889,7 +1888,7 @@ if (nestedBinding.enclosingInstances != null) { for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; - createSyntheticField(arg, type, index++, Disposition.THIS_REF); + createSyntheticField(arg, type, Disposition.THIS_REF); } } @@ -1908,7 +1907,7 @@ } } } - createSyntheticField(arg, type, index++, isReallyThisRef ? Disposition.THIS_REF + createSyntheticField(arg, type, isReallyThisRef ? Disposition.THIS_REF : Disposition.FINAL); } } @@ -2084,13 +2083,11 @@ } private JField createSyntheticField(SyntheticArgumentBinding arg, JDeclaredType enclosingType, - int index, Disposition disposition) { + Disposition disposition) { JType type = typeMap.get(arg.type); SourceInfo info = enclosingType.getSourceInfo(); JField field = new JField(info, intern(arg.name), enclosingType, type, false, disposition); - // TODO: remove me, source identical for now! - enclosingType.addField(index, field); - // enclosingType.addField(field); + enclosingType.addField(field); curClass.syntheticFields.put(arg, field); if (arg.matchingField != null) { typeMap.setField(arg.matchingField, field); @@ -2758,8 +2755,6 @@ } } - public static boolean ENABLED = true; - /** * Manually tracked version count. * @@ -2803,7 +2798,7 @@ */ public static long getSerializationVersion() { // TODO(zundel): something much awesomer. - return ENABLED ? AST_VERSION : 0L; + return AST_VERSION; } static String dotify(char[][] name) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java index 33684c5..a6cd491 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
@@ -35,7 +35,10 @@ /** * A utility class that can look up a {@link JsniRef} in a {@link JProgram}. + * + * @deprecated find alternatives, only a couple of corner cases use this now. */ +@Deprecated public class JsniRefLookup { /** * A callback used to indicate the reason for a failed JSNI lookup.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java index 31d952b..680e19b 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -243,8 +243,10 @@ jsoMethodInstances.put(polyMethod.getSignature(), methodCount); String devirtualName = prefix + "__devirtual$"; JMethod newMethod = - program.createMethod(sourceInfo, devirtualName, jsoType, polyMethod.getType(), false, true, - true, AccessModifier.PUBLIC, false); + new JMethod(sourceInfo, devirtualName, jsoType, polyMethod.getType(), false, true, true, + AccessModifier.PUBLIC); + newMethod.setBody(new JMethodBody(sourceInfo)); + jsoType.addMethod(newMethod); newMethod.setSynthetic(); // Setup parameters.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java deleted file mode 100644 index 94056ee..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java +++ /dev/null
@@ -1,182 +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.jjs.impl; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.dev.jdt.RebindPermutationOracle; -import com.google.gwt.dev.jjs.InternalCompilerException; -import com.google.gwt.dev.jjs.ast.Context; -import com.google.gwt.dev.jjs.ast.HasName; -import com.google.gwt.dev.jjs.ast.JClassLiteral; -import com.google.gwt.dev.jjs.ast.JClassType; -import com.google.gwt.dev.jjs.ast.JDeclaredType; -import com.google.gwt.dev.jjs.ast.JExpression; -import com.google.gwt.dev.jjs.ast.JGwtCreate; -import com.google.gwt.dev.jjs.ast.JMethod; -import com.google.gwt.dev.jjs.ast.JMethodCall; -import com.google.gwt.dev.jjs.ast.JModVisitor; -import com.google.gwt.dev.jjs.ast.JNameOf; -import com.google.gwt.dev.jjs.ast.JNode; -import com.google.gwt.dev.jjs.ast.JNullLiteral; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.ast.JReferenceType; -import com.google.gwt.dev.jjs.ast.JStringLiteral; -import com.google.gwt.dev.util.JsniRef; -import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; -import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; - -import java.util.ArrayList; -import java.util.List; - -/** - * Replaces any "GWT.create()" calls with a special node. - */ -public class ReplaceRebinds { - - private class RebindVisitor extends JModVisitor { - - private JDeclaredType currentClass; - private final JMethod nameOfMethod; - private final JMethod rebindCreateMethod; - - public RebindVisitor(JMethod nameOfMethod, JMethod rebindCreateMethod) { - this.nameOfMethod = nameOfMethod; - this.rebindCreateMethod = rebindCreateMethod; - } - - @Override - public void endVisit(JMethodCall x, Context ctx) { - JMethod method = x.getTarget(); - if (method == nameOfMethod) { - replaceImplNameOf(x, ctx); - - } else if (method == rebindCreateMethod) { - replaceGwtCreate(x, ctx); - } - } - - @Override - public boolean visit(JMethod x, Context ctx) { - currentClass = x.getEnclosingType(); - return true; - } - - private void replaceGwtCreate(JMethodCall x, Context ctx) { - assert (x.getArgs().size() == 1); - JExpression arg = x.getArgs().get(0); - assert (arg instanceof JClassLiteral); - JClassLiteral classLiteral = (JClassLiteral) arg; - JReferenceType sourceType = (JReferenceType) classLiteral.getRefType(); - List<JClassType> allRebindResults = getAllPossibleRebindResults(sourceType); - JGwtCreate gwtCreate = - new JGwtCreate(x.getSourceInfo(), sourceType, allRebindResults, program - .getTypeJavaLangObject(), currentClass); - if (allRebindResults.size() == 1) { - // Just replace with the instantiation expression. - ctx.replaceMe(gwtCreate.getInstantiationExpressions().get(0)); - } else { - ctx.replaceMe(gwtCreate); - } - } - - private void replaceImplNameOf(JMethodCall x, Context ctx) { - JExpression arg0 = x.getArgs().get(0); - assert arg0 instanceof JStringLiteral; - JStringLiteral stringLiteral = (JStringLiteral) arg0; - String stringValue = stringLiteral.getValue(); - - JNode node = null; - - JDeclaredType refType; - JsniRef ref = JsniRef.parse(stringValue); - - if (ref != null) { - final List<String> errors = new ArrayList<String>(); - node = JsniRefLookup.findJsniRefTarget(ref, program, new JsniRefLookup.ErrorReporter() { - public void reportError(String error) { - errors.add(error); - } - }); - if (!errors.isEmpty()) { - for (String error : errors) { - logger.log(TreeLogger.ERROR, error); - } - } - } else { - // See if it's just @foo.Bar, which would result in the class seed - node = - program.getFromTypeMap(stringValue.charAt(0) == '@' ? stringValue.substring(1) - : stringValue); - } - if (node == null) { - // Not found, must be null - ctx.replaceMe(JNullLiteral.INSTANCE); - } else { - ctx.replaceMe(new JNameOf(x.getSourceInfo(), program.getTypeJavaLangString(), - (HasName) node)); - } - } - } - - public static boolean exec(TreeLogger logger, JProgram program, RebindPermutationOracle rpo) { - Event replaceRebindsEvent = SpeedTracerLogger.start(CompilerEventType.REPLACE_REBINDS); - boolean didChange = new ReplaceRebinds(logger, program, rpo).execImpl(); - replaceRebindsEvent.end(); - return didChange; - } - - private final TreeLogger logger; - private final JProgram program; - private final RebindPermutationOracle rpo; - - private ReplaceRebinds(TreeLogger logger, JProgram program, RebindPermutationOracle rpo) { - this.logger = logger; - this.program = program; - this.rpo = rpo; - } - - protected List<JClassType> getAllPossibleRebindResults(JReferenceType type) { - // Rebinds are always on a source type name. - String reqType = type.getName().replace('$', '.'); - String[] answers; - try { - answers = rpo.getAllPossibleRebindAnswers(logger, reqType); - } catch (UnableToCompleteException e) { - // Should never happen. - throw new InternalCompilerException("Unexpected failure to get possible rebind answers for '" - + reqType + "'"); - } - List<JClassType> rebindAnswers = new ArrayList<JClassType>(); - for (String answer : answers) { - JReferenceType result = program.getFromTypeMap(answer); - assert (result != null); - rebindAnswers.add((JClassType) result); - } - assert rebindAnswers.size() > 0; - return rebindAnswers; - } - - private boolean execImpl() { - RebindVisitor rebinder = - new RebindVisitor(program.getIndexedMethod("Impl.getNameOf"), program - .getIndexedMethod("GWT.create")); - rebinder.accept(program); - return rebinder.didChange(); - } - -}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java index 87d9b98..ba463cd 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
@@ -18,6 +18,7 @@ import com.google.gwt.dev.jjs.InternalCompilerException; import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.ast.AccessModifier; +import com.google.gwt.dev.jjs.SourceOrigin; import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.JBlock; import com.google.gwt.dev.jjs.ast.JCaseStatement; @@ -53,7 +54,8 @@ if (isSoftRebind(x.getSourceType())) { JMethod method = - rebindMethod(x.getSourceType(), x.getResultTypes(), x.getInstantiationExpressions()); + rebindMethod(x.getSourceInfo(), x.getSourceType(), x.getResultTypes(), x + .getInstantiationExpressions()); JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method); ctx.replaceMe(call); return; @@ -76,7 +78,9 @@ public void endVisit(JReboundEntryPoint x, Context ctx) { if (isSoftRebind(x.getSourceType())) { - JMethod method = rebindMethod(x.getSourceType(), x.getResultTypes(), x.getEntryCalls()); + JMethod method = + rebindMethod(x.getSourceInfo(), x.getSourceType(), x.getResultTypes(), x + .getEntryCalls()); JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method); ctx.replaceMe(call.makeStatement()); return; @@ -158,7 +162,7 @@ return !hardRebindAnswers.containsKey(requestType); } - private JMethod rebindMethod(String requestType, List<String> resultTypes, + private JMethod rebindMethod(SourceInfo info, String requestType, List<String> resultTypes, List<JExpression> instantiationExpressions) { assert resultTypes.size() == instantiationExpressions.size(); @@ -196,12 +200,13 @@ } assert mostUsed != null; + info = info.makeChild(SourceOrigin.UNKNOWN); // c_g_g_d_c_i_DOMImpl - SourceInfo info = program.createSourceInfoSynthetic(getClass()); toReturn = - program.createMethod(info, requestType.replace("_", "_1").replace('.', '_'), holderType, - program.getTypeJavaLangObject().getNonNull(), false, true, true, - AccessModifier.PUBLIC, false); + new JMethod(info, requestType.replace("_", "_1").replace('.', '_'), holderType, program + .getTypeJavaLangObject().getNonNull(), false, true, true, AccessModifier.PUBLIC); + toReturn.setBody(new JMethodBody(info)); + holderType.addMethod(toReturn); toReturn.freezeParamTypes(); info.addCorrelation(info.getCorrelator().by(toReturn)); rebindMethods.put(requestType, toReturn);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeLinker.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeLinker.java deleted file mode 100644 index fd4ff5b..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeLinker.java +++ /dev/null
@@ -1,34 +0,0 @@ -/* - * Copyright 2010 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.jjs.impl; - -/** - * Provides linking information for types for separate compilation. - */ -public interface TypeLinker { - - TypeLinker NULL_TYPE_LINKER = new TypeLinker() { - public boolean isExternalType(String name) { - return false; - } - }; - - /** - * Returns true if the type is external (source code not provided) to the - * program. - */ - boolean isExternalType(String name); -}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java deleted file mode 100644 index cb2390d..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java +++ /dev/null
@@ -1,279 +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.jjs.impl; - -import com.google.gwt.dev.jjs.InternalCompilerException; -import com.google.gwt.dev.jjs.ast.JConstructor; -import com.google.gwt.dev.jjs.ast.JDeclaredType; -import com.google.gwt.dev.jjs.ast.JField; -import com.google.gwt.dev.jjs.ast.JMethod; -import com.google.gwt.dev.jjs.ast.JNode; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.ast.JType; -import com.google.gwt.dev.util.collect.IdentityHashSet; - -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.Binding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedFieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; - -/** - * Contains the list of the top-level and array types. - */ -public class TypeMap { - - /** - * Maps Eclipse AST nodes to our JNodes. - */ - private final Map<Binding, JNode> crossRefMap = new IdentityHashMap<Binding, JNode>(); - - private final Map<String, JDeclaredType> externalTypesByName = - new HashMap<String, JDeclaredType>(); - - /** - * Centralizes creation and singleton management. - */ - private final JProgram program; - - public TypeMap(JProgram program) { - this.program = program; - } - - public JNode get(Binding binding) { - return get(binding, true); - } - - public JProgram getProgram() { - return program; - } - - public void put(Binding binding, JNode to) { - if (binding == null) { - throw new InternalCompilerException("Trying to put null into typeMap."); - } - - Object old = crossRefMap.put(binding, to); - assert (old == null); - - if (to instanceof JDeclaredType) { - JDeclaredType type = (JDeclaredType) to; - if (type.isExternal()) { - externalTypesByName.put(type.getName(), type); - } - } - } - - public JNode tryGet(Binding binding) { - return get(binding, false); - } - - private boolean equals(MethodBinding binding, JMethod method) { - if (!(method instanceof JConstructor && binding.isConstructor()) - && !method.getName().equals(String.valueOf(binding.constantPoolName()))) { - return false; - } - - List<JType> paramTypes = method.getOriginalParamTypes(); - TypeBinding[] bindingParams = binding.parameters; - - if (paramTypes.size() != bindingParams.length) { - return false; - } - - for (int i = 0; i < bindingParams.length; ++i) { - TypeBinding bindingParam = bindingParams[i]; - if (paramTypes.get(i) != get(bindingParam)) { - return false; - } - } - - return method.getType() == get(binding.returnType); - } - - private JNode get(Binding binding, boolean failOnNull) { - if (binding instanceof TypeVariableBinding) { - TypeVariableBinding tvb = (TypeVariableBinding) binding; - return get(tvb.erasure(), failOnNull); - } else if (binding instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) binding; - return get(ptb.erasure(), failOnNull); - } else if (binding instanceof ParameterizedMethodBinding) { - ParameterizedMethodBinding pmb = (ParameterizedMethodBinding) binding; - return get(pmb.original(), failOnNull); - } else if (binding instanceof ParameterizedFieldBinding) { - ParameterizedFieldBinding pfb = (ParameterizedFieldBinding) binding; - return get(pfb.original(), failOnNull); - } else if (binding instanceof WildcardBinding) { - WildcardBinding wcb = (WildcardBinding) binding; - return get(wcb.erasure(), failOnNull); - } - JNode result = internalGet(binding, failOnNull); - if (result == null && failOnNull) { - InternalCompilerException ice = new InternalCompilerException("Failed to get JNode"); - ice.addNode(binding.getClass().getName(), binding.toString(), null); - throw ice; - } - return result; - } - - private JField getFieldForBinding(JDeclaredType type, FieldBinding binding) { - for (JField field : type.getFields()) { - if (field.getName().equals(String.valueOf(binding.name))) { - return field; - } - } - - return null; - } - - private JMethod getMethodForBinding(JDeclaredType type, MethodBinding binding) { - for (JMethod method : type.getMethods()) { - if (equals(binding, method)) { - return method; - } - } - - return null; - } - - /** - * Returns a list of JNodes that have the same name as the JDT Binding. This - * method is only used during debugging sessions from the interactive - * expression evaluator. - */ - @SuppressWarnings("unused") - private List<JNode> haveSameName(Binding binding) { - IdentityHashSet<JNode> nodes = new IdentityHashSet<JNode>(); - for (Binding b : crossRefMap.keySet()) { - if (String.valueOf(b.readableName()).equals(String.valueOf(binding.readableName()))) { - nodes.add(crossRefMap.get(b)); - } - } - return new ArrayList<JNode>(nodes); - } - - private JNode internalGet(Binding binding, boolean failOnNull) { - JNode cached = crossRefMap.get(binding); - if (cached != null) { - return cached; - } else if (binding instanceof BaseTypeBinding) { - BaseTypeBinding baseTypeBinding = (BaseTypeBinding) binding; - // see org.eclipse.jdt.internal.compiler.lookup.TypeIds constants - switch (baseTypeBinding.id) { - case TypeIds.T_JavaLangObject: - // here for consistency, should already be cached - return program.getTypeJavaLangObject(); - case TypeIds.T_char: - return program.getTypePrimitiveChar(); - case TypeIds.T_byte: - return program.getTypePrimitiveByte(); - case TypeIds.T_short: - return program.getTypePrimitiveShort(); - case TypeIds.T_boolean: - return program.getTypePrimitiveBoolean(); - case TypeIds.T_void: - return program.getTypeVoid(); - case TypeIds.T_long: - return program.getTypePrimitiveLong(); - case TypeIds.T_double: - return program.getTypePrimitiveDouble(); - case TypeIds.T_float: - return program.getTypePrimitiveFloat(); - case TypeIds.T_int: - return program.getTypePrimitiveInt(); - case TypeIds.T_JavaLangString: - // here for consistency, should already be cached - return program.getTypeJavaLangString(); - case TypeIds.T_null: - return program.getTypeNull(); - case TypeIds.T_undefined: - default: - return null; - } - } else if (binding instanceof ArrayBinding) { - ArrayBinding arrayBinding = (ArrayBinding) binding; - JType elementType = (JType) get(arrayBinding.elementsType(), failOnNull); - if (elementType == null) { - return null; - } - return program.getTypeArray(elementType); - } else if (binding instanceof BinaryTypeBinding) { - BinaryTypeBinding binaryBinding = (BinaryTypeBinding) binding; - String name = BuildTypeMap.dotify(binaryBinding.compoundName); - - // There may be many BinaryTypeBindings for a single binary type - JDeclaredType type = externalTypesByName.get(name); - if (type != null) { - put(binding, type); - } - return type; - } else if (binding instanceof MethodBinding) { - MethodBinding b = (MethodBinding) binding; - JMethod cachedMethod = (JMethod) crossRefMap.get(b); - if (cachedMethod == null) { - JDeclaredType type = (JDeclaredType) get(b.declaringClass, failOnNull); - if (type == null) { - return type; - } - cachedMethod = getMethodForBinding(type, b); - if (cachedMethod != null) { - put(b, cachedMethod); - } - } else { - // Happens sometimes when looking up the type to resolve the binding - // causes us to also resolve the binding. - } - - return cachedMethod; - } else if (binding instanceof FieldBinding) { - FieldBinding b = (FieldBinding) binding; - JField cachedField = (JField) crossRefMap.get(b); - - if (cachedField == null) { - JDeclaredType type = (JDeclaredType) get(b.declaringClass, failOnNull); - if (type == null) { - return null; - } - cachedField = getFieldForBinding(type, b); - if (cachedField != null) { - put(b, cachedField); - } - } else { - // Happens sometimes when looking up the type to resolve the binding - // causes us to also resolve the binding. - } - - return cachedField; - } - - return null; - } -} \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java index a46ae10..06490a1 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -516,10 +516,13 @@ this.classFileMapBySource = rpo.getCompilationState().getClassFileMapBySource(); } - public void addRootTypes(Collection<String> sourceTypeNames) { + public void addRootTypes(Collection<String> sourceTypeNames) throws UnableToCompleteException { for (String sourceTypeName : sourceTypeNames) { searchForTypeBySource(sourceTypeName); } + if (errorsFound) { + throw new UnableToCompleteException(); + } } /**
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java index 5082227..3ed9a94 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java +++ b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
@@ -215,30 +215,31 @@ createSampleProgram(); } - private JClassType createClass(String className, JClassType superClass, - boolean isAbstract, boolean isFinal) { - JClassType clazz = program.createClass(synthSource, className, isAbstract, - isFinal); - clazz.setSuperClass(superClass); - return clazz; + private JClassType createClass(String className, JClassType superClass, boolean isAbstract, + boolean isFinal) { + JClassType x = new JClassType(synthSource, className, isAbstract, isFinal); + program.addType(x); + x.setSuperClass(superClass); + return x; } private JInterfaceType createInterface(String className) { - JInterfaceType intf = program.createInterface(synthSource, className); - return intf; + JInterfaceType x = new JInterfaceType(synthSource, className); + program.addType(x); + return x; } private void createSampleProgram() { // Make the program itself program = new JProgram(); typeOracle = program.typeOracle; - synthSource = program.createSourceInfoSynthetic(JjsTypeTest.class); + synthSource = SourceOrigin.UNKNOWN; classObject = createClass("java.lang.Object", null, false, false); classString = createClass("java.lang.String", classObject, false, true); createClass("com.google.gwt.lang.Array", classObject, false, true); - classJso = createClass("com.google.gwt.core.client.JavaScriptObject", - classObject, false, false); + classJso = + createClass("com.google.gwt.core.client.JavaScriptObject", classObject, false, false); intfSerializable = createInterface("java.io.Serializable"); intfCloneable = createInterface("java.lang.Cloneable"); @@ -267,7 +268,7 @@ classJso1.addImplements(intfJ); classJso2 = createClass("Jso2", classJso, false, false); classJso2.addImplements(intfK); - + program.typeOracle.computeBeforeAST(); // Save off some miscellaneous types to test against @@ -287,8 +288,7 @@ arrayOfArrayOfB = program.getTypeArray(classB, 2); } - private JReferenceType generalizeTypes(JReferenceType type1, - JReferenceType type2) { + private JReferenceType generalizeTypes(JReferenceType type1, JReferenceType type2) { List<JReferenceType> types = new ArrayList<JReferenceType>(2); types.add(type1); types.add(type2);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java index a1087b0..39c0741 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
@@ -235,17 +235,13 @@ } }); addBuiltinClasses(sourceOracle); - boolean wasEnabled = GwtAstBuilder.ENABLED; - try { - GwtAstBuilder.ENABLED = true; - CompilationState state = CompilationStateBuilder.buildFrom(logger, - sourceOracle.getResources(), getAdditionalTypeProviderDelegate()); - JProgram program = JavaAstConstructor.construct(logger, state, - "test.EntryPoint", "com.google.gwt.lang.Exceptions"); - return program; - } finally { - GwtAstBuilder.ENABLED = wasEnabled; - } + CompilationState state = + CompilationStateBuilder.buildFrom(logger, sourceOracle.getResources(), + getAdditionalTypeProviderDelegate()); + JProgram program = + JavaAstConstructor.construct(logger, state, "test.EntryPoint", + "com.google.gwt.lang.Exceptions"); + return program; } protected void addBuiltinClasses(MockResourceOracle sourceOracle) {
diff --git a/user/test/com/google/gwt/dev/jjs/GwtAstBuilderTest.java b/user/test/com/google/gwt/dev/jjs/GwtAstBuilderTest.java deleted file mode 100644 index e3ab41e..0000000 --- a/user/test/com/google/gwt/dev/jjs/GwtAstBuilderTest.java +++ /dev/null
@@ -1,149 +0,0 @@ -/* - * Copyright 2011 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.jjs; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.dev.GwtAstBuilderUtil; -import com.google.gwt.dev.cfg.ModuleDef; -import com.google.gwt.dev.cfg.ModuleDefLoader; -import com.google.gwt.dev.javac.CompilationState; -import com.google.gwt.dev.javac.CompilationUnit; -import com.google.gwt.dev.jjs.ast.JDeclaredType; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.util.log.PrintWriterTreeLogger; - -import junit.framework.TestCase; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Massive test for {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder}. - */ -public class GwtAstBuilderTest extends TestCase { - /* - * Reuse the module and compilation state between tests, because it takes a - * long time to build them. This is fine as long as we don't mutate them. - */ - - private static CompilationState compilationState; - private static PrintWriterTreeLogger logger; - private static ModuleDef module; - - private static synchronized CompilationState getCompilationState() - throws UnableToCompleteException { - if (compilationState == null) { - compilationState = GwtAstBuilderUtil.buildGwtAst(getLogger(), getTestModule()); - } - return compilationState; - } - - private static synchronized TreeLogger getLogger() { - if (logger == null) { - logger = new PrintWriterTreeLogger(new PrintWriter(System.err, true)); - logger.setMaxDetail(TreeLogger.ERROR); - } - return logger; - } - - private static synchronized ModuleDef getTestModule() throws UnableToCompleteException { - if (module == null) { - module = - ModuleDefLoader.createSyntheticModule(getLogger(), - "com.google.gwt.dev.jjs.CompilerSuite.GwtAstBuilderTest", new String[]{ - "com.google.gwt.junit.JUnit", "com.google.gwt.dev.jjs.CompilerSuite"}, false); - } - return module; - } - - /** - * Tests source compatibility between - * {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder} and - * {@link com.google.gwt.dev.jjs.impl.GenerateJavaAST}. - */ - public void testGwtAstBuilder() throws UnableToCompleteException { - CompilationState compilationState = getCompilationState(); - assertFalse(compilationState.hasErrors()); - JProgram jprogram = - GwtAstBuilderUtil.buildGenerateJavaAst(getLogger(), getTestModule(), compilationState); - - Map<String, JDeclaredType> compStateTypes = new HashMap<String, JDeclaredType>(); - for (CompilationUnit unit : compilationState.getCompilationUnits()) { - for (JDeclaredType type : unit.getTypes()) { - compStateTypes.put(type.getName(), type); - } - } - - for (JDeclaredType genJavaAstType : jprogram.getDeclaredTypes()) { - String typeName = genJavaAstType.getName(); - if ("com.google.gwt.core.client.GWT".equals(typeName)) { - // Known mismatch; UnifyAst fills in the magic methods. - continue; - } - if ("com.google.gwt.core.client.JavaScriptObject".equals(typeName)) { - // Known mismatch; genJavaAst version implements all JSO interfaces. - continue; - } - if ("com.google.gwt.dev.jjs.test.B$1".equals(typeName)) { - // Known mismatch; genJavaAst is "wrong". - continue; - } - if (typeName.startsWith("com.google.gwt.dev.jjs.test.CoverageTest$Inner$1")) { - // Known mismatch; two different emulation paths do the same thing. - continue; - } - JDeclaredType compStateType = compStateTypes.get(typeName); - assertNotNull("No matching prebuilt type for '" + typeName + "'", compStateType); - String oldSource = genJavaAstType.toSource(); - String newSource = compStateType.toSource(); - assertEquals("Mismatched output for '" + typeName + "'", oldSource, newSource); - } - } - - /** - * Test that serialization doesn't crash and produces the same source tree. - */ - public void testSerialization() throws UnableToCompleteException, IOException, - ClassNotFoundException { - CompilationState compilationState = getCompilationState(); - assertFalse(compilationState.hasErrors()); - for (CompilationUnit unit : compilationState.getCompilationUnits()) { - Map<String, JDeclaredType> compStateTypes = new HashMap<String, JDeclaredType>(); - for (JDeclaredType type : unit.getTypes()) { - compStateTypes.put(type.getName(), type); - } - byte[] bytes = unit.getTypesSerialized(); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bais); - List<JDeclaredType> deserializedTypes = JProgram.deserializeTypes(ois); - assertEquals(compStateTypes.size(), deserializedTypes.size()); - for (JDeclaredType deserializedType : deserializedTypes) { - String typeName = deserializedType.getName(); - JDeclaredType compStateType = compStateTypes.get(typeName); - assertNotNull("No matching prebuilt type for '" + typeName + "'", compStateType); - String oldSource = compStateType.toSource(); - String newSource = deserializedType.toSource(); - assertEquals("Mismatched output for '" + typeName + "'", oldSource, newSource); - } - } - } -}