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

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

/*
 * 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.common.collect.ImmutableMap;
import com.google.javascript.rhino.ErrorReporter;
import com.google.javascript.rhino.SimpleErrorReporter;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

/**
 * An error reporter for serializing Rhino errors into our error format.
 * @author [email protected] (Nick Santos)
 */
class RhinoErrorReporter {

  static final DiagnosticType PARSE_ERROR =
      DiagnosticType.error("JSC_PARSE_ERROR", "Parse error. {0}");

  static final DiagnosticType TYPE_PARSE_ERROR =
      DiagnosticType.warning("JSC_TYPE_PARSE_ERROR", "{0}");

  static final DiagnosticType UNRECOGNIZED_TYPE_ERROR =
      DiagnosticType.warning("JSC_UNRECOGNIZED_TYPE_ERROR", "{0}");

  // This is separate from TYPE_PARSE_ERROR because there are many instances of this warning
  // and it is unfeasible to fix them all right away.
  static final DiagnosticType JSDOC_MISSING_BRACES_WARNING =
      DiagnosticType.disabled("JSC_JSDOC_MISSING_BRACES_WARNING", "{0}");

  // This is separate from TYPE_PARSE_ERROR because there are many instances of this warning
  // and it is unfeasible to fix them all right away.
  static final DiagnosticType JSDOC_MISSING_TYPE_WARNING =
      DiagnosticType.disabled("JSC_JSDOC_MISSING_TYPE_WARNING", "{0}");

  static final DiagnosticType TOO_MANY_TEMPLATE_PARAMS =
      DiagnosticType.disabled("JSC_TOO_MANY_TEMPLATE_PARAMS", "{0}");

  // Special-cased errors, so that they can be configured via the
  // warnings API.
  static final DiagnosticType TRAILING_COMMA =
      DiagnosticType.error("JSC_TRAILING_COMMA",
          "Parse error. IE8 (and below) will parse trailing commas in " +
          "array and object literals incorrectly. " +
          "If you are targeting newer versions of JS, " +
          "set the appropriate language_in option.");

  static final DiagnosticType DUPLICATE_PARAM =
      DiagnosticType.error("JSC_DUPLICATE_PARAM", "Parse error. {0}");

  static final DiagnosticType UNNECESSARY_ESCAPE =
      DiagnosticType.disabled("JSC_UNNECESSARY_ESCAPE", "Parse error. {0}");

  static final DiagnosticType INVALID_PARAM =
      DiagnosticType.warning("JSC_INVALID_PARAM", "Parse error. {0}");

  static final DiagnosticType BAD_JSDOC_ANNOTATION =
      DiagnosticType.warning("JSC_BAD_JSDOC_ANNOTATION", "Parse error. {0}");

  static final DiagnosticType JSDOC_IN_BLOCK_COMMENT =
      DiagnosticType.warning("JSC_JSDOC_IN_BLOCK_COMMENT", "Parse error. {0}");

  static final DiagnosticType INVALID_ES3_PROP_NAME = DiagnosticType.warning(
      "JSC_INVALID_ES3_PROP_NAME",
      "Keywords and reserved words are not allowed as unquoted property " +
      "names in older versions of JavaScript. " +
      "If you are targeting newer versions of JavaScript, " +
      "set the appropriate language_in option.");

  static final DiagnosticType PARSE_TREE_TOO_DEEP =
      DiagnosticType.error("PARSE_TREE_TOO_DEEP",
          "Parse tree too deep.");

  static final DiagnosticType INVALID_OCTAL_LITERAL =
      DiagnosticType.warning("INVALID_OCTAL_LITERAL",
          "This style of octal literal is not supported in strict mode.");

  static final DiagnosticType STRING_CONTINUATION =
      DiagnosticType.warning("JSC_STRING_CONTINUATION", "{0}");

  static final DiagnosticType LANGUAGE_FEATURE =
      DiagnosticType.error("JSC_LANGUAGE_FEATURE", "{0}.");

  static final DiagnosticType ES6_TYPED =
      DiagnosticType.error("ES6_TYPED",
          "{0}. Use --language_in=ECMASCRIPT6_TYPED to enable ES6 typed features.");

  static final DiagnosticType MISPLACED_TYPE_SYNTAX =
      DiagnosticType.error("MISPLACED_TYPE_SYNTAX",
          "Can only have JSDoc or inline type annotations, not both");

  // A map of Rhino messages to their DiagnosticType.
  private final Map typeMap;

  final AbstractCompiler compiler;

  /**
   * For each message such as "Not a good use of {0}", replace the place
   * holder {0} with a wild card that matches all possible strings.
   * Also put the any non-place-holder in quotes for regex matching later.
   */
  private static Pattern replacePlaceHolders(String s) {
    s = Pattern.quote(s);
    return Pattern.compile(s.replaceAll("\\{\\d+\\}", "\\\\E.*\\\\Q"));
  }

  private RhinoErrorReporter(AbstractCompiler compiler) {
    this.compiler = compiler;
    typeMap =
        ImmutableMap.builder()
            // Trailing comma
            .put(
                Pattern.compile("Trailing comma is not legal in an ECMA-262 object initializer"),
                TRAILING_COMMA)

            // Duplicate parameter
            .put(replacePlaceHolders("Duplicate parameter name \"{0}\""), DUPLICATE_PARAM)

            .put(Pattern.compile("Unnecessary escape:.*"), UNNECESSARY_ESCAPE)

            .put(Pattern.compile("^invalid param name.*"), INVALID_PARAM)

            // Unknown @annotations.
            .put(
                replacePlaceHolders(SimpleErrorReporter.getMessage0("msg.bad.jsdoc.tag")),
                BAD_JSDOC_ANNOTATION)

            .put(
                Pattern.compile("^" + Pattern.quote(
                    "Non-JSDoc comment has annotations. "
                        + "Did you mean to start it with '/**'?")),
                JSDOC_IN_BLOCK_COMMENT)

            .put(
                Pattern.compile(
                    "^Keywords and reserved words are not allowed as unquoted property.*"),
                INVALID_ES3_PROP_NAME)

            .put(Pattern.compile("^Too many template parameters"), TOO_MANY_TEMPLATE_PARAMS)

            // Type annotation warnings.
            .put(
                Pattern.compile(".*Type annotations should have curly braces.*"),
                JSDOC_MISSING_BRACES_WARNING)

            .put(Pattern.compile("Missing type declaration\\."), JSDOC_MISSING_TYPE_WARNING)

            // Unresolved types that aren't forward declared.
            .put(Pattern.compile(".*Unknown type.*"), UNRECOGNIZED_TYPE_ERROR)

            // Type annotation errors.
            .put(Pattern.compile("^Bad type annotation.*"), TYPE_PARSE_ERROR)

            // Parse tree too deep.
            .put(Pattern.compile("Too deep recursion while parsing"), PARSE_TREE_TOO_DEEP)

            // Old-style octal literals
            .put(Pattern.compile("^Octal .*literal.*"), INVALID_OCTAL_LITERAL)

            .put(Pattern.compile("^String continuations.*"), STRING_CONTINUATION)

            .put(
                Pattern.compile("^This language feature is only supported for .*"),
                LANGUAGE_FEATURE)

            .put(Pattern.compile("^type syntax is only supported in ES6 typed mode.*"), ES6_TYPED)

            .put(Pattern.compile("^Can only have JSDoc or inline type.*"), MISPLACED_TYPE_SYNTAX)

            .build();
  }

  public static ErrorReporter forOldRhino(AbstractCompiler compiler) {
    return new OldRhinoErrorReporter(compiler);
  }

  void warningAtLine(String message, String sourceName, int line,
      int lineOffset) {
    compiler.report(
        makeError(message, sourceName, line, lineOffset, CheckLevel.WARNING));
  }

  void errorAtLine(String message, String sourceName, int line,
      int lineOffset) {
    compiler.report(
        makeError(message, sourceName, line, lineOffset, CheckLevel.ERROR));
  }

  protected DiagnosticType mapError(String message) {
    for (Entry entry : typeMap.entrySet()) {
      if (entry.getKey().matcher(message).matches()) {
        return entry.getValue();
      }
    }
    return null;
  }

  private JSError makeError(String message, String sourceName, int line,
      int lineOffset, CheckLevel defaultLevel) {

    // Try to see if the message is one of the rhino errors we want to
    // expose as DiagnosticType by matching it with the regex key.
    DiagnosticType type = mapError(message);
    if (type != null) {
      return JSError.make(
          sourceName, line, lineOffset, type, message);
    }

    return JSError.make(sourceName, line, lineOffset, defaultLevel,
        PARSE_ERROR, message);
  }

  private static class OldRhinoErrorReporter extends RhinoErrorReporter
      implements ErrorReporter {

    private OldRhinoErrorReporter(AbstractCompiler compiler) {
      super(compiler);
    }

    @Override
    public void error(String message, String sourceName, int line,
        int lineOffset) {
      super.errorAtLine(message, sourceName, line, lineOffset);
    }

    @Override
    public void warning(String message, String sourceName, int line,
        int lineOffset) {
      super.warningAtLine(message, sourceName, line, lineOffset);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy