blob: 34921080ee318586433b7bb0da7aacbf94315c01 [file] [log] [blame]
/*
* 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;
}
}
}