• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as ts from "typescript";
17import { CmdOptions } from "./cmdOptions";
18import {
19    DiagnosticCode,
20    DiagnosticError
21} from "./diagnostic";
22import { hasExportKeywordModifier } from "./base/util";
23import { findInnerExprOfParenthesis } from "./expression/parenthesizedExpression";
24import * as jshelpers from "./jshelpers";
25import { getContainingFunctionDeclaration, getSourceFileOfNode } from "./jshelpers";
26import { LOGE } from "./log";
27import { Recorder } from "./recorder";
28import {
29    CatchParameter,
30    ClassDecl,
31    ConstDecl,
32    Decl,
33    FuncDecl,
34    FunctionScope,
35    GlobalScope,
36    LetDecl,
37    LocalScope,
38    ModuleScope,
39    Scope,
40    VarDecl
41} from "./scope";
42import { isStrictMode } from "./strictMode";
43import { checkSyntaxErrorForStrictMode } from "./syntaxCheckerForStrcitMode";
44import {
45    allowLetAndConstDeclarations,
46    isAssignmentOperator,
47    isBindingPattern,
48    isDeclInGlobal,
49    isFunctionLikeDeclaration,
50    isGlobalIdentifier,
51    isOptionalParameter,
52    isStatement,
53    visibilityToString,
54    isInBlockScope
55} from "./syntaxCheckHelper";
56import { MandatoryArguments } from "./variable";
57
58//*************************************Part 1: Implement early check of declarations*******************************//
59export function checkDuplicateDeclaration(recorder: Recorder): void {
60    let scopeMap = recorder.getScopeMap();
61    scopeMap.forEach((scope, node) => {
62        // implement functionParameter-related duplicate-entry check
63        if (isFunctionLikeDeclaration(node)) {
64            if (isStrictMode(node)) {
65                checkDuplicateParameter(node, recorder);
66            }
67
68            if (node.body) {
69                let bodyScope = <Scope>scopeMap.get(node.body);
70                let parameterNames = getParameterNames(node, recorder);
71                if (bodyScope) {
72                    checkDuplicateParameterVar(parameterNames, bodyScope);
73                }
74            }
75        }
76
77        // implement catchParameter-related duplicate-entry check
78        if ((node.kind === ts.SyntaxKind.Block) && (node.parent != undefined && node.parent.kind === ts.SyntaxKind.CatchClause)) {
79            let catchScope = <Scope>scopeMap.get(node.parent);
80            checkDuplicateInCatch(scope, catchScope);
81        }
82
83        let decls = scope.getDecls();
84        let exportFuncMap: Map<string, boolean> = new Map<string, boolean>();
85        for (let i = 0; i < decls.length; i++) {
86            checkDeclareGlobalId(decls[i], scope);
87            checkDuplicateEntryInScope(scope, i);
88            checkDuplicateEntryAcrossScope(scope, i);
89            if (ts.isFunctionDeclaration(decls[i].node) && scope instanceof ModuleScope) {
90                hasDuplicateExportedFuncDecl(<FuncDecl>decls[i], exportFuncMap);
91            }
92        }
93    })
94}
95
96function checkDuplicateEntryAcrossScope(scope: Scope, index: number): void {
97    let decls = scope.getDecls();
98    let parentScope: Scope | undefined = scope;
99    if (decls[index] instanceof VarDecl) {
100        while (!(parentScope instanceof FunctionScope)) {
101            parentScope = parentScope.getParent();
102            if (!parentScope) {
103                return;
104            }
105
106            let parentDecls = parentScope.getDecls();
107            parentDecls.forEach(parentDecl => {
108                if (hasDuplicateEntryAcrossScope(decls[index], parentDecl)) {
109                    throwDupIdError(decls[index]);
110                }
111            });
112        }
113    }
114}
115
116function checkDuplicateEntryInScope(scope: Scope, index: number): void {
117    let decls = scope.getDecls();
118    for (let i = index + 1; i < decls.length; i++) {
119        if (hasDuplicateEntryInScope(decls[index], decls[i], scope)) {
120            throwDupIdError(decls[i]);
121        }
122    }
123}
124
125function hasDuplicateExportedFuncDecl(decl: FuncDecl, exportFuncMap: Map<string, boolean>): void {
126    if (!exportFuncMap.has(decl.name)) {
127        exportFuncMap.set(decl.name, hasExportKeywordModifier(decl.node));
128    } else {
129        if (exportFuncMap.get(decl.name) === true || hasExportKeywordModifier(decl.node)) {
130            throw new DiagnosticError(decl.node, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(decl.node), [decl.name]);
131        }
132    }
133}
134
135function hasDuplicateEntryAcrossScope(decl1: Decl, decl2: Decl): boolean {
136    if ((decl2 instanceof LetDecl) || (decl2 instanceof ConstDecl)) {
137        return decl1.name === decl2.name;
138    }
139}
140
141function hasDuplicateEntryInScope(decl1: Decl, decl2: Decl, scope: Scope): boolean {
142    if (((decl1 instanceof LetDecl) || (decl1 instanceof ConstDecl) || (decl1 instanceof ClassDecl && ts.isClassDeclaration(decl1.node)) ||
143        (decl2 instanceof LetDecl) || (decl2 instanceof ConstDecl) || (decl2 instanceof ClassDecl && ts.isClassDeclaration(decl1.node))) &&
144        !ts.isClassExpression(decl1.node) && !ts.isClassExpression(decl2.node)) {
145        return decl1.name === decl2.name;
146    }
147    // Var and FunctionDeclaration with same names, FunctionDeclaration and FunctionDeclaration with same names are illegal in strict mode
148    // and Module
149    /**
150     * eg1.
151     * if (true) {
152     *     var a;
153     *     function a() {};
154     * }
155     *
156     * eg2.
157     * if (true) {
158     *     function a() {};
159     *     function a() {};
160     * }
161     * eg3. [module]
162     * var a;
163     * function a(){};
164     */
165    if (scope instanceof LocalScope && isStrictMode(decl1.node) || scope instanceof ModuleScope) {
166        if (decl1 instanceof FuncDecl || decl2 instanceof FuncDecl) {
167            if (isFunctionLikeDeclaration(decl1.node.parent.parent) || isFunctionLikeDeclaration(decl2.node.parent.parent)) {
168                return false;
169            }
170            return decl1.name === decl2.name;
171        }
172    }
173
174    return false;
175}
176
177function checkDuplicateInCatch(blockScope: Scope, catchScope: Scope): void {
178    let bodyDecls = blockScope.getDecls();
179    let catchParameters = catchScope.getDecls();
180
181    for (let i = 0; i < catchParameters.length; i++) {
182        for (let j = i + 1; j < catchParameters.length; j++) {
183            if (catchParameters[i].name === catchParameters[j].name) {
184                throwDupIdError(catchParameters[j]);
185            }
186        }
187
188        for (let m = 0; m < bodyDecls.length; m++) {
189            if (bodyDecls[m] instanceof VarDecl) {
190                continue;
191            }
192
193            if (catchParameters[i].name === bodyDecls[m].name) {
194                throwDupIdError(bodyDecls[m]);
195            }
196        }
197    }
198}
199
200function getParameterNames(node: ts.FunctionLikeDeclaration, recorder: Recorder): string[] {
201    let parameters = recorder.getParametersOfFunction(node);
202    let parameterNames: string[] = [];
203
204    if (!parameters) {
205        return;
206    }
207
208    parameters.forEach(funcParam => {
209        parameterNames.push(funcParam.name);
210    });
211
212    return parameterNames;
213}
214
215function checkDuplicateParameter(node: ts.FunctionLikeDeclaration, recorder: Recorder): void {
216    let parameters = recorder.getParametersOfFunction(node);
217    let tempNames: string[] = [];
218    if (!parameters) {
219        return;
220    }
221    parameters.forEach(param => {
222        // @ts-ignore
223        if (tempNames.includes(param.name)) {
224            throwDupIdError(param);
225        } else {
226            tempNames.push(param.name);
227        }
228    });
229}
230
231function checkDuplicateParameterVar(parameterNames: string[] | undefined, scope: Scope): void {
232    if (!parameterNames) {
233        return;
234    }
235    let decls = scope.getDecls();
236    for (let i = 0; i < decls.length; i++) {
237        if ((decls[i] instanceof VarDecl) || (decls[i] instanceof FuncDecl)) {
238            continue;
239        }
240        let name = decls[i].name;
241        // @ts-ignore
242        if (parameterNames.includes(name)) {
243            throwDupIdError(decls[i]);
244        }
245    }
246}
247
248function checkDeclareGlobalId(decl: Decl, scope: Scope): void {
249    if (!(scope instanceof GlobalScope)) {
250        return;
251    }
252
253    if ((decl instanceof VarDecl) || (decl instanceof CatchParameter)) {
254        return;
255    }
256
257    if (isGlobalIdentifier(decl.name) && isDeclInGlobal(<ts.Identifier>decl.node)) {
258        let sourceNode = jshelpers.getSourceFileOfNode(decl.node);
259        throw new DiagnosticError(decl.node, DiagnosticCode.Declaration_name_conflicts_with_built_in_global_identifier_0, sourceNode, [decl.name]);
260    }
261}
262
263function throwDupIdError(decl: Decl): void {
264    let sourceNode = jshelpers.getSourceFileOfNode(decl.node);
265    if (decl.node.kind === ts.SyntaxKind.FunctionDeclaration) {
266        decl.node = <ts.Identifier>(<ts.FunctionDeclaration>decl.node).name;
267    }
268    throw new DiagnosticError(decl.node, DiagnosticCode.Duplicate_identifier_0, sourceNode, [decl.name]);
269}
270
271//**********************************Part 2: Implementing syntax check except declaration******************************************//
272export function checkSyntaxError(node: ts.Node, scope:Scope): void {
273    checkSyntaxErrorForSloppyAndStrictMode(node);
274    if (isStrictMode(node) || CmdOptions.isModules()) {
275        checkSyntaxErrorForStrictMode(node, scope);
276    }
277}
278
279function checkBreakOrContinueStatement(node: ts.BreakOrContinueStatement): boolean {
280    let curNode: ts.Node = node;
281    while (curNode) {
282        if (ts.isFunctionLike(curNode)) {
283            throw new DiagnosticError(node, DiagnosticCode.Jump_target_cannot_cross_function_boundary, jshelpers.getSourceFileOfNode(curNode));
284        }
285
286        switch (curNode.kind) {
287            case ts.SyntaxKind.SwitchStatement: {
288                if (node.kind === ts.SyntaxKind.BreakStatement && !node.label) {
289                    // unlabeled break within switch statement - ok
290                    return;
291                }
292                break;
293            }
294            case ts.SyntaxKind.LabeledStatement: {
295                if (node.label && (<ts.LabeledStatement>curNode).label.escapedText === node.label.escapedText) {
296                    // found matching label - verify that label usage is correct
297                    // continue can only target labels that are on iteration statements
298                    let isMisplacedContinueLabel = false;
299                    if (node.kind === ts.SyntaxKind.ContinueStatement &&
300                        !jshelpers.isIterationStatement((<ts.LabeledStatement>curNode).statement, /*lookInLabeledStatement*/ true)) {
301                        isMisplacedContinueLabel = true;
302                    }
303
304                    if (isMisplacedContinueLabel) {
305                        throw new DiagnosticError(node, DiagnosticCode.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement,
306                            jshelpers.getSourceFileOfNode(curNode));
307                    }
308
309                    return;
310                }
311                break;
312            }
313            default: {
314                if (jshelpers.isIterationStatement(curNode, /*lookInLabeledStatement*/ false) && !node.label) {
315                    // unlabeled break or continue within iteration statement - ok
316                    return false;
317                }
318                break;
319            }
320        }
321
322        curNode = curNode.parent;
323    }
324
325    let diagnosticCode;
326
327    if (node.label) {
328        if (node.kind === ts.SyntaxKind.BreakStatement) {
329            diagnosticCode = DiagnosticCode.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement;
330        } else {
331            diagnosticCode = DiagnosticCode.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement;
332        }
333    } else {
334        if (node.kind === ts.SyntaxKind.BreakStatement) {
335            diagnosticCode = DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement;
336        } else {
337            diagnosticCode = DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement;
338        }
339    }
340
341    throw new DiagnosticError(node, diagnosticCode, jshelpers.getSourceFileOfNode(node));
342}
343
344function checkReturnStatement(node: ts.ReturnStatement): void {
345    let func = jshelpers.getContainingFunction(node);
346    if (!func) {
347        let file = jshelpers.getSourceFileOfNode(node);
348        throw new DiagnosticError(node, DiagnosticCode.A_return_statement_can_only_be_used_within_a_function_body, file);
349    }
350}
351
352function checkMetaProperty(node: ts.MetaProperty): void {
353    let text = jshelpers.getTextOfIdentifierOrLiteral(node.name);
354    let file = jshelpers.getSourceFileOfNode(node);
355    switch (node.keywordToken) {
356        case ts.SyntaxKind.NewKeyword: {
357            let args = [text, jshelpers.tokenToString(node.keywordToken), "target"];
358            if (text != "target") {
359                throw new DiagnosticError(node, DiagnosticCode._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, file, args);
360            }
361
362            let func = getContainingFunctionDeclaration(node);
363            if (!func) {
364                throw new DiagnosticError(node,
365                    DiagnosticCode.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, file, args);
366            } else {
367                if (ts.isMethodDeclaration(func)) {
368                    throw new DiagnosticError(node,
369                        DiagnosticCode.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, file, args);
370                }
371                if (ts.isArrowFunction(func) && !jshelpers.getNewTargetContainer(node)) {
372                    throw new DiagnosticError(node,
373                        DiagnosticCode.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, file, args);
374                }
375            }
376            break;
377        }
378        case ts.SyntaxKind.ImportKeyword: {
379            if (text != "meta") {
380                let args = [text, jshelpers.tokenToString(node.keywordToken), "meta"];
381                throw new DiagnosticError(node, DiagnosticCode._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, file, args);
382            }
383            break;
384        }
385        default:
386            break;
387    }
388}
389
390function checkNameInLetOrConstDeclarations(name: ts.Identifier | ts.BindingPattern): void {
391    if (name.kind === ts.SyntaxKind.Identifier) {
392        if (name.originalKeywordKind === ts.SyntaxKind.LetKeyword) {
393            let file = jshelpers.getSourceFileOfNode(name);
394            throw new DiagnosticError(name, DiagnosticCode.The_let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations, file);
395        }
396    } else {
397        let elements = name.elements;
398        for (let element of elements) {
399            if (!ts.isOmittedExpression(element)) {
400                checkNameInLetOrConstDeclarations(element.name);
401            }
402        }
403    }
404}
405
406function checkDisallowedLetOrConstStatement(node: ts.VariableStatement): void {
407    if (allowLetAndConstDeclarations(node.parent)) {
408        return;
409    }
410
411    if (jshelpers.isLet(node.declarationList)) {
412        throw new DiagnosticError(node, DiagnosticCode.The_let_declarations_can_only_be_declared_inside_a_block);
413    }
414
415    if (jshelpers.isVarConst(node.declarationList)) {
416        throw new DiagnosticError(node, DiagnosticCode.The_const_declarations_can_only_be_declared_inside_a_block);
417    }
418}
419
420function checkVariableDeclaration(node: ts.VariableDeclaration): void {
421    let file = jshelpers.getSourceFileOfNode(node);
422    if (!ts.isForInStatement(node.parent.parent) && !ts.isForOfStatement(node.parent.parent) && !ts.isCatchClause(node.parent)) {
423        if (!node.initializer) {
424            if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
425                throw new DiagnosticError(node, DiagnosticCode.A_destructuring_declaration_must_have_an_initializer, file);
426            }
427
428            if (jshelpers.isVarConst(node)) {
429                throw new DiagnosticError(node, DiagnosticCode.The_const_declarations_must_be_initialized, file);
430            }
431        }
432    }
433
434    if (node.exclamationToken && (node.parent.parent.kind !== ts.SyntaxKind.VariableStatement || !node.type || node.initializer)) {
435        if (node.initializer) {
436            throw new DiagnosticError(node.exclamationToken,
437                DiagnosticCode.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions, file);
438        } else {
439            throw new DiagnosticError(node.exclamationToken,
440                DiagnosticCode.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations, file);
441        }
442    }
443
444    if (jshelpers.isLet(node) || jshelpers.isVarConst(node)) {
445        checkNameInLetOrConstDeclarations(node.name);
446        if (!isInBlockScope(node.parent.parent.parent) &&
447            !ts.isForInStatement(node.parent.parent) &&
448            !ts.isForOfStatement(node.parent.parent) &&
449            !ts.isForStatement(node.parent.parent)) {
450            throw new DiagnosticError(node, DiagnosticCode.const_and_let_declarations_not_allowed_in_statement_positions, file);
451        }
452    }
453}
454
455function checkDecorators(node: ts.Node): void {
456    if (!node.decorators) {
457        return;
458    }
459
460    let file = jshelpers.getSourceFileOfNode(node);
461    if (!jshelpers.nodeCanBeDecorated(node, node.parent, node.parent.parent)) {
462        if (ts.isMethodDeclaration(node) && !jshelpers.nodeIsPresent((<ts.MethodDeclaration>node).body)) {
463            throw new DiagnosticError(node, DiagnosticCode.A_decorator_can_only_decorate_a_method_implementation_not_an_overload, file);
464        } else {
465            throw new DiagnosticError(node, DiagnosticCode.Decorators_are_not_valid_here, file);
466        }
467    } else if (ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) {
468        let accessors = jshelpers.getAllAccessorDeclarations((<ts.ClassDeclaration>node.parent).members, <ts.AccessorDeclaration>node);
469        if (accessors.firstAccessor.decorators && node === accessors.secondAccessor) {
470            throw new DiagnosticError(node, DiagnosticCode.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name, file);
471        }
472    }
473}
474
475function checkAsyncModifier(node: ts.Node, asyncModifier: ts.Node): void {
476    switch (node.kind) {
477        case ts.SyntaxKind.ArrowFunction:
478        case ts.SyntaxKind.FunctionDeclaration:
479        case ts.SyntaxKind.FunctionExpression:
480        case ts.SyntaxKind.MethodDeclaration:
481            return;
482        default:
483            break;
484    }
485    let file = jshelpers.getSourceFileOfNode(node);
486    throw new DiagnosticError(asyncModifier, DiagnosticCode._0_modifier_cannot_be_used_here, file, ["async"]);
487}
488
489function checkModifiers(node: ts.Node): void {
490    if (!node.modifiers) {
491        return;
492    }
493
494    let lastStatic: ts.Node | undefined;
495    let lastDeclare: ts.Node | undefined;
496    let lastAsync: ts.Node | undefined;
497    let lastReadonly: ts.Node | undefined;
498    let flags = ts.ModifierFlags.None;
499    let file = jshelpers.getSourceFileOfNode(node);
500
501    for (let modifier of node.modifiers!) {
502        if (modifier.kind !== ts.SyntaxKind.ReadonlyKeyword) {
503            if (ts.isPropertySignature(node) || ts.isMethodSignature(node)) {
504                throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_type_member,
505                    file, [jshelpers.tokenToString(modifier.kind)]);
506            }
507            if (ts.isIndexSignatureDeclaration(node)) {
508                throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_an_index_signature,
509                    file, [jshelpers.tokenToString(modifier.kind)]);
510            }
511        }
512        switch (modifier.kind) {
513            case ts.SyntaxKind.ConstKeyword: {
514                if (ts.isEnumDeclaration(node)) {
515                    throw new DiagnosticError(node, DiagnosticCode.A_class_member_cannot_have_the_0_keyword,
516                        file, [jshelpers.tokenToString(ts.SyntaxKind.ConstKeyword)]);
517                }
518                break;
519            }
520            case ts.SyntaxKind.PublicKeyword:
521            case ts.SyntaxKind.ProtectedKeyword:
522            case ts.SyntaxKind.PrivateKeyword: {
523                const text = visibilityToString(jshelpers.modifierToFlag(modifier.kind));
524
525                if (flags & ts.ModifierFlags.AccessibilityModifier) {
526                    throw new DiagnosticError(modifier, DiagnosticCode.Accessibility_modifier_already_seen, file);
527                } else if (flags & ts.ModifierFlags.Static) {
528                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "static"]);
529                } else if (flags & ts.ModifierFlags.Readonly) {
530                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "readonly"]);
531                } else if (flags & ts.ModifierFlags.Async) {
532                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "async"]);
533                } else if (ts.isModuleBlock(node.parent) || ts.isSourceFile(node.parent)) {
534                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_module_or_namespace_element, file, [text]);
535                } else if (flags & ts.ModifierFlags.Abstract) {
536                    if (modifier.kind === ts.SyntaxKind.PrivateKeyword) {
537                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, [text, "abstract"]);
538                    } else {
539                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "abstract"]);
540                    }
541                } else if (ts.isPropertyDeclaration(node) && ts.isPrivateIdentifier(node.name)) {
542                    throw new DiagnosticError(modifier, DiagnosticCode.An_accessibility_modifier_cannot_be_used_with_a_private_identifier, file);
543                }
544                flags |= jshelpers.modifierToFlag(modifier.kind);
545                break;
546            }
547            case ts.SyntaxKind.StaticKeyword: {
548                if (flags & ts.ModifierFlags.Static) {
549                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["static"]);
550                } else if (flags & ts.ModifierFlags.Readonly) {
551                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["static", "readonly"]);
552                } else if (flags & ts.ModifierFlags.Async) {
553                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["static", "async"]);
554                } else if (ts.isModuleBlock(node.parent) || ts.isSourceFile(node.parent)) {
555                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_module_or_namespace_element, file, ["static"]);
556                } else if (ts.isParameter(node)) {
557                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["static"]);
558                } else if (flags & ts.ModifierFlags.Abstract) {
559                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["static", "abstract"]);
560                } else if (ts.isPropertyDeclaration(node) && ts.isPrivateIdentifier(node.name)) {
561                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_a_private_identifier, file, ["static"]);
562                }
563                flags |= ts.ModifierFlags.Static;
564                lastStatic = modifier;
565                break;
566            }
567            case ts.SyntaxKind.ReadonlyKeyword: {
568                if (flags & ts.ModifierFlags.Readonly) {
569                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["readonly"]);
570                } else if (!ts.isPropertyDeclaration(node) && !ts.isPropertySignature(node) &&
571                           !ts.isIndexSignatureDeclaration(node) && !ts.isParameter(node)) {
572                    // If node.kind === SyntaxKind.Parameter, checkParameter report an error if it's not a parameter property.
573                    throw new DiagnosticError(modifier,
574                        DiagnosticCode.The_readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature, file);
575                }
576                flags |= ts.ModifierFlags.Readonly;
577                lastReadonly = modifier;
578                break;
579            }
580            case ts.SyntaxKind.ExportKeyword: {
581                if (flags & ts.ModifierFlags.Export) {
582                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["export"]);
583                } else if (flags & ts.ModifierFlags.Ambient) {
584                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["export", "declare"]);
585                } else if (flags & ts.ModifierFlags.Abstract) {
586                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["export", "abstract"]);
587                } else if (flags & ts.ModifierFlags.Async) {
588                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["export", "async"]);
589                } else if (ts.isClassLike(node.parent)) {
590                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_class_elements_of_this_kind, file, ["export"]);
591                } else if (ts.isParameter(node)) {
592                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["export"]);
593                }
594                flags |= ts.ModifierFlags.Export;
595                break;
596            }
597            case ts.SyntaxKind.DefaultKeyword: {
598                let container = ts.isSourceFile(node.parent) ? node.parent : node.parent.parent;
599                if (ts.isModuleDeclaration(container) && !jshelpers.isAmbientModule(container)) {
600                    throw new DiagnosticError(modifier, DiagnosticCode.A_default_export_can_only_be_used_in_an_ECMAScript_style_module, file);
601                }
602
603                flags |= ts.ModifierFlags.Default;
604                break;
605            }
606            case ts.SyntaxKind.DeclareKeyword: {
607                if (flags & ts.ModifierFlags.Ambient) {
608                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["declare"]);
609                } else if (flags & ts.ModifierFlags.Async) {
610                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_in_an_ambient_context, file, ["async"]);
611                } else if (ts.isClassLike(node.parent) && !ts.isPropertyDeclaration(node)) {
612                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_class_elements_of_this_kind, file, ["declare"]);
613                } else if (ts.isParameter(node)) {
614                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["declare"]);
615                } else if (ts.isPropertyDeclaration(node) && ts.isPrivateIdentifier(node.name)) {
616                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_a_private_identifier, file, ["declare"]);
617                }
618                flags |= ts.ModifierFlags.Ambient;
619                lastDeclare = modifier;
620                break;
621            }
622            case ts.SyntaxKind.AbstractKeyword: {
623                if (flags & ts.ModifierFlags.Abstract) {
624                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["abstract"]);
625                }
626                if (ts.isClassDeclaration(node) && ts.isConstructorTypeNode(node)) {
627                    if (!ts.isMethodDeclaration(node) && !ts.isPropertyDeclaration(node) &&
628                        !ts.isGetAccessorDeclaration(node) && !ts.isSetAccessorDeclaration(node)) {
629                        throw new DiagnosticError(modifier,
630                            DiagnosticCode.The_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration, file);
631                    }
632                    if (flags & ts.ModifierFlags.Static) {
633                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["static", "abstract"]);
634                    }
635                    if (flags & ts.ModifierFlags.Private) {
636                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["private", "abstract"]);
637                    }
638                    if (flags & ts.ModifierFlags.Async && lastAsync) {
639                        throw new DiagnosticError(lastAsync, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["async", "abstract"]);
640                    }
641                }
642                let name = (<ts.NamedDeclaration>node).name;
643                if (name && ts.isPrivateIdentifier(name)) {
644                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_a_private_identifier, file, ["abstract"]);
645                }
646
647                flags |= ts.ModifierFlags.Abstract;
648                break;
649            }
650            case ts.SyntaxKind.AsyncKeyword: {
651                if (flags & ts.ModifierFlags.Async) {
652                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["async"]);
653                } else if (flags & ts.ModifierFlags.Ambient) {
654                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_in_an_ambient_context, file, ["async"]);
655                } else if (ts.isParameter(node)) {
656                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["async"]);
657                }
658                if (flags & ts.ModifierFlags.Abstract) {
659                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["async", "abstract"]);
660                }
661                flags |= ts.ModifierFlags.Async;
662                lastAsync = modifier;
663                break;
664            }
665            default:
666                break;
667        }
668    }
669
670    if (ts.isConstructorDeclaration(node)) {
671        if (flags & ts.ModifierFlags.Static) {
672            throw new DiagnosticError(lastStatic!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["static"]);
673        }
674        if (flags & ts.ModifierFlags.Abstract) {
675            throw new DiagnosticError(lastStatic!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["abstract"]);
676        } else if (flags & ts.ModifierFlags.Async) {
677            throw new DiagnosticError(lastAsync!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["async"]);
678        } else if (flags & ts.ModifierFlags.Readonly) {
679            throw new DiagnosticError(lastReadonly!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["readonly"]);
680        }
681    } else if ((ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node)) && flags & ts.ModifierFlags.Ambient) {
682        throw new DiagnosticError(lastDeclare!, DiagnosticCode.A_0_modifier_cannot_be_used_with_an_import_declaration, file, ["declare"]);
683    } else if (ts.isParameter(node) && (flags & ts.ModifierFlags.ParameterPropertyModifier) && isBindingPattern((<ts.ParameterDeclaration>node).name)) {
684        throw new DiagnosticError(node, DiagnosticCode.A_parameter_property_may_not_be_declared_using_a_binding_pattern, file);
685    } else if (ts.isParameter(node) && (flags & ts.ModifierFlags.ParameterPropertyModifier) && (<ts.ParameterDeclaration>node).dotDotDotToken) {
686        throw new DiagnosticError(node, DiagnosticCode.A_parameter_property_cannot_be_declared_using_a_rest_parameter, file);
687    }
688
689    if (flags & ts.ModifierFlags.Async) {
690        checkAsyncModifier(node, lastAsync!);
691    }
692}
693
694function checkVariableDeclarationList(declarationList: ts.VariableDeclarationList): void {
695    let declarations = declarationList.declarations;
696    if (!declarations.length) {
697        throw new DiagnosticError(declarationList, DiagnosticCode.Identifier_expected);
698    }
699
700    let decl = declarations[0].name;
701    if (isBindingPattern(decl)) {
702        checkBindingPattern(<ts.BindingPattern>decl);
703    }
704}
705
706function checkVariableStatement(node: ts.VariableStatement): void {
707    checkDecorators(node);
708    checkModifiers(node);
709    checkVariableDeclarationList(node.declarationList);
710    checkDisallowedLetOrConstStatement(node);
711}
712
713function checkForInOrForOfStatement(stmt: ts.ForInOrOfStatement): void {
714    let file = jshelpers.getSourceFileOfNode(stmt);
715    let leftExpr = stmt.initializer;
716    if (ts.isParenthesizedExpression(leftExpr)) {
717        leftExpr = findInnerExprOfParenthesis(leftExpr);
718    }
719    if (ts.isVariableDeclarationList(leftExpr)) {
720        let variableList = <ts.VariableDeclarationList>leftExpr;
721        checkVariableDeclarationList(variableList);
722        let declarations = variableList.declarations;
723
724        if (declarations.length > 1) {
725            if (ts.isForInStatement(stmt)) {
726                throw new DiagnosticError(variableList.declarations[1],
727                    DiagnosticCode.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement, file);
728            } else {
729                throw new DiagnosticError(variableList.declarations[1],
730                    DiagnosticCode.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement, file);
731            }
732        }
733
734        if (declarations[0].initializer) {
735            if (ts.isForInStatement(stmt)) {
736                throw new DiagnosticError(declarations[0].name,
737                    DiagnosticCode.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer, file);
738            } else {
739                throw new DiagnosticError(declarations[0].name,
740                    DiagnosticCode.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer, file);
741            }
742        }
743
744        if (declarations[0].type) {
745            if (ts.isForInStatement(stmt)) {
746                throw new DiagnosticError(declarations[0],
747                    DiagnosticCode.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation, file);
748            } else {
749                throw new DiagnosticError(declarations[0],
750                    DiagnosticCode.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation, file);
751            }
752        }
753    } else {
754        isInVaildAssignmentLeftSide(<ts.Expression>leftExpr);
755
756        if (ts.isArrayLiteralExpression(leftExpr) || ts.isObjectLiteralExpression(leftExpr)) {
757            checkDestructuringAssignmentLhs(leftExpr);
758        }
759    }
760}
761
762function checkForInOrForOfVariableDeclaration(iterationStatement: ts.ForInOrOfStatement): void {
763    let variableDeclarationList = <ts.VariableDeclarationList>iterationStatement.initializer;
764    // checkGrammarForInOrForOfStatement will check that there is exactly one declaration.
765    if (variableDeclarationList.declarations.length >= 1) {
766        checkVariableDeclaration(variableDeclarationList.declarations[0]);
767    }
768}
769
770function checkForInStatement(node: ts.ForInStatement): void {
771    checkForInOrForOfStatement(node);
772
773    let file = jshelpers.getSourceFileOfNode(node);
774    // for (let VarDecl in Expr) Statement
775    if (ts.isVariableDeclarationList(node.initializer)) {
776        checkForInOrForOfVariableDeclaration(node);
777    } else {
778        let varExpr = node.initializer;
779        if (ts.isArrayLiteralExpression(varExpr) || ts.isObjectLiteralExpression(varExpr)) {
780            throw new DiagnosticError(varExpr, DiagnosticCode.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern, file);
781        }
782    }
783}
784
785const enum OuterExpressionKinds {
786    PARENTHESES = 1 << 0,
787    TYPEASSERTIONS = 1 << 1,
788    NON_NULL_ASSERTIONS= 1 << 2,
789    PARTIALLY_EMITTED_EXPRESSIONS = 1 << 3,
790    ASSERTIONS= TYPEASSERTIONS | NON_NULL_ASSERTIONS,
791    ALL = PARENTHESES | ASSERTIONS | PARTIALLY_EMITTED_EXPRESSIONS
792}
793
794function checkReferenceExpression(expr: ts.Expression, invalidReferenceCode: DiagnosticCode, invalidOptionalChainCode: DiagnosticCode): void {
795    let node = jshelpers.skipOuterExpressions(expr, OuterExpressionKinds.ASSERTIONS | OuterExpressionKinds.PARENTHESES);
796    if (node.kind !== ts.SyntaxKind.Identifier && node.kind !== ts.SyntaxKind.PropertyAccessExpression &&
797        node.kind !== ts.SyntaxKind.ElementAccessExpression) {
798        throw new DiagnosticError(expr, invalidReferenceCode);
799    }
800
801    if (node.flags & ts.NodeFlags.OptionalChain) {
802        throw new DiagnosticError(expr, invalidOptionalChainCode);
803    }
804}
805
806function checkReferenceAssignment(node: ts.Expression): void {
807    let invalidReferenceCode: DiagnosticCode;
808    let invalidOptionalChainCode: DiagnosticCode;
809
810    if (ts.isSpreadAssignment(node.parent)) {
811        invalidReferenceCode = DiagnosticCode.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access;
812        invalidOptionalChainCode = DiagnosticCode.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access;
813    } else {
814        invalidReferenceCode = DiagnosticCode.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access;
815        invalidOptionalChainCode = DiagnosticCode.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access;
816    }
817
818    checkReferenceExpression(node, invalidReferenceCode, invalidOptionalChainCode);
819}
820
821function checkDestructuringAssignment(node: ts.Expression | ts.ShorthandPropertyAssignment): void {
822    let target: ts.Expression;
823    if (ts.isShorthandPropertyAssignment(node)) {
824        let prop = <ts.ShorthandPropertyAssignment>node;
825        target = prop.name;
826    } else {
827        target = node;
828    }
829
830    if (ts.isBinaryExpression(target) && (<ts.BinaryExpression>target).operatorToken.kind === ts.SyntaxKind.EqualsToken) {
831        checkBinaryExpression(<ts.BinaryExpression>target);
832        target = (<ts.BinaryExpression>target).left;
833    }
834
835    if (ts.isObjectLiteralExpression(target)) {
836        checkObjectLiteralExpression(target);
837    }
838
839    checkReferenceAssignment(target);
840
841}
842
843function checkForOfStatement(node: ts.ForOfStatement): void {
844    checkForInOrForOfStatement(node);
845
846    if (ts.isVariableDeclarationList(node.initializer)) {
847        checkForInOrForOfVariableDeclaration(node);
848    } else {
849        let varExpr = node.initializer;
850
851        if (ts.isArrayLiteralExpression(varExpr) || ts.isObjectLiteralExpression(varExpr)) {
852            checkDestructuringAssignment(varExpr);
853        } else {
854            checkReferenceExpression(
855                varExpr,
856                DiagnosticCode.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access,
857                DiagnosticCode.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access);
858        }
859    }
860}
861
862function checkClassDeclaration(node: ts.ClassLikeDeclaration): void {
863    checkClassDeclarationHeritageClauses(node);
864    let hasConstructorImplementation = false;
865    let file = jshelpers.getSourceFileOfNode(node);
866    node.members.forEach(member => {
867        switch (member.kind) {
868            case ts.SyntaxKind.Constructor: {
869                if (hasConstructorImplementation) {
870                    throw new DiagnosticError(node, DiagnosticCode.Multiple_constructor_implementations_are_not_allowed, file);
871                } else {
872                    hasConstructorImplementation = true;
873                }
874                break;
875            }
876            case ts.SyntaxKind.MethodDeclaration:
877            case ts.SyntaxKind.SetAccessor:
878                checkFunctionLikeDeclaration(<ts.FunctionLikeDeclaration | ts.MethodSignature>member);
879                break;
880            case ts.SyntaxKind.GetAccessor:
881                checkGetAccessor(<ts.GetAccessorDeclaration>member);
882                break;
883            default:
884                break;
885        }
886    });
887
888    // Class declaration not allowed in statement position
889    if (isStatement(node.parent.kind)) {
890        throw new DiagnosticError(node, DiagnosticCode.Class_declaration_not_allowed_in_statement_position, file);
891    }
892
893}
894
895function checkClassDeclarationHeritageClauses(node: ts.ClassLikeDeclaration): void {
896    let hasExtendsKeyWords = false;
897    checkDecorators(node);
898    checkModifiers(node);
899    if (node.heritageClauses === undefined) {
900        return;
901    }
902
903    let file = jshelpers.getSourceFileOfNode(node);
904    for (let heritageClause of node.heritageClauses) {
905        if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
906            if (hasExtendsKeyWords) {
907                throw new DiagnosticError(heritageClause, DiagnosticCode.The_extends_clause_already_seen, file);
908            }
909
910            if (heritageClause.types.length > 1) {
911                throw new DiagnosticError(heritageClause, DiagnosticCode.Classes_can_only_extend_a_single_class);
912            }
913            hasExtendsKeyWords = true;
914        }
915    }
916}
917
918function checkBinaryExpression(node: ts.BinaryExpression): void {
919    // AssignmentExpression
920    if (isAssignmentOperator(node.operatorToken.kind)) {
921        let leftExpr: ts.Expression = node.left;
922        if (ts.isParenthesizedExpression(leftExpr)) {
923            leftExpr = findInnerExprOfParenthesis(leftExpr);
924        }
925
926        if (node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
927            if (ts.isArrayLiteralExpression(leftExpr) || ts.isObjectLiteralExpression(leftExpr)) {
928                checkDestructuringAssignmentLhs(leftExpr);
929            }
930        }
931
932        isInVaildAssignmentLeftSide(leftExpr);
933    }
934}
935
936function isInVaildAssignmentLeftSide(leftExpr: ts.Expression): void {
937    if (jshelpers.isKeyword(leftExpr.kind) ||
938        leftExpr.kind === ts.SyntaxKind.NumericLiteral ||
939        leftExpr.kind === ts.SyntaxKind.StringLiteral) {
940        throw new DiagnosticError(leftExpr, DiagnosticCode.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access);
941    }
942}
943
944
945function checkContextualIdentifier(node: ts.Identifier): void {
946    if (jshelpers.isIdentifierName(node)) {
947        return;
948    }
949
950    let file = jshelpers.getSourceFileOfNode(node);
951    if (node.originalKeywordKind === ts.SyntaxKind.AwaitKeyword) {
952        if (jshelpers.isExternalOrCommonJsModule(file) && jshelpers.isInTopLevelContext(node)) {
953            throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module,
954                file, jshelpers.declarationNameToString(node));
955        } else if (node.flags & ts.NodeFlags.AwaitContext) {
956            throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here,
957                file, jshelpers.declarationNameToString(node));
958        }
959    } else if (node.originalKeywordKind === ts.SyntaxKind.YieldKeyword && node.flags & ts.NodeFlags.YieldContext) {
960        throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here,
961            file, jshelpers.declarationNameToString(node));
962    }
963}
964
965function checkComputedPropertyName(node: ts.Node): void {
966    if (!ts.isComputedPropertyName(node)) {
967        return;
968    }
969
970    let expression = node.expression;
971    if (ts.isBinaryExpression(expression) && expression.operatorToken.kind === ts.SyntaxKind.CommaToken) {
972        let file = jshelpers.getSourceFileOfNode(node);
973        throw new DiagnosticError(expression, DiagnosticCode.A_comma_expression_is_not_allowed_in_a_computed_property_name, file);
974    }
975}
976
977const enum DeclarationMeaning {
978    GET_ACCESSOR = 1,
979    SET_ACCESSOR = 2,
980    PROPERTY_ASSIGNMENT = 4,
981    METHOD= 8,
982    GET_OR_SET_ACCESSOR = GET_ACCESSOR | SET_ACCESSOR,
983    PROPERTY_ASSIGNMENT_OR_METHOD = PROPERTY_ASSIGNMENT | METHOD,
984}
985
986function checkObjectLiteralExpression(node: ts.ObjectLiteralExpression): void {
987    let inDestructuring = jshelpers.isAssignmentTarget(node);
988    let file = jshelpers.getSourceFileOfNode(node);
989    let seen = new Map<ts.__String, DeclarationMeaning>();
990
991    for (let prop of node.properties) {
992        if (ts.isSpreadAssignment(prop)) {
993            if (inDestructuring) {
994                let expression = jshelpers.skipParentheses(prop.expression);
995                if (ts.isArrayLiteralExpression(expression) || ts.isObjectLiteralExpression(expression)) {
996                    throw new DiagnosticError(prop.expression, DiagnosticCode.A_rest_element_cannot_contain_a_binding_pattern, file);
997                }
998            }
999            continue;
1000        }
1001        let name = prop.name;
1002        if (ts.isComputedPropertyName(name)) {
1003            checkComputedPropertyName(name);
1004        }
1005
1006        if (ts.isShorthandPropertyAssignment(prop) && !inDestructuring && prop.objectAssignmentInitializer) {
1007            throw new DiagnosticError(prop.equalsToken!,
1008                DiagnosticCode.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern,
1009                file);
1010        }
1011
1012        if (ts.isPrivateIdentifier(name)) {
1013            throw new DiagnosticError(name, DiagnosticCode.Private_identifiers_are_not_allowed_outside_class_bodies, file);
1014        }
1015
1016        if (prop.modifiers) {
1017            for (let mod of prop.modifiers) {
1018                if (!ts.isMethodDeclaration(prop) || mod.kind != ts.SyntaxKind.AsyncKeyword) {
1019                    throw new DiagnosticError(mod, DiagnosticCode._0_modifier_cannot_be_used_here, file, [jshelpers.getTextOfNode(mod)]);
1020                }
1021            }
1022        }
1023
1024        /**
1025        * It is a Syntax Error if PropertyNameList of PropertyDefinitionList contains any duplicate entries for "__proto__" and
1026        * at least two of those entries were obtained from productions of the form
1027        * PropertyDefinition : PropertyName : AssignmentExpression .
1028        */
1029        let curKind = getPropertieDeclaration(prop, name);
1030        if (!curKind) {
1031            continue;
1032        }
1033        if (!inDestructuring) {
1034            let effectName = jshelpers.getPropertyNameForPropertyNameNode(name);
1035            if (!effectName || ts.isComputedPropertyName(name)) {
1036                continue;
1037            }
1038            let existKind = seen.get(effectName);
1039            if (!existKind) {
1040                seen.set(effectName, curKind);
1041            } else {
1042                if ((curKind & DeclarationMeaning.PROPERTY_ASSIGNMENT_OR_METHOD) && (existKind & DeclarationMeaning.PROPERTY_ASSIGNMENT_OR_METHOD)) {
1043                    if (effectName === "___proto__") {
1044                        throw new DiagnosticError(name, DiagnosticCode.Duplicate_identifier_0, file, [jshelpers.getTextOfNode(name)]);
1045                    }
1046                }
1047            }
1048        }
1049    }
1050}
1051
1052function checkInvalidExclamationToken(exclamationToken: ts.ExclamationToken | undefined): void {
1053    if (!!exclamationToken) {
1054        let file = jshelpers.getSourceFileOfNode(exclamationToken);
1055        throw new DiagnosticError(exclamationToken, DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context, file);
1056    }
1057}
1058
1059function checkInvalidQuestionMark(questionToken: ts.QuestionToken | undefined): void {
1060    if (!!questionToken) {
1061        let file = jshelpers.getSourceFileOfNode(questionToken);
1062        throw new DiagnosticError(questionToken, DiagnosticCode.An_object_member_cannot_be_declared_optional, file);
1063    }
1064}
1065
1066// @ts-ignore
1067function getPropertieDeclaration(node: ts.Node, name: ts.Node): any {
1068    let decl = undefined;
1069    if (ts.isShorthandPropertyAssignment(node)) {
1070        checkInvalidExclamationToken(node.exclamationToken);
1071    } else if (ts.isPropertyAssignment(node)) {
1072        checkInvalidQuestionMark(node.questionToken);
1073        decl = DeclarationMeaning.PROPERTY_ASSIGNMENT;
1074    } else if (ts.isMethodDeclaration(node)) {
1075        decl = DeclarationMeaning.METHOD;
1076    } else if (ts.isGetAccessor(node)) {
1077        checkGetAccessor(node);
1078        decl = DeclarationMeaning.GET_ACCESSOR;
1079    } else if (ts.isSetAccessor(node)) {
1080        decl = DeclarationMeaning.SET_ACCESSOR;
1081    } else {
1082        LOGE("Unexpected syntax kind:" + node.kind);
1083    }
1084    return decl;
1085}
1086
1087function checkDisallowedTrailingComma(list: ts.NodeArray<ts.Node> | undefined): void {
1088    if (list && list.hasTrailingComma) {
1089        let file = jshelpers.getSourceFileOfNode(list[0]);
1090        throw new DiagnosticError(list[0], DiagnosticCode.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, file);
1091    }
1092}
1093
1094function checkParameters(parameters: ts.NodeArray<ts.ParameterDeclaration>): void {
1095    let count = parameters.length;
1096    let optionalParameter = false;
1097
1098    for (let i = 0; i < count; i++) {
1099        let parameter = parameters[i];
1100        let file = jshelpers.getSourceFileOfNode(parameter);
1101        if (parameter.dotDotDotToken) {
1102            if (i != count - 1) {
1103                throw new DiagnosticError(parameter.dotDotDotToken, DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list, file);
1104            }
1105
1106            checkDisallowedTrailingComma(parameters);
1107
1108            if (parameter.initializer) {
1109                throw new DiagnosticError(parameter.name, DiagnosticCode.A_rest_parameter_cannot_have_an_initializer, file);
1110            }
1111
1112            if (parameter.questionToken) {
1113                throw new DiagnosticError(parameter.questionToken, DiagnosticCode.A_rest_parameter_cannot_be_optional, file);
1114            }
1115
1116        } else if (isOptionalParameter(parameter)) {
1117            optionalParameter = true;
1118            if (parameter.questionToken && parameter.initializer) {
1119                throw new DiagnosticError(parameter.name, DiagnosticCode.Parameter_cannot_have_question_mark_and_initializer, file);
1120            }
1121        }
1122        else if (optionalParameter && !parameter.initializer) {
1123            throw new DiagnosticError(parameter.name, DiagnosticCode.A_required_parameter_cannot_follow_an_optional_parameter, file);
1124        }
1125    }
1126}
1127
1128function checkArrowFunction(node: ts.Node): void {
1129    if (!ts.isArrowFunction(node)) {
1130        return;
1131    }
1132
1133    const { equalsGreaterThanToken } = node;
1134    let file = jshelpers.getSourceFileOfNode(node);
1135    const startLine = file.getLineAndCharacterOfPosition(equalsGreaterThanToken.pos).line;
1136    const endLine = file.getLineAndCharacterOfPosition(equalsGreaterThanToken.end).line;
1137    if (startLine !== endLine) {
1138        throw new DiagnosticError(equalsGreaterThanToken, DiagnosticCode.Line_terminator_not_permitted_before_arrow, file);
1139    }
1140}
1141
1142function checkFunctionLikeDeclaration(node: ts.FunctionLikeDeclaration | ts.MethodSignature): void {
1143    checkDecorators(node);
1144    checkModifiers(node);
1145    checkParameters(node.parameters);
1146    checkArrowFunction(node);
1147}
1148
1149function checkLabeledStatement(node: ts.LabeledStatement): void {
1150    let file = jshelpers.getSourceFileOfNode(node);
1151    jshelpers.findAncestor(node.parent, current => {
1152        if (jshelpers.isFunctionLike(current)) {
1153            return "quit";
1154        }
1155
1156        if (ts.isLabeledStatement(current) && (<ts.LabeledStatement>current).label.escapedText === node.label.escapedText) {
1157            throw new DiagnosticError(node.label, DiagnosticCode.Duplicate_label_0, file, [jshelpers.getTextOfNode(node.label)]);
1158        }
1159        return false;
1160    });
1161
1162    let statement = node.statement;
1163    if (ts.isVariableStatement(statement)) {
1164        let variableStatement = <ts.VariableStatement>statement;
1165        if (jshelpers.isLet(variableStatement.declarationList)) {
1166            throw new DiagnosticError(node, DiagnosticCode.Lexical_declaration_let_not_allowed_in_statement_position);
1167        }
1168
1169        if (jshelpers.isVarConst(variableStatement.declarationList)) {
1170            throw new DiagnosticError(node, DiagnosticCode.Lexical_declaration_const_not_allowed_in_statement_position);
1171        }
1172    }
1173}
1174
1175function checkGetAccessor(node: ts.GetAccessorDeclaration): void {
1176    checkFunctionLikeDeclaration(node);
1177    if (node.parameters.length != 0) {
1178        throw new DiagnosticError(node, DiagnosticCode.Getter_must_not_have_any_formal_parameters);
1179    }
1180}
1181
1182function isValidUseSuperExpression(node: ts.Node, isCallExpression: boolean): boolean {
1183    if (!node) {
1184        return false;
1185    }
1186
1187    if (isCallExpression) {
1188        return ts.isConstructorDeclaration(node);
1189    }
1190
1191    if (!ts.isClassLike(node.parent) && !ts.isObjectLiteralExpression(node.parent)) {
1192        return false;
1193    }
1194
1195    return ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node) ||
1196        ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isConstructorDeclaration(node);
1197}
1198
1199function checkSuperExpression(node: ts.SuperExpression): void {
1200    let file = jshelpers.getSourceFileOfNode(node);
1201    let isCallExpression = false;
1202    if (ts.isCallExpression(node.parent) && (<ts.CallExpression>node.parent).expression === node) {
1203        isCallExpression = true;
1204    }
1205
1206    let container = jshelpers.getSuperContainer(node, true);
1207
1208    if (!isCallExpression) {
1209        while (container && ts.isArrowFunction(container)) {
1210            container = jshelpers.getSuperContainer(container, true);
1211        }
1212    }
1213
1214    let isSuperExpCanUse = isValidUseSuperExpression(container, isCallExpression);
1215
1216    if (!isSuperExpCanUse) {
1217        let current = jshelpers.findAncestor(node, n => n === container ? "quit" : ts.isComputedPropertyName(n));
1218        if (current && ts.isComputedPropertyName(current)) {
1219            throw new DiagnosticError(node, DiagnosticCode.The_super_cannot_be_referenced_in_a_computed_property_name, file);
1220        }
1221        let containerFunc = jshelpers.findAncestor(node, ts.isConstructorDeclaration);
1222        if (containerFunc) {
1223            return;
1224        }
1225        if (isCallExpression) {
1226            throw new DiagnosticError(node,
1227                DiagnosticCode.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors, file);
1228        }
1229
1230        if (!container || !container.parent || !ts.isClassLike(container.parent) || ts.isObjectLiteralExpression(container.parent)) {
1231            throw new DiagnosticError(node,
1232                DiagnosticCode.The_super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions, file);
1233        }
1234
1235        throw new DiagnosticError(node,
1236            DiagnosticCode.The_super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class, file);
1237    }
1238}
1239
1240function checkImportExpression(node: ts.ImportExpression): void {
1241    let args = (<ts.CallExpression>node.parent).arguments;
1242    if (args.length != 1) {
1243        throw new DiagnosticError(node, DiagnosticCode.Dynamic_imports_can_only_accept_a_module_specifier_optional_assertion_is_not_supported_yet);
1244    }
1245
1246    args.forEach(arg => {
1247        if (ts.isSpreadElement(arg)) {
1248            throw new DiagnosticError(node, DiagnosticCode.Argument_of_dynamic_import_cannot_be_spread_element);
1249        }
1250    });
1251}
1252
1253function checkRegularExpression(regexp: ts.RegularExpressionLiteral): void {
1254    let regexpText = regexp.text;
1255    let regexpParse = require("regexpp").RegExpParser;
1256    new regexpParse().parseLiteral(regexpText);
1257}
1258
1259function checkThrowStatement(node: ts.ThrowStatement): void {
1260    if (ts.isIdentifier(node.expression) && (<ts.Identifier>node.expression).text === '') {
1261        throw new DiagnosticError(node, DiagnosticCode.Line_break_not_permitted_here, jshelpers.getSourceFileOfNode(node));
1262    }
1263}
1264
1265function checkSyntaxErrorForSloppyAndStrictMode(node: ts.Node): void {
1266    switch (node.kind) {
1267        case ts.SyntaxKind.BreakStatement:
1268        case ts.SyntaxKind.ContinueStatement:
1269            checkBreakOrContinueStatement(<ts.BreakOrContinueStatement>node);
1270            break;
1271        case ts.SyntaxKind.ReturnStatement:
1272            checkReturnStatement(<ts.ReturnStatement>node);
1273            break;
1274        case ts.SyntaxKind.ComputedPropertyName:
1275            checkComputedPropertyName(<ts.ComputedPropertyName>node);
1276            break;
1277        case ts.SyntaxKind.ObjectBindingPattern:
1278        case ts.SyntaxKind.ArrayBindingPattern:
1279            checkBindingPattern(<ts.BindingPattern>node);
1280            break;
1281        case ts.SyntaxKind.MetaProperty:
1282            checkMetaProperty(<ts.MetaProperty>node);
1283            break;
1284        case ts.SyntaxKind.VariableDeclaration:
1285            checkVariableDeclaration(<ts.VariableDeclaration>node);
1286            break;
1287        case ts.SyntaxKind.VariableStatement:
1288            checkVariableStatement(<ts.VariableStatement>node);
1289            break;
1290        case ts.SyntaxKind.ForInStatement:
1291            checkForInStatement(<ts.ForInStatement>node);
1292            break;
1293        case ts.SyntaxKind.ForOfStatement:
1294            checkForOfStatement(<ts.ForOfStatement>node);
1295            break;
1296        case ts.SyntaxKind.ClassDeclaration:
1297        case ts.SyntaxKind.ClassExpression:
1298            checkClassDeclaration(<ts.ClassLikeDeclaration>node);
1299            break;
1300        case ts.SyntaxKind.SuperKeyword:
1301            checkSuperExpression(<ts.SuperExpression>node);
1302            break;
1303        case ts.SyntaxKind.ImportKeyword:
1304            checkImportExpression(<ts.ImportExpression>node);
1305            break;
1306        case ts.SyntaxKind.BinaryExpression:
1307            checkBinaryExpression(<ts.BinaryExpression>node);
1308            break;
1309        case ts.SyntaxKind.Identifier:
1310            checkContextualIdentifier(<ts.Identifier>node);
1311            break;
1312        case ts.SyntaxKind.ObjectLiteralExpression:
1313            checkObjectLiteralExpression(<ts.ObjectLiteralExpression>node);
1314            break;
1315        case ts.SyntaxKind.FunctionDeclaration:
1316        case ts.SyntaxKind.MethodSignature:
1317        case ts.SyntaxKind.MethodDeclaration:
1318        case ts.SyntaxKind.SetAccessor:
1319        case ts.SyntaxKind.Constructor:
1320        case ts.SyntaxKind.FunctionExpression:
1321        case ts.SyntaxKind.ArrowFunction:
1322            checkFunctionLikeDeclaration(<ts.FunctionLikeDeclaration | ts.MethodSignature>node);
1323            break;
1324        case ts.SyntaxKind.GetAccessor:
1325            checkGetAccessor(<ts.GetAccessorDeclaration>node);
1326            break;
1327        case ts.SyntaxKind.LabeledStatement:
1328            checkLabeledStatement(<ts.LabeledStatement>node);
1329            break;
1330        case ts.SyntaxKind.RegularExpressionLiteral:
1331            checkRegularExpression(<ts.RegularExpressionLiteral>node);
1332            break;
1333        case ts.SyntaxKind.ThrowStatement:
1334            checkThrowStatement(<ts.ThrowStatement>node);
1335            break;
1336        default:
1337            break;
1338    }
1339}
1340
1341function checkDestructuringAssignmentLhs(lhs: ts.Expression): void {
1342    let file = getSourceFileOfNode(lhs);
1343    if (ts.isArrayLiteralExpression(lhs)) {
1344        let elements = lhs.elements;
1345
1346        for (let i = 0; i < elements.length; i++) {
1347            let target = elements[i];
1348
1349            if (ts.isSpreadElement(target)) {
1350                if (i != elements.length - 1) {
1351                    throw new DiagnosticError(target, DiagnosticCode.A_rest_element_must_be_last_in_a_destructuring_pattern, file);
1352                }
1353
1354                if (elements.hasTrailingComma) {
1355                    throw new DiagnosticError(target, DiagnosticCode.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, file);
1356                }
1357
1358                if (ts.isArrayLiteralExpression(target.expression) || ts.isObjectLiteralExpression(target.expression)) {
1359                    checkDestructuringAssignmentLhs(target.expression);
1360                }
1361
1362                continue;
1363            }
1364
1365            target = ts.isBinaryExpression(target) ? target.left : target;
1366
1367            if (ts.isOmittedExpression(target) || ts.isElementAccessExpression(target)) {
1368                continue;
1369            }
1370
1371            if (ts.isIdentifier(target)) {
1372                let name = jshelpers.getTextOfIdentifierOrLiteral(target);
1373
1374                if (name === MandatoryArguments || name === "eval") {
1375                    throw new DiagnosticError(target, DiagnosticCode.Property_destructuring_pattern_expected, file);
1376                }
1377                continue;
1378            }
1379
1380            if (ts.isPropertyAccessExpression(target)) {
1381                if (target.questionDotToken) {
1382                    throw new DiagnosticError(target, DiagnosticCode.Property_destructuring_pattern_expected, file);
1383                }
1384
1385                continue;
1386            }
1387
1388            if (ts.isArrayLiteralExpression(target) || ts.isObjectLiteralExpression(target)) {
1389                checkDestructuringAssignmentLhs(target);
1390                continue;
1391            }
1392
1393            throw new DiagnosticError(target, DiagnosticCode.Property_destructuring_pattern_expected, file);
1394        }
1395    }
1396
1397    if (ts.isObjectLiteralExpression(lhs)) {
1398        let elements = lhs.properties;
1399
1400        for (let i = 0; i < elements.length; i++) {
1401            let element = elements[i];
1402
1403            if (ts.isSpreadAssignment(element)) {
1404                if (i != elements.length - 1) {
1405                    let file = getSourceFileOfNode(lhs);
1406                    throw new DiagnosticError(element, DiagnosticCode.A_rest_element_must_be_last_in_a_destructuring_pattern, file);
1407                }
1408                continue;
1409            }
1410
1411            if (ts.isPropertyAssignment(element)) {
1412                let target = ts.isBinaryExpression(element.initializer) ? element.initializer.left : element.initializer;
1413
1414                if (ts.isIdentifier(target) ||
1415                    ts.isElementAccessExpression(target)) {
1416                    continue;
1417                }
1418
1419                if (ts.isPropertyAccessExpression(target)) {
1420                    if (target.questionDotToken) {
1421                        throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1422                    }
1423                    continue;
1424                }
1425
1426                if (ts.isObjectLiteralExpression(target) || ts.isArrayLiteralExpression(target)) {
1427                    checkDestructuringAssignmentLhs(target);
1428                    continue;
1429                }
1430
1431                throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1432            }
1433
1434            if (ts.isShorthandPropertyAssignment(element)) {
1435                let name = jshelpers.getTextOfIdentifierOrLiteral(element.name);
1436
1437                if (name === MandatoryArguments || name === "eval") {
1438                    throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1439                }
1440
1441                continue;
1442            }
1443
1444            if (ts.isMethodDeclaration(element) ||
1445                ts.isGetAccessorDeclaration(element) ||
1446                ts.isSetAccessorDeclaration(element)) {
1447                throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1448            }
1449        }
1450    }
1451}
1452
1453function checkBindingPattern(node: ts.BindingPattern): void {
1454    let elements = node.elements;
1455
1456    for (let i = 0; i < elements.length; i++) {
1457        let element = elements[i];
1458
1459        if (ts.isOmittedExpression(element)) {
1460            continue;
1461        }
1462
1463        if (element.dotDotDotToken) {
1464            let file = getSourceFileOfNode(node);
1465
1466            if (i != elements.length - 1) {
1467                throw new DiagnosticError(element, DiagnosticCode.A_rest_element_must_be_last_in_a_destructuring_pattern, file);
1468            }
1469
1470            if (element.initializer) {
1471                throw new DiagnosticError(element, DiagnosticCode.A_rest_parameter_cannot_have_an_initializer);
1472            }
1473        }
1474    }
1475}
1476