summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/src/frontend/Parser.cpp44
-rw-r--r--js/src/frontend/Parser.h2
-rw-r--r--js/src/jit-test/tests/parser/missing-closing-brace.js30
-rw-r--r--js/src/js.msg1
4 files changed, 71 insertions, 6 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 01ab3f64c..9aed88ce9 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1014,6 +1014,35 @@ Parser<ParseHandler>::hasValidSimpleStrictParameterNames()
template <typename ParseHandler>
void
+Parser<ParseHandler>::reportMissingClosing(unsigned errorNumber, unsigned noteNumber,
+ uint32_t openedPos)
+{
+ auto notes = MakeUnique<JSErrorNotes>();
+ if (!notes)
+ return;
+
+ uint32_t line, column;
+ tokenStream.srcCoords.lineNumAndColumnIndex(openedPos, &line, &column);
+
+ const size_t MaxWidth = sizeof("4294967295");
+ char columnNumber[MaxWidth];
+ SprintfLiteral(columnNumber, "%" PRIu32, column);
+ char lineNumber[MaxWidth];
+ SprintfLiteral(lineNumber, "%" PRIu32, line);
+
+ if (!notes->addNoteASCII(pc->sc()->context,
+ getFilename(), line, column,
+ GetErrorMessage, nullptr,
+ noteNumber, lineNumber, columnNumber))
+ {
+ return;
+ }
+
+ errorWithNotes(Move(notes), errorNumber);
+}
+
+template <typename ParseHandler>
+void
Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind,
TokenPos pos, uint32_t prevPos)
{
@@ -1039,11 +1068,11 @@ Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKi
char lineNumber[MaxWidth];
SprintfLiteral(lineNumber, "%" PRIu32, line);
- if (!notes->addNoteLatin1(pc->sc()->context,
- getFilename(), line, column,
- GetErrorMessage, nullptr,
- JSMSG_REDECLARED_PREV,
- lineNumber, columnNumber))
+ if (!notes->addNoteASCII(pc->sc()->context,
+ getFilename(), line, column,
+ GetErrorMessage, nullptr,
+ JSMSG_REDECLARED_PREV,
+ lineNumber, columnNumber))
{
return;
}
@@ -3613,6 +3642,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return false;
+ uint32_t openedPos = 0;
if (tt != TOK_LC) {
if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
@@ -3634,6 +3664,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
tokenStream.ungetToken();
bodyType = ExpressionBody;
funbox->setIsExprBody();
+ } else {
+ openedPos = pos().begin;
}
// Arrow function parameters inherit yieldHandling from the enclosing
@@ -3675,7 +3707,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand))
return false;
if (!matched) {
- error(JSMSG_CURLY_AFTER_BODY);
+ reportMissingClosing(JSMSG_CURLY_AFTER_BODY, JSMSG_CURLY_OPENED, openedPos);
return false;
}
funbox->setEnd(pos().end);
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 7866bc4fd..b1d3bdee0 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1459,6 +1459,8 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool hasValidSimpleStrictParameterNames();
+ void reportMissingClosing(unsigned errorNumber, unsigned noteNumber, uint32_t openedPos);
+
void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos,
uint32_t prevPos);
bool notePositionalFormalParameter(Node fn, HandlePropertyName name, uint32_t beginPos,
diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js
new file mode 100644
index 000000000..4512ad133
--- /dev/null
+++ b/js/src/jit-test/tests/parser/missing-closing-brace.js
@@ -0,0 +1,30 @@
+function test(source, [lineNumber, columnNumber]) {
+ let caught = false;
+ try {
+ Reflect.parse(source, { source: "foo.js" });
+ } catch (e) {
+ assertEq(e.message.includes("missing } "), true);
+ let notes = getErrorNotes(e);
+ assertEq(notes.length, 1);
+ let note = notes[0];
+ assertEq(note.message, "{ opened at line " + lineNumber + ", column " + columnNumber);
+ assertEq(note.fileName, "foo.js");
+ assertEq(note.lineNumber, lineNumber);
+ assertEq(note.columnNumber, columnNumber);
+ caught = true;
+ }
+ assertEq(caught, true);
+}
+
+// Function
+
+test(`
+function test1() {
+}
+function test2() {
+ if (true) {
+ //}
+}
+function test3() {
+}
+`, [4, 17]);
diff --git a/js/src/js.msg b/js/src/js.msg
index 569928be8..a51d99933 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -228,6 +228,7 @@ MSG_DEF(JSMSG_COLON_IN_COND, 0, JSEXN_SYNTAXERR, "missing : in conditi
MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing ] in computed property name")
MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE, 1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position")
MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body")
+MSG_DEF(JSMSG_CURLY_OPENED, 2, JSEXN_NOTE, "{ opened at line {0}, column {1}")
MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing } after catch block")
MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 0, JSEXN_SYNTAXERR, "missing } after finally block")
MSG_DEF(JSMSG_CURLY_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list")