mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 17:55:50 +00:00
Bug 930414 - Check for duplicate module exports r=shu
This commit is contained in:
parent
071566ef1a
commit
725f28c7b5
@ -1172,6 +1172,7 @@ ObjectBox::trace(JSTracer* trc)
|
||||
} else if (box->isModuleBox()) {
|
||||
ModuleBox* modulebox = box->asModuleBox();
|
||||
modulebox->bindings.trace(trc);
|
||||
modulebox->exportNames.trace(trc);
|
||||
}
|
||||
box = box->traceLink;
|
||||
}
|
||||
|
@ -697,7 +697,8 @@ ModuleBox::ModuleBox(ExclusiveContext* cx, ObjectBox* traceListHead, ModuleObjec
|
||||
ParseContext<ParseHandler>* outerpc)
|
||||
: ObjectBox(module, traceListHead),
|
||||
SharedContext(cx, Directives(true), false),
|
||||
bindings()
|
||||
bindings(),
|
||||
exportNames(cx)
|
||||
{}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@ -4553,7 +4554,7 @@ Parser<ParseHandler>::importDeclaration()
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT);
|
||||
|
||||
if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) {
|
||||
if (!pc->atModuleLevel()) {
|
||||
report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
|
||||
return null();
|
||||
}
|
||||
@ -4649,13 +4650,39 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
ClassContext classContext,
|
||||
DefaultHandling defaultHandling);
|
||||
|
||||
|
||||
template<>
|
||||
bool
|
||||
Parser<FullParseHandler>::addExportName(JSAtom* exportName)
|
||||
{
|
||||
TraceableVector<JSAtom*>& exportNames = pc->sc->asModuleBox()->exportNames;
|
||||
for (JSAtom* name : exportNames) {
|
||||
if (name == exportName) {
|
||||
JSAutoByteString str;
|
||||
if (AtomToPrintableString(context, exportName, &str))
|
||||
report(ParseError, false, null(), JSMSG_DUPLICATE_EXPORT_NAME, str.ptr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return exportNames.append(exportName);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::addExportName(JSAtom* exportName)
|
||||
{
|
||||
JS_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return SyntaxParseHandler::NodeFailure;
|
||||
}
|
||||
|
||||
template<>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::exportDeclaration()
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT);
|
||||
|
||||
if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) {
|
||||
if (!pc->atModuleLevel()) {
|
||||
report(ParseError, false, null(), JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
|
||||
return null();
|
||||
}
|
||||
@ -4705,6 +4732,9 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
if (!exportName)
|
||||
return null();
|
||||
|
||||
if (!addExportName(exportName->pn_atom))
|
||||
return null();
|
||||
|
||||
Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
|
||||
if (!exportSpec)
|
||||
return null();
|
||||
@ -4756,13 +4786,22 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
kid = functionStmt(YieldIsKeyword, NameRequired);
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
if (!addExportName(kid->pn_funbox->function()->atom()))
|
||||
return null();
|
||||
break;
|
||||
|
||||
case TOK_CLASS:
|
||||
case TOK_CLASS: {
|
||||
kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired);
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
const ClassNode& cls = kid->as<ClassNode>();
|
||||
MOZ_ASSERT(cls.names());
|
||||
if (!addExportName(cls.names()->innerBinding()->pn_atom))
|
||||
return null();
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_VAR:
|
||||
kid = variables(YieldIsName, PNK_VAR, NotInForInit);
|
||||
@ -4773,6 +4812,15 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
kid = MatchOrInsertSemicolon(tokenStream) ? kid : nullptr;
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
MOZ_ASSERT(kid->isArity(PN_LIST));
|
||||
for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
|
||||
if (var->isKind(PNK_ASSIGN))
|
||||
var = var->pn_left;
|
||||
MOZ_ASSERT(var->isKind(PNK_NAME));
|
||||
if (!addExportName(var->pn_atom))
|
||||
return null();
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_DEFAULT: {
|
||||
@ -4798,6 +4846,9 @@ Parser<FullParseHandler>::exportDeclaration()
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
if (!addExportName(context->names().default_))
|
||||
return null();
|
||||
|
||||
return handler.newExportDefaultDeclaration(kid, TokenPos(begin, pos().end));
|
||||
}
|
||||
|
||||
|
@ -739,6 +739,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
TokenKind tt, unsigned msg);
|
||||
|
||||
bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet);
|
||||
bool addExportName(JSAtom* exportName);
|
||||
|
||||
enum ClassContext { ClassStatement, ClassExpression };
|
||||
Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling);
|
||||
|
@ -381,6 +381,7 @@ class ModuleBox : public ObjectBox, public SharedContext
|
||||
{
|
||||
public:
|
||||
Bindings bindings;
|
||||
TraceableVector<JSAtom*> exportNames;
|
||||
|
||||
template <typename ParseHandler>
|
||||
ModuleBox(ExclusiveContext* cx, ObjectBox* traceListHead, ModuleObject* module,
|
||||
|
20
js/src/jit-test/tests/modules/duplicate-exports.js
Normal file
20
js/src/jit-test/tests/modules/duplicate-exports.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Test errors due to duplicate exports
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
function testSyntaxError(source) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
parseModule(source);
|
||||
}, SyntaxError);
|
||||
}
|
||||
|
||||
testSyntaxError("export var v; export var v;");
|
||||
testSyntaxError("export var x, y, z; export var y;");
|
||||
testSyntaxError("export default 1; export default 2;");
|
||||
testSyntaxError("export var default; export default 1;");
|
||||
testSyntaxError("export var default; export default function() {};");
|
||||
testSyntaxError("export var default; export default function foo() {};");
|
||||
testSyntaxError("export var default; export default export class { constructor() {} };");
|
||||
testSyntaxError("export var default; export default export class foo { constructor() {} };");
|
||||
testSyntaxError("var v; export {v}; export {v};");
|
||||
testSyntaxError("var v, x; export {v}; export {x as v};");
|
@ -244,6 +244,7 @@ MSG_DEF(JSMSG_DEPRECATED_LET_BLOCK, 0, JSEXN_NONE, "JavaScript 1.7's let bl
|
||||
MSG_DEF(JSMSG_DEPRECATED_FOR_EACH, 0, JSEXN_NONE, "JavaScript 1.6's for-each-in loops are deprecated; consider using ES6 for-of instead")
|
||||
MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
|
||||
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
|
||||
MSG_DEF(JSMSG_DUPLICATE_EXPORT_NAME, 1, JSEXN_SYNTAXERR, "duplicate export name '{0}'")
|
||||
MSG_DEF(JSMSG_DUPLICATE_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
|
||||
MSG_DEF(JSMSG_DUPLICATE_LABEL, 0, JSEXN_SYNTAXERR, "duplicate label")
|
||||
MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
|
||||
|
@ -29,11 +29,11 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 305;
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 306;
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||
|
||||
static_assert(JSErr_Limit == 406,
|
||||
static_assert(JSErr_Limit == 407,
|
||||
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
|
||||
"removed MSG_DEFs from js.msg, you should increment "
|
||||
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
|
||||
|
Loading…
Reference in New Issue
Block a user