All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.SanityCheck Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs. This binary checks for style issues such as incorrect or missing JSDoc usage, and missing goog.require() statements. It does not do more advanced checks such as typechecking.

There is a newer version: v20200830
Show newest version
/*
 * Copyright 2009 The Closure Compiler Authors.
 *
 * 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.javascript.jscomp;

import com.google.javascript.rhino.Node;

import java.util.Set;

/**
 * A compiler pass that verifies the structure of the AST conforms
 * to a number of invariants. Because this can add a lot of overhead,
 * we only run this in development mode.
 *
 * @author [email protected] (Nick Santos)
 */
class SanityCheck implements CompilerPass {

  static final DiagnosticType CANNOT_PARSE_GENERATED_CODE =
      DiagnosticType.error("JSC_CANNOT_PARSE_GENERATED_CODE",
          "Internal compiler error. Cannot parse generated code: {0}");

  static final DiagnosticType GENERATED_BAD_CODE = DiagnosticType.error(
      "JSC_GENERATED_BAD_CODE",
      "Internal compiler error. Generated bad code." +
      "----------------------------------------\n" +
      "Expected:\n{0}\n" +
      "----------------------------------------\n" +
      "Actual:\n{1}");

  static final DiagnosticType EXTERN_PROPERTIES_CHANGED =
      DiagnosticType.error("JSC_EXTERN_PROPERTIES_CHANGED",
          "Internal compiler error. Extern properties modified.");

  private final AbstractCompiler compiler;
  private final AstValidator astValidator;

  SanityCheck(AbstractCompiler compiler) {
    this.compiler = compiler;
    this.astValidator = new AstValidator(compiler);
  }

  @Override
  public void process(Node externs, Node root) {
    sanityCheckAst(externs, root);
    sanityCheckNormalization(externs, root);
    sanityCheckCodeGeneration(root);
    sanityCheckVars(externs, root);
    sanityCheckExternProperties(externs);
  }

  /**
   * Sanity check the AST is structurally accurate.
   */
  private void sanityCheckAst(Node externs, Node root) {
    astValidator.validateCodeRoot(externs);
    astValidator.validateCodeRoot(root);
  }

  private void sanityCheckVars(Node externs, Node root) {
    if (compiler.getLifeCycleStage().isNormalized()) {
      (new VarCheck(compiler, true)).process(externs, root);
    }
  }

  /**
   * Sanity checks code generation by performing it once, parsing the result,
   * then generating code from the second parse tree to verify that it matches
   * the code generated from the first parse tree.
   *
   * @return The regenerated parse tree. Null on error.
   */
  private Node sanityCheckCodeGeneration(Node root) {
    if (compiler.hasHaltingErrors()) {
      // Don't even bother checking code generation if we already know the
      // the code is bad.
      return null;
    }

    String source = compiler.toSource(root);
    Node root2 = compiler.parseSyntheticCode(source);
    if (compiler.hasHaltingErrors()) {
      compiler.report(JSError.make(CANNOT_PARSE_GENERATED_CODE,
              Strings.truncateAtMaxLength(source, 100, true)));

      // Throw an exception, so that the infrastructure will tell us
      // which pass violated the sanity check.
      throw new IllegalStateException("Sanity Check failed");
    }

    String source2 = compiler.toSource(root2);
    if (!source.equals(source2)) {
      compiler.report(JSError.make(GENERATED_BAD_CODE, source, source2));

      // Throw an exception, so that the infrastructure will tell us
      // which pass violated the sanity check.
      throw new IllegalStateException("Sanity Check failed");
    }

    return root2;
  }

  /**
   * Sanity checks the AST. This is by verifying the normalization passes do
   * nothing.
   */
  private void sanityCheckNormalization(Node externs, Node root) {
    // Verify nothing has inappropriately denormalize the AST.
    CodeChangeHandler handler = new ForbiddenChange();
    compiler.addChangeHandler(handler);

    // TODO(johnlenz): Change these normalization checks Preconditions and
    // Exceptions into Errors so that it is easier to find the root cause
    // when there are cascading issues.
    new PrepareAst(compiler, true).process(null, root);
    if (compiler.getLifeCycleStage().isNormalized()) {
      (new Normalize(compiler, true)).process(externs, root);

      if (compiler.getLifeCycleStage().isNormalizedUnobfuscated()) {
        boolean checkUserDeclarations = true;
        CompilerPass pass = new Normalize.VerifyConstants(
            compiler, checkUserDeclarations);
        pass.process(externs, root);
      }
    }

    compiler.removeChangeHandler(handler);
  }

  private void sanityCheckExternProperties(Node externs) {
    Set externProperties = compiler.getExternProperties();
    if (externProperties == null) {
      // GatherExternProperties hasn't run yet. Don't report a violation.
      return;
    }
    (new GatherExternProperties(compiler)).process(externs, null);
    if (!compiler.getExternProperties().equals(externProperties)) {
      compiler.report(JSError.make(EXTERN_PROPERTIES_CHANGED));
      // Throw an exception, so that the infrastructure will tell us
      // which pass violated the sanity check.
      throw new IllegalStateException("Sanity Check failed");
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy