/**
  * Create a compilation unit that can be serialized from another {@link CompilationUnit}.
  *
  * @param unit A unit to copy
  * @param sourceToken A valid {@DiskCache} token for this unit's source code.
  * @param astToken A valid {@DiskCache} token for this unit's serialized AST types.
  */
 @SuppressWarnings("deprecation")
 CachedCompilationUnit(CompilationUnit unit, long sourceToken, long astToken) {
   assert unit != null;
   this.compiledClasses = unit.getCompiledClasses();
   this.contentId = unit.getContentId();
   this.dependencies = unit.getDependencies();
   this.resourceLocation = unit.getResourceLocation();
   this.resourcePath = unit.getResourcePath();
   this.jsniMethods = unit.getJsniMethods();
   this.lastModified = unit.getLastModified();
   this.methodArgNamesLookup = unit.getMethodArgs();
   this.typeName = unit.getTypeName();
   this.isError = unit.isError();
   this.isGenerated = unit.isGenerated();
   this.isSuperSource = unit.isSuperSource();
   CategorizedProblem[] problemsIn = unit.getProblems();
   if (problemsIn == null) {
     this.problems = null;
   } else {
     this.problems = new CategorizedProblem[problemsIn.length];
     for (int i = 0; i < problemsIn.length; i++) {
       this.problems[i] = new SerializableCategorizedProblem(problemsIn[i]);
     }
   }
   this.astToken = new DiskCacheToken(astToken);
   this.astVersion = GwtAstBuilder.getSerializationVersion();
   this.sourceToken = new DiskCacheToken(sourceToken);
 }
 /** 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);
     }
   }
 }
  /**
   * 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);
  }