@Override
 public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
   for (AnnotationMirror annotationMirror : elements.getAllAnnotationMirrors(e)) {
     Element e2 = annotationMirror.getAnnotationType().asElement();
     p.add((TypeElement) e2);
   }
   return super.scan(e, p);
 }
 private Set<String> initPlatformAnnotations() {
   Set<String> platformAnnotations = new HashSet<String>();
   platformAnnotations.add("java.lang.Deprecated");
   platformAnnotations.add("java.lang.Override");
   platformAnnotations.add("java.lang.SuppressWarnings");
   platformAnnotations.add("java.lang.annotation.Documented");
   platformAnnotations.add("java.lang.annotation.Inherited");
   platformAnnotations.add("java.lang.annotation.Retention");
   platformAnnotations.add("java.lang.annotation.Target");
   return Collections.unmodifiableSet(platformAnnotations);
 }
Example #3
0
  /**
   * Specify 'flow' and 'cast' as supported lint options for all Type checkers.
   *
   * <p>WMD: the above comment talks about 'flow', but I don't find a use of it as a lint option. I
   * added a new key 'flow:inferFromAsserts'. Maybe 'flow' should be used in
   * BasicAnnotatedTypeFactory with/instead of FLOW_BY_DEFAULT.
   */
  @Override
  public Set<String> getSupportedLintOptions() {
    Set<String> lintSet = new HashSet<String>(super.getSupportedLintOptions());
    lintSet.add("cast");
    lintSet.add("cast:redundant");
    lintSet.add("cast:unsafe");
    lintSet.add("flow:inferFromAsserts");
    // Temporary option to make array subtyping invariant,
    // which will be the new default soon.
    lintSet.add("arrays:invariant");
    // Temporary option to make casts stricter, in particular when casting
    // to an array or generic type. This will be the new default soon.
    lintSet.add("cast:strict");

    return Collections.unmodifiableSet(lintSet);
  }
  private void discoverAndRunProcs(
      Context context,
      Set<TypeElement> annotationsPresent,
      List<ClassSymbol> topLevelClasses,
      List<PackageSymbol> packageInfoFiles) {
    Map<String, TypeElement> unmatchedAnnotations =
        new HashMap<String, TypeElement>(annotationsPresent.size());

    for (TypeElement a : annotationsPresent) {
      unmatchedAnnotations.put(a.getQualifiedName().toString(), a);
    }

    // Give "*" processors a chance to match
    if (unmatchedAnnotations.size() == 0) unmatchedAnnotations.put("", null);

    DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator();
    // TODO: Create proper argument values; need past round
    // information to fill in this constructor.  Note that the 1
    // st round of processing could be the last round if there
    // were parse errors on the initial source files; however, we
    // are not doing processing in that case.

    Set<Element> rootElements = new LinkedHashSet<Element>();
    rootElements.addAll(topLevelClasses);
    rootElements.addAll(packageInfoFiles);
    rootElements = Collections.unmodifiableSet(rootElements);

    RoundEnvironment renv =
        new JavacRoundEnvironment(false, false, rootElements, JavacProcessingEnvironment.this);

    while (unmatchedAnnotations.size() > 0 && psi.hasNext()) {
      ProcessorState ps = psi.next();
      Set<String> matchedNames = new HashSet<String>();
      Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>();

      for (Map.Entry<String, TypeElement> entry : unmatchedAnnotations.entrySet()) {
        String unmatchedAnnotationName = entry.getKey();
        if (ps.annotationSupported(unmatchedAnnotationName)) {
          matchedNames.add(unmatchedAnnotationName);
          TypeElement te = entry.getValue();
          if (te != null) typeElements.add(te);
        }
      }

      if (matchedNames.size() > 0 || ps.contributed) {
        boolean processingResult = callProcessor(ps.processor, typeElements, renv);
        ps.contributed = true;
        ps.removeSupportedOptions(unmatchedProcessorOptions);

        if (printProcessorInfo || verbose) {
          log.printNoteLines(
              "x.print.processor.info",
              ps.processor.getClass().getName(),
              matchedNames.toString(),
              processingResult);
        }

        if (processingResult) {
          unmatchedAnnotations.keySet().removeAll(matchedNames);
        }
      }
    }
    unmatchedAnnotations.remove("");

    if (lint && unmatchedAnnotations.size() > 0) {
      // Remove annotations processed by javac
      unmatchedAnnotations.keySet().removeAll(platformAnnotations);
      if (unmatchedAnnotations.size() > 0) {
        log = Log.instance(context);
        log.warning("proc.annotations.without.processors", unmatchedAnnotations.keySet());
      }
    }

    // Run contributing processors that haven't run yet
    psi.runContributingProcs(renv);

    // Debugging
    if (options.isSet("displayFilerState")) filer.displayState();
  }
  // TODO: internal catch clauses?; catch and rethrow an annotation
  // processing error
  public JavaCompiler doProcessing(
      Context context,
      List<JCCompilationUnit> roots,
      List<ClassSymbol> classSymbols,
      Iterable<? extends PackageSymbol> pckSymbols) {

    TaskListener taskListener = context.get(TaskListener.class);
    log = Log.instance(context);

    Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
    for (PackageSymbol psym : pckSymbols) specifiedPackages.add(psym);
    this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);

    Round round = new Round(context, roots, classSymbols);

    boolean errorStatus;
    boolean moreToDo;
    do {
      // Run processors for round n
      round.run(false, false);

      // Processors for round n have run to completion.
      // Check for errors and whether there is more work to do.
      errorStatus = round.unrecoverableError();
      moreToDo = moreToDo();

      round.showDiagnostics(errorStatus || showResolveErrors);

      // Set up next round.
      // Copy mutable collections returned from filer.
      round =
          round.next(
              new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
              new LinkedHashMap<String, JavaFileObject>(filer.getGeneratedClasses()));

      // Check for errors during setup.
      if (round.unrecoverableError()) errorStatus = true;

    } while (moreToDo && !errorStatus);

    // run last round
    round.run(true, errorStatus);
    round.showDiagnostics(true);

    filer.warnIfUnclosedFiles();
    warnIfUnmatchedOptions();

    /*
     * If an annotation processor raises an error in a round,
     * that round runs to completion and one last round occurs.
     * The last round may also occur because no more source or
     * class files have been generated.  Therefore, if an error
     * was raised on either of the last *two* rounds, the compile
     * should exit with a nonzero exit code.  The current value of
     * errorStatus holds whether or not an error was raised on the
     * second to last round; errorRaised() gives the error status
     * of the last round.
     */
    if (messager.errorRaised() || werror && round.warningCount() > 0 && round.errorCount() > 0)
      errorStatus = true;

    Set<JavaFileObject> newSourceFiles =
        new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects());
    roots = cleanTrees(round.roots);

    JavaCompiler compiler = round.finalCompiler(errorStatus);

    if (newSourceFiles.size() > 0) roots = roots.appendList(compiler.parseFiles(newSourceFiles));

    errorStatus = errorStatus || (compiler.errorCount() > 0);

    // Free resources
    this.close();

    if (taskListener != null)
      taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));

    if (errorStatus) {
      if (compiler.errorCount() == 0) compiler.log.nerrors++;
      return compiler;
    }

    if (procOnly && !foundTypeProcessors) {
      compiler.todo.clear();
    } else {
      if (procOnly && foundTypeProcessors) compiler.shouldStopPolicy = CompileState.FLOW;

      compiler.enterTrees(roots);
    }

    return compiler;
  }