Fix crash on bad namespace parse (#37626)

* Fix crash on bad namespace parse

`global` inside a class body is parsed as a module declaration, and in
the following example has no body:

```ts
class C {
  global x
}
```

`x` is parsed as a separate ExpressionStatement. This caused a crash in
emit because the code didn't expect a module declaration with no body.

* inline node.body variable

* fix missed references to body
This commit is contained in:
Nathan Shively-Sanders 2020-04-01 15:05:49 -07:00 committed by GitHub
parent ed1863b3e6
commit 95a124f802
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 19 deletions

View File

@ -2693,27 +2693,28 @@ namespace ts {
const statements: Statement[] = [];
startLexicalEnvironment();
let statementsLocation: TextRange;
let statementsLocation: TextRange | undefined;
let blockLocation: TextRange | undefined;
const body = node.body!;
if (body.kind === SyntaxKind.ModuleBlock) {
saveStateAndInvoke(body, body => addRange(statements, visitNodes((<ModuleBlock>body).statements, namespaceElementVisitor, isStatement)));
statementsLocation = body.statements;
blockLocation = body;
}
else {
const result = visitModuleDeclaration(<ModuleDeclaration>body);
if (result) {
if (isArray(result)) {
addRange(statements, result);
}
else {
statements.push(result);
}
if (node.body) {
if (node.body.kind === SyntaxKind.ModuleBlock) {
saveStateAndInvoke(node.body, body => addRange(statements, visitNodes((<ModuleBlock>body).statements, namespaceElementVisitor, isStatement)));
statementsLocation = node.body.statements;
blockLocation = node.body;
}
else {
const result = visitModuleDeclaration(<ModuleDeclaration>node.body);
if (result) {
if (isArray(result)) {
addRange(statements, result);
}
else {
statements.push(result);
}
}
const moduleBlock = <ModuleBlock>getInnerMostModuleDeclarationFromDottedModule(node)!.body;
statementsLocation = moveRangePos(moduleBlock.statements, -1);
const moduleBlock = <ModuleBlock>getInnerMostModuleDeclarationFromDottedModule(node)!.body;
statementsLocation = moveRangePos(moduleBlock.statements, -1);
}
}
insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
@ -2750,7 +2751,7 @@ namespace ts {
// })(hi = hello.hi || (hello.hi = {}));
// })(hello || (hello = {}));
// We only want to emit comment on the namespace which contains block body itself, not the containing namespaces.
if (body.kind !== SyntaxKind.ModuleBlock) {
if (!node.body || node.body.kind !== SyntaxKind.ModuleBlock) {
setEmitFlags(block, getEmitFlags(block) | EmitFlags.NoComments);
}
return block;

View File

@ -0,0 +1,26 @@
tests/cases/compiler/nestedGlobalNamespaceInClass.ts(3,5): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected.
tests/cases/compiler/nestedGlobalNamespaceInClass.ts(3,5): error TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.
tests/cases/compiler/nestedGlobalNamespaceInClass.ts(3,5): error TS2670: Augmentations for the global scope should have 'declare' modifier unless they appear in already ambient context.
tests/cases/compiler/nestedGlobalNamespaceInClass.ts(3,12): error TS1005: ';' expected.
tests/cases/compiler/nestedGlobalNamespaceInClass.ts(3,12): error TS2304: Cannot find name 'x'.
tests/cases/compiler/nestedGlobalNamespaceInClass.ts(4,1): error TS1128: Declaration or statement expected.
==== tests/cases/compiler/nestedGlobalNamespaceInClass.ts (6 errors) ====
// should not crash - from #35717
class C {
global x
~~~~~~
!!! error TS1068: Unexpected token. A constructor, method, accessor, or property was expected.
~~~~~~
!!! error TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.
~~~~~~
!!! error TS2670: Augmentations for the global scope should have 'declare' modifier unless they appear in already ambient context.
~
!!! error TS1005: ';' expected.
~
!!! error TS2304: Cannot find name 'x'.
}
~
!!! error TS1128: Declaration or statement expected.

View File

@ -0,0 +1,18 @@
//// [nestedGlobalNamespaceInClass.ts]
// should not crash - from #35717
class C {
global x
}
//// [nestedGlobalNamespaceInClass.js]
// should not crash - from #35717
var C = /** @class */ (function () {
function C() {
}
return C;
}());
var global;
(function (global) {
})(global || (global = {}));
x;

View File

@ -0,0 +1,9 @@
=== tests/cases/compiler/nestedGlobalNamespaceInClass.ts ===
// should not crash - from #35717
class C {
>C : Symbol(C, Decl(nestedGlobalNamespaceInClass.ts, 0, 0))
global x
>global : Symbol(global, Decl(nestedGlobalNamespaceInClass.ts, 1, 9))
}

View File

@ -0,0 +1,10 @@
=== tests/cases/compiler/nestedGlobalNamespaceInClass.ts ===
// should not crash - from #35717
class C {
>C : C
global x
>global : any
>x : any
}

View File

@ -0,0 +1,4 @@
// should not crash - from #35717
class C {
global x
}