001: /*
002: * Copyright 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.jdt;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.core.ext.UnableToCompleteException;
020: import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor.DeferredBindingSite;
021: import com.google.gwt.dev.util.Empty;
022: import com.google.gwt.dev.util.Util;
023:
024: import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
025: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
026: import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
027: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
028: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
029:
030: import java.util.HashMap;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.Map;
034: import java.util.Set;
035:
036: /**
037: * Provides a reusable front-end based on the JDT compiler that incorporates
038: * GWT-specific concepts such as JSNI and deferred binding.
039: */
040: public class WebModeCompilerFrontEnd extends AstCompiler {
041:
042: private final RebindPermutationOracle rebindPermOracle;
043:
044: public WebModeCompilerFrontEnd(SourceOracle sourceOracle,
045: RebindPermutationOracle rebindPermOracle) {
046: super (sourceOracle);
047: this .rebindPermOracle = rebindPermOracle;
048: }
049:
050: public CompilationUnitDeclaration[] getCompilationUnitDeclarations(
051: TreeLogger logger, String[] seedTypeNames)
052: throws UnableToCompleteException {
053:
054: // Build the initial set of compilation units.
055: //
056: ICompilationUnit[] units = new ICompilationUnit[seedTypeNames.length];
057: for (int i = 0; i < seedTypeNames.length; i++) {
058: String seedTypeName = seedTypeNames[i];
059: units[i] = getCompilationUnitForType(logger, seedTypeName);
060: }
061:
062: // Compile, which will pull in everything else via
063: // doFindAdditionalTypesUsingMagic()
064: //
065: CompilationUnitDeclaration[] cuds = compile(logger, units);
066: return cuds;
067: }
068:
069: public RebindPermutationOracle getRebindPermutationOracle() {
070: return rebindPermOracle;
071: }
072:
073: /**
074: * Pull in types referenced only via JSNI.
075: */
076: protected String[] doFindAdditionalTypesUsingJsni(
077: TreeLogger logger, CompilationUnitDeclaration cud) {
078: Set dependentTypeNames = new HashSet();
079: FindJsniRefVisitor v = new FindJsniRefVisitor(
080: dependentTypeNames);
081: cud.traverse(v, cud.scope);
082: return (String[]) dependentTypeNames.toArray(Empty.STRINGS);
083: }
084:
085: /**
086: * Pull in types implicitly referenced through rebind answers.
087: */
088: protected String[] doFindAdditionalTypesUsingRebinds(
089: TreeLogger logger, CompilationUnitDeclaration cud) {
090: Set dependentTypeNames = new HashSet();
091:
092: // Find all the deferred binding request types.
093: //
094: Map requestedTypes = new HashMap();
095: FindDeferredBindingSitesVisitor v = new FindDeferredBindingSitesVisitor(
096: requestedTypes);
097: cud.traverse(v, cud.scope);
098:
099: // For each, ask the host for every possible deferred binding answer.
100: //
101: for (Iterator iter = requestedTypes.keySet().iterator(); iter
102: .hasNext();) {
103: String reqType = (String) iter.next();
104: DeferredBindingSite site = (DeferredBindingSite) requestedTypes
105: .get(reqType);
106:
107: try {
108: String[] resultTypes = rebindPermOracle
109: .getAllPossibleRebindAnswers(logger, reqType);
110: // Check that each result is instantiable.
111: for (int i = 0; i < resultTypes.length; ++i) {
112: String typeName = resultTypes[i];
113:
114: // This causes the compiler to find the additional type, possibly
115: // winding its back to ask for the compilation unit from the source
116: // oracle.
117: //
118: ReferenceBinding type = resolvePossiblyNestedType(typeName);
119:
120: // Sanity check rebind results.
121: if (type == null) {
122: FindDeferredBindingSitesVisitor
123: .reportRebindProblem(
124: site,
125: "Rebind result '"
126: + typeName
127: + "' could not be found");
128: continue;
129: }
130: if (!type.isClass()) {
131: FindDeferredBindingSitesVisitor
132: .reportRebindProblem(site,
133: "Rebind result '" + typeName
134: + "' must be a class");
135: continue;
136: }
137: if (type.isAbstract()) {
138: FindDeferredBindingSitesVisitor
139: .reportRebindProblem(
140: site,
141: "Rebind result '"
142: + typeName
143: + "' cannot be abstract");
144: continue;
145: }
146: if (type.isNestedType() && !type.isStatic()) {
147: FindDeferredBindingSitesVisitor
148: .reportRebindProblem(
149: site,
150: "Rebind result '"
151: + typeName
152: + "' cannot be a non-static nested class");
153: continue;
154: }
155: if (type.isLocalType()) {
156: FindDeferredBindingSitesVisitor
157: .reportRebindProblem(
158: site,
159: "Rebind result '"
160: + typeName
161: + "' cannot be a local class");
162: continue;
163: }
164: // Look for a noArg ctor.
165: MethodBinding noArgCtor = type.getExactMethod(
166: "<init>".toCharArray(),
167: TypeBinding.NoParameters, cud.scope);
168:
169: if (noArgCtor == null) {
170: FindDeferredBindingSitesVisitor
171: .reportRebindProblem(
172: site,
173: "Rebind result '"
174: + typeName
175: + "' has no default (zero argument) constructors");
176: continue;
177: }
178: dependentTypeNames.add(typeName);
179: }
180: Util.addAll(dependentTypeNames, resultTypes);
181: } catch (UnableToCompleteException e) {
182: FindDeferredBindingSitesVisitor.reportRebindProblem(
183: site, "Failed to resolve '" + reqType
184: + "' via deferred binding");
185: }
186: }
187: return (String[]) dependentTypeNames.toArray(Empty.STRINGS);
188: }
189: }
|