public CompileMoreLater(
     CompilerContext compilerContext, AdditionalTypeProviderDelegate delegate) {
   this.compilerContext = compilerContext;
   this.compiler = new JdtCompiler(compilerContext, new UnitProcessorImpl());
   this.suppressErrors = !compilerContext.getOptions().isStrict();
   compiler.setAdditionalTypeProviderDelegate(delegate);
 }
 /** Use previously compiled {@link CompilationUnit}s to pre-populate the unit cache. */
 public static void addArchive(
     CompilerContext compilerContext, CompilationUnitArchive compilationUnitArchive) {
   UnitCache unitCache = compilerContext.getUnitCache();
   for (CachedCompilationUnit archivedUnit : compilationUnitArchive.getUnits().values()) {
     if (archivedUnit.getTypesSerializedVersion() != GwtAstBuilder.getSerializationVersion()) {
       continue;
     }
     CompilationUnit cachedCompilationUnit = unitCache.find(archivedUnit.getResourcePath());
     // A previously cached unit might be from the persistent cache or another
     // archive.
     if (cachedCompilationUnit == null
         || cachedCompilationUnit.getLastModified() < archivedUnit.getLastModified()) {
       unitCache.addArchivedUnit(archivedUnit);
     }
   }
 }
 public void assertHonorsStrictResources(boolean strictResources)
     throws UnableToCompleteException {
   TreeLogger logger = TreeLogger.NULL;
   compilerContext.getOptions().setEnforceStrictResources(strictResources);
   ModuleDef emptyModule =
       ModuleDefLoader.loadFromClassPath(
           logger, compilerContext, "com.google.gwt.dev.cfg.testdata.merging.Empty");
   Resource sourceFile =
       emptyModule.findSourceFile("com/google/gwt/dev/cfg/testdata/merging/client/InOne.java");
   Resource publicFile = emptyModule.findPublicFile("Public.java");
   if (strictResources) {
     // Empty.gwt.xml did not register any source or public paths and the strictResource setting is
     // blocking the implicit addition of any default entries. So these resource searches should
     // fail.
     assertNull(sourceFile);
     assertNull(publicFile);
   } else {
     assertNotNull(sourceFile);
     assertNotNull(publicFile);
   }
 }
  /**
   * Compile new generated units into an existing state.
   *
   * <p>TODO: maybe use a finer brush than to synchronize the whole thing.
   */
  synchronized Collection<CompilationUnit> doBuildGeneratedTypes(
      TreeLogger logger,
      CompilerContext compilerContext,
      Collection<GeneratedUnit> generatedUnits,
      CompileMoreLater compileMoreLater)
      throws UnableToCompleteException {
    UnitCache unitCache = compilerContext.getUnitCache();

    // Units we definitely want to build.
    List<CompilationUnitBuilder> builders = new ArrayList<CompilationUnitBuilder>();

    // Units we don't want to rebuild unless we have to.
    Map<CompilationUnitBuilder, CompilationUnit> cachedUnits =
        new IdentityHashMap<CompilationUnitBuilder, CompilationUnit>();

    // For each incoming generated Java source file...
    for (GeneratedUnit generatedUnit : generatedUnits) {
      // Create a builder for all incoming units.
      CompilationUnitBuilder builder = CompilationUnitBuilder.create(generatedUnit);

      // Look for units previously compiled
      CompilationUnit cachedUnit = unitCache.find(builder.getContentId());
      if (cachedUnit != null) {
        // Recompile generated units with errors so source can be dumped.
        if (!cachedUnit.isError()) {
          cachedUnits.put(builder, cachedUnit);
          compileMoreLater.addValidUnit(cachedUnit);
          continue;
        }
      }
      builders.add(builder);
    }
    return compileMoreLater.compile(
        logger,
        compilerContext,
        builders,
        cachedUnits,
        CompilerEventType.JDT_COMPILER_CSB_GENERATED);
  }
  /**
   * Build a new compilation state from a source oracle. Allow the caller to specify a compiler
   * delegate that will handle undefined names.
   *
   * <p>TODO: maybe use a finer brush than to synchronize the whole thing.
   */
  public synchronized CompilationState doBuildFrom(
      TreeLogger logger,
      CompilerContext compilerContext,
      Set<Resource> resources,
      AdditionalTypeProviderDelegate compilerDelegate)
      throws UnableToCompleteException {
    UnitCache unitCache = compilerContext.getUnitCache();

    // Units we definitely want to build.
    List<CompilationUnitBuilder> builders = new ArrayList<CompilationUnitBuilder>();

    // Units we don't want to rebuild unless we have to.
    Map<CompilationUnitBuilder, CompilationUnit> cachedUnits =
        new IdentityHashMap<CompilationUnitBuilder, CompilationUnit>();

    CompileMoreLater compileMoreLater = new CompileMoreLater(compilerContext, compilerDelegate);

    // For each incoming Java source file...
    for (Resource resource : resources) {
      // Create a builder for all incoming units.
      CompilationUnitBuilder builder = CompilationUnitBuilder.create(resource);

      CompilationUnit cachedUnit = unitCache.find(resource.getPathPrefix() + resource.getPath());

      // Try to rescue cached units from previous sessions where a jar has been
      // recompiled.
      if (cachedUnit != null && cachedUnit.getLastModified() != resource.getLastModified()) {
        unitCache.remove(cachedUnit);
        if (cachedUnit instanceof CachedCompilationUnit
            && cachedUnit.getContentId().equals(builder.getContentId())) {
          CachedCompilationUnit updatedUnit =
              new CachedCompilationUnit(
                  (CachedCompilationUnit) cachedUnit,
                  resource.getLastModified(),
                  resource.getLocation());
          unitCache.add(updatedUnit);
        } else {
          cachedUnit = null;
        }
      }
      if (cachedUnit != null) {
        cachedUnits.put(builder, cachedUnit);
        compileMoreLater.addValidUnit(cachedUnit);
        continue;
      }
      builders.add(builder);
    }
    if (logger.isLoggable(TreeLogger.TRACE)) {
      logger.log(
          TreeLogger.TRACE,
          "Found "
              + cachedUnits.size()
              + " cached/archived units.  Used "
              + cachedUnits.size()
              + " / "
              + resources.size()
              + " units from cache.");
    }

    Collection<CompilationUnit> resultUnits =
        compileMoreLater.compile(
            logger,
            compilerContext,
            builders,
            cachedUnits,
            CompilerEventType.JDT_COMPILER_CSB_FROM_ORACLE);

    boolean compileMonolithic = compilerContext.shouldCompileMonolithic();
    TypeOracle typeOracle = null;
    CompilationUnitTypeOracleUpdater typeOracleUpdater = null;
    if (compileMonolithic) {
      typeOracle = new TypeOracle();
      typeOracleUpdater = new CompilationUnitTypeOracleUpdater(typeOracle);
    } else {
      typeOracle = new LibraryTypeOracle(compilerContext);
      typeOracleUpdater = ((LibraryTypeOracle) typeOracle).getTypeOracleUpdater();
    }

    return new CompilationState(
        logger, compilerContext, typeOracle, typeOracleUpdater, resultUnits, compileMoreLater);
  }
    /**
     * Compiles the source code in each supplied CompilationUnitBuilder into a CompilationUnit and
     * reports errors.
     *
     * <p>A compilation unit is considered invalid if any of its dependencies (recursively) isn't
     * being compiled and isn't in allValidClasses, or if it has a signature that doesn't match a
     * dependency. Valid compilation units will be added to cachedUnits and the unit cache, and
     * their types will be added to allValidClasses. Invalid compilation units will be removed.
     *
     * <p>I/O: serializes the AST of each Java type to DiskCache. (This happens even if the
     * compilation unit is later dropped.) If we're using the persistent unit cache, each valid unit
     * will also be serialized to the gwt-unitcache file. (As a result, each AST will be copied
     * there from the DiskCache.) A new persistent unit cache file will be created each time
     * compile() is called (if there's at least one valid unit) and the entire cache will be
     * rewritten to disk every {@link PersistentUnitCache#CACHE_FILE_THRESHOLD} files.
     *
     * <p>This function won't report errors in invalid source files unless suppressErrors is false.
     * Instead, a summary giving the number of invalid files will be logged.
     *
     * <p>If the JDT compiler aborts, logs an error and throws UnableToCompleteException. (This
     * doesn't happen for normal compile errors.)
     */
    Collection<CompilationUnit> compile(
        TreeLogger logger,
        CompilerContext compilerContext,
        Collection<CompilationUnitBuilder> builders,
        Map<CompilationUnitBuilder, CompilationUnit> cachedUnits,
        EventType eventType)
        throws UnableToCompleteException {
      UnitCache unitCache = compilerContext.getUnitCache();
      // Initialize the set of valid classes to the initially cached units.
      for (CompilationUnit unit : cachedUnits.values()) {
        for (CompiledClass cc : unit.getCompiledClasses()) {
          // Map by source name.
          String sourceName = cc.getSourceName();
          allValidClasses.put(sourceName, cc);
        }
      }

      ArrayList<CompilationUnit> resultUnits = new ArrayList<CompilationUnit>();
      do {
        final TreeLogger branch = logger.branch(TreeLogger.TRACE, "Compiling...");
        // Compile anything that needs to be compiled.
        buildQueue = new LinkedBlockingQueue<CompilationUnitBuilder>();
        final ArrayList<CompilationUnit> newlyBuiltUnits = new ArrayList<CompilationUnit>();
        final CompilationUnitBuilder sentinel = CompilationUnitBuilder.create((GeneratedUnit) null);
        final Throwable[] workerException = new Throwable[1];
        final ProgressLogger progressLogger =
            new ProgressLogger(branch, TreeLogger.TRACE, builders.size(), 10);
        Thread buildThread =
            new Thread() {
              @Override
              public void run() {
                int processedCompilationUnitBuilders = 0;
                try {
                  do {
                    CompilationUnitBuilder builder = buildQueue.take();
                    if (!progressLogger.isTimerStarted()) {
                      // Set start time here, after first job has arrived, since it can take a
                      // little
                      // while for the first job to arrive, and this helps with the accuracy of the
                      // estimated times.
                      progressLogger.startTimer();
                    }
                    if (builder == sentinel) {
                      return;
                    }
                    // Expensive, must serialize GWT AST types to bytes.
                    CompilationUnit unit = builder.build();
                    newlyBuiltUnits.add(unit);

                    processedCompilationUnitBuilders++;
                    progressLogger.updateProgress(processedCompilationUnitBuilders);
                  } while (true);
                } catch (Throwable e) {
                  workerException[0] = e;
                }
              }
            };
        buildThread.setName("CompilationUnitBuilder");
        buildThread.start();
        Event jdtCompilerEvent = SpeedTracerLogger.start(eventType);
        long compilationStartNanos = System.nanoTime();
        try {
          compiler.doCompile(branch, builders);
        } finally {
          jdtCompilerEvent.end();
        }
        buildQueue.add(sentinel);
        try {
          buildThread.join();
          long compilationNanos = System.nanoTime() - compilationStartNanos;
          // Convert nanos to seconds.
          double compilationSeconds = compilationNanos / (double) TimeUnit.SECONDS.toNanos(1);
          branch.log(
              TreeLogger.TRACE,
              String.format("Compilation completed in %.02f seconds", compilationSeconds));
          if (workerException[0] != null) {
            throw workerException[0];
          }
        } catch (RuntimeException e) {
          throw e;
        } catch (Throwable e) {
          throw new RuntimeException("Exception processing units", e);
        } finally {
          buildQueue = null;
        }
        resultUnits.addAll(newlyBuiltUnits);
        builders.clear();

        // Resolve all newly built unit deps against the global classes.
        for (CompilationUnit unit : newlyBuiltUnits) {
          unit.getDependencies().resolve(allValidClasses);
        }

        /*
         * Invalidate any cached units with invalid refs.
         */
        Collection<CompilationUnit> invalidatedUnits = new ArrayList<CompilationUnit>();
        for (Iterator<Entry<CompilationUnitBuilder, CompilationUnit>> it =
                cachedUnits.entrySet().iterator();
            it.hasNext(); ) {
          Entry<CompilationUnitBuilder, CompilationUnit> entry = it.next();
          CompilationUnit unit = entry.getValue();
          boolean isValid = unit.getDependencies().validate(logger, allValidClasses);
          if (isValid && unit.isError()) {
            // See if the unit has classes that can't provide a
            // NameEnvironmentAnswer
            for (CompiledClass cc : unit.getCompiledClasses()) {
              try {
                cc.getNameEnvironmentAnswer();
              } catch (ClassFormatException ex) {
                isValid = false;
                break;
              }
            }
          }
          if (!isValid) {
            if (logger.isLoggable(TreeLogger.TRACE)) {
              logger.log(TreeLogger.TRACE, "Invalid Unit: " + unit.getTypeName());
            }
            invalidatedUnits.add(unit);
            builders.add(entry.getKey());
            it.remove();
          }
        }

        if (invalidatedUnits.size() > 0) {
          if (logger.isLoggable(TreeLogger.TRACE)) {
            logger.log(TreeLogger.TRACE, "Invalid units found: " + invalidatedUnits.size());
          }
        }

        // Any units we invalidated must now be removed from the valid classes.
        for (CompilationUnit unit : invalidatedUnits) {
          for (CompiledClass cc : unit.getCompiledClasses()) {
            allValidClasses.remove(cc.getSourceName());
          }
        }
      } while (builders.size() > 0);

      for (CompilationUnit unit : resultUnits) {
        unitCache.add(unit);
      }

      // Any remaining cached units are valid now.
      resultUnits.addAll(cachedUnits.values());

      // Done with a pass of the build - tell the cache its OK to cleanup
      // stale cache files.
      unitCache.cleanup(logger);

      // Sort, then report all errors (re-report for cached units).
      Collections.sort(resultUnits, CompilationUnit.COMPARATOR);
      logger = logger.branch(TreeLogger.DEBUG, "Validating units:");
      int errorCount = 0;
      for (CompilationUnit unit : resultUnits) {
        if (CompilationProblemReporter.reportErrors(logger, unit, suppressErrors)) {
          errorCount++;
        }
      }
      if (suppressErrors
          && errorCount > 0
          && !logger.isLoggable(TreeLogger.TRACE)
          && logger.isLoggable(TreeLogger.INFO)) {
        logger.log(
            TreeLogger.INFO,
            "Ignored "
                + errorCount
                + " unit"
                + (errorCount > 1 ? "s" : "")
                + " with compilation errors in first pass.\n"
                + "Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.");
      }
      return resultUnits;
    }