Package com.google.errorprone

Source Code of com.google.errorprone.ErrorProneAnalyzer$DeclFreeCompilationUnitWrapper

/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* 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.errorprone;

import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;

/**
* Used to run an error-prone analysis as a phase in the javac compiler.
*/
public class ErrorProneAnalyzer {

  private final Log log;
  private final Context context;
  private final Scanner errorProneScanner;
  // If matchListener != null, then we are in search mode.
  private final SearchResultsPrinter resultsPrinter;

  /** The set of trees that have already been scanned. */
  private final Set<JCTree> seen = new HashSet<>();

  public ErrorProneAnalyzer(Log log, Context context) {
    this(log, context, null);
  }

  public ErrorProneAnalyzer(Log log, Context context, SearchResultsPrinter resultsPrinter) {
    this.log = log;
    this.context = context;
    this.resultsPrinter = resultsPrinter;
    this.errorProneScanner = context.get(Scanner.class);
    if (this.errorProneScanner == null) {
      throw new IllegalStateException(
          "No error-prone scanner registered in context. Is annotation processing enabled?");
    }
  }

  private static class DeclFreeCompilationUnitWrapper extends JCCompilationUnit {
    protected DeclFreeCompilationUnitWrapper(JCCompilationUnit original) {
      super(
          original.packageAnnotations,
          original.pid,
          com.sun.tools.javac.util.List.<JCTree>nil(),
          original.sourcefile,
          original.packge,
          original.namedImportScope,
          original.starImportScope);
    }
  }

  /**
   * Reports that a class (represented by the env) is ready for error-prone to analyze.
   */
  public void reportReadyForAnalysis(Env<AttrContext> env, boolean hasErrors) {
    try {
      // Javac sometimes performs the flow phase on class decls twice. If javac is desugaring some
      // class whose superclass hasn't been desugared, the superclass gets desugared early.
      // When the compilation reaches the point where the superclass would originally have gone
      // through dataflow and desugaring it goes through them again. This is normally fine since
      // those phases are (hopefully?) both idempotent. However, error-prone assumes that (1) it
      // sees each class once, and (2) that they haven't been desugared yet.
      if (!seen.add(env.tree)) {
        return;
      }

      TreePath path;
      if (env.toplevel != env.tree) {
        // The current tree is a class decl, so construct a TreePath rooted at the enclosing
        // compilation unit.
        path = TreePath.getPath(env.toplevel, env.tree);
      } else {
        // The current tree is a compilation unit. Wrap the compilation unit to hide its class
        // decls, since (1) we've already visited them, and (2) the bodies of all but the last class
        // decl have been lowered out of them.
        path = new TreePath(new DeclFreeCompilationUnitWrapper(env.toplevel));
      }
      errorProneScanner.scan(path, createVisitorState(env));
    } catch (CompletionFailure e) {
      // A CompletionFailure can be triggered when error-prone tries to complete a symbol
      // that isn't on the compilation classpath. This can occur when a check performs an
      // instanceof test on a symbol, which requires inspecting the transitive closure of the
      // symbol's supertypes. If javac didn't need to check the symbol's assignability
      // then a normal compilation would have succeeded, and no diagnostics will have been
      // reported yet, but we don't want to crash javac.
      StringWriter message = new StringWriter();
      e.printStackTrace(new PrintWriter(message));
      log.error("proc.cant.access", e.sym, e.getDetailValue(), message.toString());
    } catch (RuntimeException e) {
      // If there is a RuntimeException in an analyzer, swallow it if there are other compiler
      // errors.  This prevents javac from exiting with code 4, Abnormal Termination.
      if (!hasErrors) {
        throw e;
      }
    }
  }

  /**
   * Create a VisitorState object from an environment.
   */
  private VisitorState createVisitorState(Env<AttrContext> env) {
    if (resultsPrinter != null) {
      resultsPrinter.setCompilationUnit(env.toplevel.sourcefile);
      return new VisitorState(context, resultsPrinter);
    } else {
      DescriptionListener logReporter = new JavacErrorDescriptionListener(log,
          env.toplevel.endPositions,
          env.enclClass.sym.sourcefile != null
          ? env.enclClass.sym.sourcefile
              : env.toplevel.sourcefile,
              context);
      return new VisitorState(context, logReporter);
    }
  }
}
TOP

Related Classes of com.google.errorprone.ErrorProneAnalyzer$DeclFreeCompilationUnitWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.