All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.dev.jdt.WebModeCompilerFrontEnd Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * 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.FragmentLoaderCreator;
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.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;

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 FragmentLoaderCreator fragmentLoaderCreator;
  private final RebindPermutationOracle rebindPermOracle;

  /**
   * Construct a WebModeCompilerFrontEnd. The reason a
   * {@link FragmentLoaderCreator} needs to be passed in is that it uses
   * generator infrastructure, and therefore needs access to more parts of the
   * compiler than WebModeCompilerFrontEnd currently has.
   */
  private WebModeCompilerFrontEnd(RebindPermutationOracle rebindPermOracle,
      TypeLinker linker) {
    super(rebindPermOracle.getCompilationState(), linker);
    this.rebindPermOracle = rebindPermOracle;
    this.fragmentLoaderCreator = new FragmentLoaderCreator(
        rebindPermOracle.getGeneratorContext());
  }

  @Override
  protected String[] doFindAdditionalTypesUsingArtificialRescues(
      TreeLogger logger, CompilationUnitDeclaration cud) {
    List 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 dependentTypeNames = new LinkedHashSet();

    // Find all the deferred binding request types.
    FindDeferredBindingSitesVisitor v = new FindDeferredBindingSitesVisitor();
    cud.traverse(v, cud.scope);
    Map requestedTypes = v.getSites();
    Map rebindAnswers = new HashMap();
    boolean doFinish = false;

    // For each, ask the host for every possible deferred binding answer.
    for (Map.Entry 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]);
      }
    }

    /*
     * Create a a fragment loader for each GWT.runAsync call. They must be
     * created now, rather than in ReplaceRunAsyncs, because all generated
     * classes need to be created before GenerateJavaAST. Note that the loaders
     * created are not yet associated with the specific sites. The present task
     * is only to make sure that enough loaders exist. The real association
     * between loaders and runAsync sites will be made in ReplaceRunAsyncs.
     */
    for (MessageSendSite site : v.getRunAsyncSites()) {
      String resultType;
      try {
        resultType = fragmentLoaderCreator.create(logger);
        dependentTypeNames.add(resultType);
        doFinish = true;
      } catch (UnableToCompleteException e) {
        FindDeferredBindingSitesVisitor.reportRebindProblem(site,
            "Failed to create a runAsync fragment loader");
      }
    }

    if (doFinish) {
      rebindPermOracle.getGeneratorContext().finish(logger);
    }

    // Sanity check all rebind answers.
    for (Map.Entry 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(TypeBinding.NO_PARAMETERS);
    if (noArgCtor == null) {
      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
          "Rebind result '" + typeName
              + "' has no default (zero argument) constructors");
      return;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy