Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions tsc/internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,7 @@ func (b *Binder) getStrictModeIdentifierMessage(node *ast.Node) *diagnostics.Mes
}

// Should be called only on prologue directives (ast.IsPrologueDirective(node) should be true)
func isUseStrictPrologueDirective(sourceFile *ast.SourceFile, node *ast.Node) bool {
func IsUseStrictPrologueDirective(sourceFile *ast.SourceFile, node *ast.Node) bool {
nodeText := scanner.GetSourceTextOfNodeFromSourceFile(sourceFile, node.Expression(), false /*includeTrivia*/)
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
// string to contain unicode escapes (as per ES5).
Expand All @@ -1352,7 +1352,7 @@ func isUseStrictPrologueDirective(sourceFile *ast.SourceFile, node *ast.Node) bo
func FindUseStrictPrologue(sourceFile *ast.SourceFile, statements []*ast.Node) *ast.Node {
for _, statement := range statements {
if ast.IsPrologueDirective(statement) {
if isUseStrictPrologueDirective(sourceFile, statement) {
if IsUseStrictPrologueDirective(sourceFile, statement) {
return statement
}
} else {
Expand Down
28 changes: 28 additions & 0 deletions tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -7419,9 +7419,37 @@ func (c *Checker) checkUnusedRenamedBindingElements() {
func (c *Checker) checkExpressionStatement(node *ast.Node) {
// Grammar checking
c.checkGrammarStatementInAmbientContext(node)
c.checkGrammarUseStrictDirective(node)
c.checkExpression(node.Expression())
}

func (c *Checker) checkGrammarUseStrictDirective(node *ast.Node) {
if !ast.IsPrologueDirective(node) || !binder.IsUseStrictPrologueDirective(ast.GetSourceFileOfNode(node), node) {
return
}

function := ast.GetContainingFunction(node)
if function == nil {
return
}
Comment on lines +7431 to +7434
body := function.Body()
if body == nil || !ast.IsBlock(body) || node.Parent != body {
c.grammarErrorOnNode(node, diagnostics.A_use_strict_directive_must_be_at_the_top_of_a_function_body)
return
}

for _, statement := range body.Statements() {
if statement == node {
return
}
// Type-only declarations are absent from the emitted JavaScript and do not end its directive prologue.
if !ast.IsPrologueDirective(statement) && statement.Kind != ast.KindInterfaceDeclaration && statement.Kind != ast.KindTypeAliasDeclaration {
c.grammarErrorOnNode(node, diagnostics.A_use_strict_directive_must_be_at_the_top_of_a_function_body)
return
}
}
}

// Returns the type of an expression. Unlike checkExpression, this function is simply concerned
// with computing the type and may not fully check all contained sub-expressions for errors.
func (c *Checker) getTypeOfExpression(node *ast.Node) *Type {
Expand Down
4 changes: 4 additions & 0 deletions tsc/internal/diagnostics/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -8555,5 +8555,9 @@
"'{0}' is not a valid meta-property for keyword 'import'. Did you mean 'meta' or 'defer'?": {
"category": "Error",
"code": 18061
},
"A 'use strict' directive must be at the top of a function body.": {
"category": "Error",
"code": 18064
}
}
4 changes: 4 additions & 0 deletions tsc/internal/diagnostics/diagnostics_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
strictModeInConstructor.ts(20,9): error TS18064: A 'use strict' directive must be at the top of a function body.
strictModeInConstructor.ts(27,5): error TS2376: A 'super' call must be the first statement in the constructor to refer to 'super' or 'this' when a derived class contains initialized properties, parameter properties, or private identifiers.
strictModeInConstructor.ts(29,17): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
strictModeInConstructor.ts(31,9): error TS18064: A 'use strict' directive must be at the top of a function body.
strictModeInConstructor.ts(49,9): error TS18064: A 'use strict' directive must be at the top of a function body.
strictModeInConstructor.ts(59,9): error TS18064: A 'use strict' directive must be at the top of a function body.


==== strictModeInConstructor.ts (2 errors) ====
==== strictModeInConstructor.ts (6 errors) ====
class A {
}

Expand All @@ -23,6 +27,8 @@ strictModeInConstructor.ts(29,17): error TS17009: 'super' must be called before
constructor () {
super(); // No error
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}
}

Expand All @@ -38,6 +44,8 @@ strictModeInConstructor.ts(29,17): error TS17009: 'super' must be called before
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
super();
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}
}

Expand All @@ -56,6 +64,8 @@ strictModeInConstructor.ts(29,17): error TS17009: 'super' must be called before
constructor () {
super(); // No error
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}
}

Expand All @@ -66,5 +76,7 @@ strictModeInConstructor.ts(29,17): error TS17009: 'super' must be called before
var x = 1; // no Error
super();
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
useStrictNotInPrologue.ts(3,5): error TS18064: A 'use strict' directive must be at the top of a function body.
useStrictNotInPrologue.ts(9,5): error TS18064: A 'use strict' directive must be at the top of a function body.
useStrictNotInPrologue.ts(20,5): error TS18064: A 'use strict' directive must be at the top of a function body.
useStrictNotInPrologue.ts(25,5): error TS18064: A 'use strict' directive must be at the top of a function body.
useStrictNotInPrologue.ts(31,9): error TS18064: A 'use strict' directive must be at the top of a function body.
useStrictNotInPrologue.ts(37,9): error TS18064: A 'use strict' directive must be at the top of a function body.


==== useStrictNotInPrologue.ts (6 errors) ====
function afterStatement() {
console.log("not strict");
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}

function afterDirectiveAndStatement() {
"use client";
console.log("not strict");
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}

function validDirective() {
"use client";
"use strict";
console.log("strict");
}

const arrow = () => {
console.log("not strict");
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
};

function* generator() {
yield;
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}

class C {
method() {
console.log("not strict");
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}
}

function nestedBlock() {
if (true) {
"use strict";
~~~~~~~~~~~~~
!!! error TS18064: A 'use strict' directive must be at the top of a function body.
}
}

function afterTypeOnlyStatement() {
interface I {}
"use strict";
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//// [tests/cases/compiler/useStrictNotInPrologue.ts] ////

//// [useStrictNotInPrologue.ts]
function afterStatement() {
console.log("not strict");
"use strict";
}

function afterDirectiveAndStatement() {
"use client";
console.log("not strict");
"use strict";
}

function validDirective() {
"use client";
"use strict";
console.log("strict");
}

const arrow = () => {
console.log("not strict");
"use strict";
};

function* generator() {
yield;
"use strict";
}

class C {
method() {
console.log("not strict");
"use strict";
}
}

function nestedBlock() {
if (true) {
"use strict";
}
}

function afterTypeOnlyStatement() {
interface I {}
"use strict";
}


//// [useStrictNotInPrologue.js]
"use strict";
function afterStatement() {
console.log("not strict");
"use strict";
}
function afterDirectiveAndStatement() {
"use client";
console.log("not strict");
"use strict";
}
function validDirective() {
"use client";
"use strict";
console.log("strict");
}
const arrow = () => {
console.log("not strict");
"use strict";
};
function* generator() {
yield;
"use strict";
}
class C {
method() {
console.log("not strict");
"use strict";
}
}
function nestedBlock() {
if (true) {
"use strict";
}
}
function afterTypeOnlyStatement() {
"use strict";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//// [tests/cases/compiler/useStrictNotInPrologue.ts] ////

=== useStrictNotInPrologue.ts ===
function afterStatement() {
>afterStatement : Symbol(afterStatement, Decl(useStrictNotInPrologue.ts, 0, 0))

console.log("not strict");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))

"use strict";
}

function afterDirectiveAndStatement() {
>afterDirectiveAndStatement : Symbol(afterDirectiveAndStatement, Decl(useStrictNotInPrologue.ts, 3, 1))

"use client";
console.log("not strict");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))

"use strict";
}

function validDirective() {
>validDirective : Symbol(validDirective, Decl(useStrictNotInPrologue.ts, 9, 1))

"use client";
"use strict";
console.log("strict");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
}

const arrow = () => {
>arrow : Symbol(arrow, Decl(useStrictNotInPrologue.ts, 17, 5))

console.log("not strict");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))

"use strict";
};

function* generator() {
>generator : Symbol(generator, Decl(useStrictNotInPrologue.ts, 20, 2))

yield;
"use strict";
}

class C {
>C : Symbol(C, Decl(useStrictNotInPrologue.ts, 25, 1))

method() {
>method : Symbol(C.method, Decl(useStrictNotInPrologue.ts, 27, 9))

console.log("not strict");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))

"use strict";
}
}

function nestedBlock() {
>nestedBlock : Symbol(nestedBlock, Decl(useStrictNotInPrologue.ts, 32, 1))

if (true) {
"use strict";
}
}

function afterTypeOnlyStatement() {
>afterTypeOnlyStatement : Symbol(afterTypeOnlyStatement, Decl(useStrictNotInPrologue.ts, 38, 1))

interface I {}
>I : Symbol(I, Decl(useStrictNotInPrologue.ts, 40, 35))

"use strict";
}

Loading