예제 #1
0
  @Override
  public Void visitXmlTagNode(XmlTagNode node) {
    if (isScriptNode(node)) {
      Source htmlSource = htmlElement.getSource();
      String scriptSourcePath = getScriptSourcePath(node);
      if (node.getAttributeEnd().getType() == TokenType.GT && scriptSourcePath == null) {
        EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
        String contents = node.getContent();

        // TODO (danrubel): Move scanning embedded scripts into AnalysisContextImpl
        // so that clients such as builder can scan, parse, and get errors without resolving
        AnalysisErrorListener errorListener =
            new AnalysisErrorListener() {
              @Override
              public void onError(AnalysisError error) {
                // TODO (danrubel): make errors accessible once this is moved into
                // AnalysisContextImpl
              }
            };
        StringScanner scanner = new StringScanner(null, contents, errorListener);
        com.google.dart.engine.scanner.Token firstToken = scanner.tokenize();
        int[] lineStarts = scanner.getLineStarts();

        // TODO (danrubel): Move parsing embedded scripts into AnalysisContextImpl
        // so that clients such as builder can scan, parse, and get errors without resolving
        Parser parser = new Parser(null, errorListener);
        CompilationUnit unit = parser.parseCompilationUnit(firstToken);

        try {
          CompilationUnitBuilder builder = new CompilationUnitBuilder();
          CompilationUnitElementImpl elem = builder.buildCompilationUnit(htmlSource, unit);
          LibraryElementImpl library = new LibraryElementImpl(context, null);
          library.setDefiningCompilationUnit(elem);
          script.setScriptLibrary(library);
        } catch (AnalysisException e) {
          // TODO (danrubel): Handle or forward the exception
          e.printStackTrace();
        }

        scripts.add(script);
      } else {
        ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
        if (scriptSourcePath != null) {
          script.setScriptSource(
              context.getSourceFactory().resolveUri(htmlSource, scriptSourcePath));
        }
        scripts.add(script);
      }
    } else {
      node.visitChildren(this);
    }
    return null;
  }
 @Override
 public void process(
     CompilationUnitBuilder builder,
     CompilationUnitDeclaration cud,
     List<CompiledClass> compiledClasses) {
   builder
       .setClasses(compiledClasses)
       .setTypes(Collections.<JDeclaredType>emptyList())
       .setDependencies(new Dependencies())
       .setJsniMethods(Collections.<JsniMethod>emptyList())
       .setMethodArgs(new MethodArgNamesLookup())
       .setProblems(cud.compilationResult().getProblems());
   results.add(builder.build());
 }
  public boolean doCompile(Collection<CompilationUnitBuilder> builders) {
    List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>();
    for (CompilationUnitBuilder builder : builders) {
      addPackages(Shared.getPackageName(builder.getTypeName()).replace('.', '/'));
      icus.add(new Adapter(builder));
    }
    if (icus.isEmpty()) {
      return false;
    }

    compilerImpl = new CompilerImpl();
    compilerImpl.compile(icus.toArray(new ICompilationUnit[icus.size()]));
    compilerImpl = null;
    return true;
  }
예제 #4
0
  /**
   * 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);
  }
 @Override
 public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
   char[] binaryNameChars = CharOperation.concatWith(compoundTypeName, '/');
   String binaryName = String.valueOf(binaryNameChars);
   CompiledClass compiledClass = binaryTypes.get(binaryName);
   try {
     if (compiledClass != null) {
       return compiledClass.getNameEnvironmentAnswer();
     }
   } catch (ClassFormatException ex) {
     // fall back to binary class
   }
   if (isPackage(binaryName)) {
     return null;
   }
   if (additionalTypeProviderDelegate != null) {
     GeneratedUnit unit = additionalTypeProviderDelegate.doFindAdditionalType(binaryName);
     if (unit != null) {
       CompilationUnitBuilder b = CompilationUnitBuilder.create(unit);
       Adapter a = new Adapter(b);
       return new NameEnvironmentAnswer(a, null);
     }
   }
   try {
     URL resource = getClassLoader().getResource(binaryName + ".class");
     if (resource != null) {
       InputStream openStream = resource.openStream();
       try {
         ClassFileReader cfr = ClassFileReader.read(openStream, resource.toExternalForm(), true);
         return new NameEnvironmentAnswer(cfr, null);
       } finally {
         Utility.close(openStream);
       }
     }
   } catch (ClassFormatException e) {
   } catch (IOException e) {
   }
   return null;
 }
 @Override
 public String toString() {
   return builder.toString();
 }
 @Override
 public char[][] getPackageName() {
   String packageName = Shared.getPackageName(builder.getTypeName());
   return CharOperation.splitOn('.', packageName.toCharArray());
 }
 @Override
 public char[] getMainTypeName() {
   return Shared.getShortName(builder.getTypeName()).toCharArray();
 }
 @Override
 public char[] getFileName() {
   return builder.getLocation().toCharArray();
 }
 @Override
 public char[] getContents() {
   return builder.getSource().toCharArray();
 }
예제 #11
0
      /**
       * A callback after the JDT compiler has compiled a .java file and created a matching
       * CompilationUnitDeclaration. We take this opportunity to create a matching CompilationUnit.
       */
      @Override
      public void process(
          CompilationUnitBuilder builder,
          CompilationUnitDeclaration cud,
          List<CompiledClass> compiledClasses) {
        Event event = SpeedTracerLogger.start(DevModeEventType.CSB_PROCESS);
        try {
          Map<MethodDeclaration, JsniMethod> jsniMethods =
              JsniCollector.collectJsniMethods(
                  cud,
                  builder.getSourceMapPath(),
                  builder.getSource(),
                  JsRootScope.INSTANCE,
                  DummyCorrelationFactory.INSTANCE);

          JSORestrictionsChecker.check(jsoState, cud);

          // JSNI check + collect dependencies.
          final Set<String> jsniDeps = new HashSet<String>();
          Map<String, Binding> jsniRefs = new HashMap<String, Binding>();
          JsniChecker.check(
              cud,
              jsoState,
              jsniMethods,
              jsniRefs,
              new JsniChecker.TypeResolver() {
                @Override
                public ReferenceBinding resolveType(String sourceOrBinaryName) {
                  ReferenceBinding resolveType = compiler.resolveType(sourceOrBinaryName);
                  if (resolveType != null) {
                    jsniDeps.add(String.valueOf(resolveType.qualifiedSourceName()));
                  }
                  return resolveType;
                }
              });

          Map<TypeDeclaration, Binding[]> artificialRescues =
              new HashMap<TypeDeclaration, Binding[]>();
          ArtificialRescueChecker.check(cud, builder.isGenerated(), artificialRescues);
          if (compilerContext.shouldCompileMonolithic()) {
            // GWT drives JDT in a way that allows missing references in the source to be resolved
            // to precompiled bytecode on disk (see INameEnvironment). This is done so that
            // annotations can be supplied in bytecode form only. But since no AST is available for
            // these types it creates the danger that some functional class (not just an annotation)
            // gets filled in but is missing AST. This would cause later compiler stages to fail.
            //
            // Library compilation needs to ignore this check since it is expected behavior for the
            // source being compiled in a library to make references to other types which are only
            // available as bytecode coming out of dependency libraries.
            //
            // But if the referenced bytecode did not come from a dependency library but instead was
            // free floating in the classpath, then there is no guarrantee that AST for it was ever
            // seen and translated to JS anywhere in the dependency tree. This would be a mistake.
            //
            // TODO(stalcup): add a more specific check for library compiles such that binary types
            // can be referenced but only if they are an Annotation or if the binary type comes from
            // a dependency library.
            BinaryTypeReferenceRestrictionsChecker.check(cud);
          }

          MethodArgNamesLookup methodArgs =
              MethodParamCollector.collect(cud, builder.getSourceMapPath());

          Interner<String> interner = StringInterner.get();
          String packageName = interner.intern(Shared.getPackageName(builder.getTypeName()));
          List<String> unresolvedQualified = new ArrayList<String>();
          List<String> unresolvedSimple = new ArrayList<String>();
          for (char[] simpleRef : cud.compilationResult().simpleNameReferences) {
            unresolvedSimple.add(interner.intern(String.valueOf(simpleRef)));
          }
          for (char[][] qualifiedRef : cud.compilationResult().qualifiedReferences) {
            unresolvedQualified.add(interner.intern(CharOperation.toString(qualifiedRef)));
          }
          for (String jsniDep : jsniDeps) {
            unresolvedQualified.add(interner.intern(jsniDep));
          }
          ArrayList<String> apiRefs = compiler.collectApiRefs(cud);
          for (int i = 0; i < apiRefs.size(); ++i) {
            apiRefs.set(i, interner.intern(apiRefs.get(i)));
          }
          Dependencies dependencies =
              new Dependencies(packageName, unresolvedQualified, unresolvedSimple, apiRefs);

          List<JDeclaredType> types = Collections.emptyList();
          if (!cud.compilationResult().hasErrors()) {
            // Make a GWT AST.
            types =
                astBuilder.process(
                    cud, builder.getSourceMapPath(), artificialRescues, jsniMethods, jsniRefs);
          }

          for (CompiledClass cc : compiledClasses) {
            allValidClasses.put(cc.getSourceName(), cc);
          }

          builder
              .setClasses(compiledClasses)
              .setTypes(types)
              .setDependencies(dependencies)
              .setJsniMethods(jsniMethods.values())
              .setMethodArgs(methodArgs)
              .setProblems(cud.compilationResult().getProblems());
          buildQueue.add(builder);
        } finally {
          event.end();
        }
      }
예제 #12
0
  /**
   * 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);
  }
예제 #13
0
    /**
     * 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;
    }