com.google.javascript.jscomp.RhinoErrorReporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of closure-compiler-unshaded Show documentation
Show all versions of closure-compiler-unshaded Show documentation
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.
/*
* 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.Msg;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.jspecify.nullness.Nullable;
/**
* An error reporter for serializing Rhino errors into our error format.
*/
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}");
static final DiagnosticType UNRECOGNIZED_TYPEOF_ERROR =
DiagnosticType.warning("JSC_UNRECOGNIZED_TYPEOF_ERROR", "{0}");
static final DiagnosticType CYCLIC_INHERITANCE_ERROR =
DiagnosticType.warning("JSC_CYCLIC_INHERITANCE_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}");
// Import is supported by VSCode and is pretty much a standard now.
static final DiagnosticType JSDOC_IMPORT_TYPE_WARNING =
DiagnosticType.disabled("JSC_JSDOC_IMPORT_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 DUPLICATE_VISIBILITY =
DiagnosticType.warning("JSC_DUPLICATE_VISIBILITY", "{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 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("JSC_PARSE_TREE_TOO_DEEP", "Parse tree too deep.");
static final DiagnosticType INVALID_OCTAL_LITERAL =
DiagnosticType.warning(
"JSC_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 UNSUPPORTED_LANGUAGE_FEATURE =
DiagnosticType.error("JSC_UNSUPPORTED_LANGUAGE_FEATURE", "{0}.");
static final DiagnosticType UNSUPPORTED_BOUNDED_GENERIC_TYPES =
DiagnosticType.error(
"JSC_UNSUPPORTED_BOUNDED_GENERIC_TYPES",
"Bounded generic semantics are currently still in development");
static final DiagnosticType BOUNDED_GENERIC_TYPE_ERROR =
DiagnosticType.error(
"JSC_BOUNDED_GENERIC_TYPE_ERROR",
"Bounded generic type error. "
+ "{0} assigned to template type {1} is not a subtype of bound {2}");
// A map of Rhino messages to their DiagnosticType.
private static final ImmutableMap 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)
// Duplicate visiblity
.put(replacePlaceHolders(Msg.JSDOC_EXTRA_VISIBILITY.format()), DUPLICATE_VISIBILITY)
.put(Pattern.compile("Unnecessary escape:.*"), UNNECESSARY_ESCAPE)
.put(Pattern.compile("^invalid param name.*"), INVALID_PARAM)
// Unknown @annotations.
.put(replacePlaceHolders(Msg.BAD_JSDOC_TAG.format()), BAD_JSDOC_ANNOTATION)
.put(
Pattern.compile(
"^Keywords and reserved words are not allowed as unquoted property.*"),
INVALID_ES3_PROP_NAME)
.put(Pattern.compile("^Too many template parameters\n.*"), 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)
.put(Pattern.compile(".*Unknown type.*\n.*"), UNRECOGNIZED_TYPE_ERROR)
// Unrecognized `typeof some.prop` errors
.put(Pattern.compile("^Missing type for `typeof` value.*"), UNRECOGNIZED_TYPEOF_ERROR)
// Cyclic inheritance errors
.put(
Pattern.compile("^Cycle detected in inheritance chain of type .*"),
CYCLIC_INHERITANCE_ERROR)
// Import annotation errors.
.put(
Pattern.compile("^Bad type annotation. Import in typedef.*"),
JSDOC_IMPORT_TYPE_WARNING)
// 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(
"^This language feature is not currently supported by the compiler:" + " .*"),
UNSUPPORTED_LANGUAGE_FEATURE)
.put(
Pattern.compile("Bounded generic semantics are currently still in development"),
UNSUPPORTED_BOUNDED_GENERIC_TYPES)
.put(Pattern.compile("^Bounded generic type error.*"), BOUNDED_GENERIC_TYPE_ERROR)
.buildOrThrow();
private final ErrorHandler internalReporter;
/**
* 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(ErrorHandler internalReporter) {
this.internalReporter = internalReporter;
}
public static ErrorReporter forOldRhino(ErrorHandler internalReporter) {
return new OldRhinoErrorReporter(internalReporter);
}
void warningAtLine(String message, String sourceName, int line,
int lineOffset) {
internalReporter.report(
null, makeError(message, sourceName, line, lineOffset, CheckLevel.WARNING));
}
void errorAtLine(String message, String sourceName, int line,
int lineOffset) {
internalReporter.report(
null, makeError(message, sourceName, line, lineOffset, CheckLevel.ERROR));
}
protected static @Nullable DiagnosticType mapError(String message) {
for (Entry entry : typeMap.entrySet()) {
if (entry.getKey().matcher(message).matches()) {
return entry.getValue();
}
}
return null;
}
private static 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);
JSError.Builder builder =
JSError.builder(type != null ? type : PARSE_ERROR, message)
.setSourceLocation(sourceName, line, lineOffset);
// If a specific DiagnosticType is present, its default level overrides the defaultLevel
// passed to this method.
if (type == null) {
builder.setLevel(defaultLevel);
}
return builder.build();
}
private static class OldRhinoErrorReporter extends RhinoErrorReporter
implements ErrorReporter {
private OldRhinoErrorReporter(ErrorHandler internalReporter) {
super(internalReporter);
}
@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);
}
}
}