• 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) {
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) {
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) {
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>) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
273    checkSyntaxErrorForSloppyAndStrictMode(node);
274    if (isStrictMode(node) || CmdOptions.isModules()) {
275        checkSyntaxErrorForStrictMode(node, scope);
276    }
277}
278
279function checkBreakOrContinueStatement(node: ts.BreakOrContinueStatement) {
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, jshelpers.getSourceFileOfNode(curNode));
306                    }
307
308                    return;
309                }
310                break;
311            }
312            default: {
313                if (jshelpers.isIterationStatement(curNode, /*lookInLabeledStatement*/ false) && !node.label) {
314                    // unlabeled break or continue within iteration statement - ok
315                    return false;
316                }
317                break;
318            }
319        }
320
321        curNode = curNode.parent;
322    }
323
324    let diagnosticCode;
325
326    if (node.label) {
327        if (node.kind == ts.SyntaxKind.BreakStatement) {
328            diagnosticCode = DiagnosticCode.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement;
329        } else {
330            diagnosticCode = DiagnosticCode.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement;
331        }
332    } else {
333        if (node.kind == ts.SyntaxKind.BreakStatement) {
334            diagnosticCode = DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement;
335        } else {
336            diagnosticCode = DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement;
337        }
338    }
339
340    throw new DiagnosticError(node, diagnosticCode, jshelpers.getSourceFileOfNode(node));
341}
342
343function checkReturnStatement(node: ts.ReturnStatement) {
344    let func = jshelpers.getContainingFunction(node);
345    if (!func) {
346        let file = jshelpers.getSourceFileOfNode(node);
347        throw new DiagnosticError(node, DiagnosticCode.A_return_statement_can_only_be_used_within_a_function_body, file);
348    }
349}
350
351function checkMetaProperty(node: ts.MetaProperty) {
352    let text = jshelpers.getTextOfIdentifierOrLiteral(node.name);
353    let file = jshelpers.getSourceFileOfNode(node);
354    switch (node.keywordToken) {
355        case ts.SyntaxKind.NewKeyword: {
356            let args = [text, jshelpers.tokenToString(node.keywordToken), "target"];
357            if (text != "target") {
358                throw new DiagnosticError(node, DiagnosticCode._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, file, args);
359            }
360
361            let func = getContainingFunctionDeclaration(node);
362            if (!func) {
363                throw new DiagnosticError(node, DiagnosticCode.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, file, args);
364            } else {
365                if (ts.isMethodDeclaration(func)) {
366                    throw new DiagnosticError(node, DiagnosticCode.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, file, args);
367                }
368                if (ts.isArrowFunction(func) && !jshelpers.getNewTargetContainer(node)) {
369                    throw new DiagnosticError(node, DiagnosticCode.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, file, args);
370                }
371            }
372            break;
373        }
374        case ts.SyntaxKind.ImportKeyword: {
375            if (text != "meta") {
376                let args = [text, jshelpers.tokenToString(node.keywordToken), "meta"];
377                throw new DiagnosticError(node, DiagnosticCode._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, file, args);
378            }
379            break;
380        }
381        default:
382            break;
383    }
384}
385
386function checkNameInLetOrConstDeclarations(name: ts.Identifier | ts.BindingPattern) {
387    if (name.kind === ts.SyntaxKind.Identifier) {
388        if (name.originalKeywordKind === ts.SyntaxKind.LetKeyword) {
389            let file = jshelpers.getSourceFileOfNode(name);
390            throw new DiagnosticError(name, DiagnosticCode.The_let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations, file);
391        }
392    } else {
393        let elements = name.elements;
394        for (let element of elements) {
395            if (!ts.isOmittedExpression(element)) {
396                checkNameInLetOrConstDeclarations(element.name);
397            }
398        }
399    }
400}
401
402function checkDisallowedLetOrConstStatement(node: ts.VariableStatement) {
403    if (allowLetAndConstDeclarations(node.parent)) {
404        return;
405    }
406
407    if (jshelpers.isLet(node.declarationList)) {
408        throw new DiagnosticError(node, DiagnosticCode.The_let_declarations_can_only_be_declared_inside_a_block);
409    }
410
411    if (jshelpers.isVarConst(node.declarationList)) {
412        throw new DiagnosticError(node, DiagnosticCode.The_const_declarations_can_only_be_declared_inside_a_block);
413    }
414}
415
416function checkVariableDeclaration(node: ts.VariableDeclaration) {
417    let file = jshelpers.getSourceFileOfNode(node);
418    if (!ts.isForInStatement(node.parent.parent) && !ts.isForOfStatement(node.parent.parent) && !ts.isCatchClause(node.parent)) {
419        if (!node.initializer) {
420            if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
421                throw new DiagnosticError(node, DiagnosticCode.A_destructuring_declaration_must_have_an_initializer, file);
422            }
423
424            if (jshelpers.isVarConst(node)) {
425                throw new DiagnosticError(node, DiagnosticCode.The_const_declarations_must_be_initialized, file);
426            }
427        }
428    }
429
430    if (node.exclamationToken && (node.parent.parent.kind !== ts.SyntaxKind.VariableStatement || !node.type || node.initializer)) {
431        if (node.initializer) {
432            throw new DiagnosticError(node.exclamationToken, DiagnosticCode.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions, file);
433        } else {
434            throw new DiagnosticError(node.exclamationToken, DiagnosticCode.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations, file);
435        }
436    }
437
438    if (jshelpers.isLet(node) || jshelpers.isVarConst(node)) {
439        checkNameInLetOrConstDeclarations(node.name);
440        if (!isInBlockScope(node.parent.parent.parent)
441            && !ts.isForInStatement(node.parent.parent)
442            && !ts.isForOfStatement(node.parent.parent)
443            && !ts.isForStatement(node.parent.parent)) {
444            throw new DiagnosticError(node, DiagnosticCode.const_and_let_declarations_not_allowed_in_statement_positions, file);
445        }
446    }
447}
448
449function checkDecorators(node: ts.Node) {
450    if (!node.decorators) {
451        return;
452    }
453
454    let file = jshelpers.getSourceFileOfNode(node);
455    if (!jshelpers.nodeCanBeDecorated(node, node.parent, node.parent.parent)) {
456        if (ts.isMethodDeclaration(node) && !jshelpers.nodeIsPresent((<ts.MethodDeclaration>node).body)) {
457            throw new DiagnosticError(node, DiagnosticCode.A_decorator_can_only_decorate_a_method_implementation_not_an_overload, file);
458        } else {
459            throw new DiagnosticError(node, DiagnosticCode.Decorators_are_not_valid_here, file);
460        }
461    } else if (ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) {
462        let accessors = jshelpers.getAllAccessorDeclarations((<ts.ClassDeclaration>node.parent).members, <ts.AccessorDeclaration>node);
463        if (accessors.firstAccessor.decorators && node === accessors.secondAccessor) {
464            throw new DiagnosticError(node, DiagnosticCode.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name, file);
465        }
466    }
467}
468
469function checkAsyncModifier(node: ts.Node, asyncModifier: ts.Node) {
470    switch (node.kind) {
471        case ts.SyntaxKind.ArrowFunction:
472        case ts.SyntaxKind.FunctionDeclaration:
473        case ts.SyntaxKind.FunctionExpression:
474        case ts.SyntaxKind.MethodDeclaration:
475            return;
476        default:
477            break;
478    }
479    let file = jshelpers.getSourceFileOfNode(node);
480    throw new DiagnosticError(asyncModifier, DiagnosticCode._0_modifier_cannot_be_used_here, file, ["async"])
481}
482
483function checkModifiers(node: ts.Node) {
484    if (!node.modifiers) {
485        return;
486    }
487
488    let lastStatic: ts.Node | undefined;
489    let lastDeclare: ts.Node | undefined;
490    let lastAsync: ts.Node | undefined;
491    let lastReadonly: ts.Node | undefined;
492    let flags = ts.ModifierFlags.None;
493    let file = jshelpers.getSourceFileOfNode(node);
494
495    for (let modifier of node.modifiers!) {
496        if (modifier.kind !== ts.SyntaxKind.ReadonlyKeyword) {
497            if (ts.isPropertySignature(node) || ts.isMethodSignature(node)) {
498                throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_type_member, file, [jshelpers.tokenToString(modifier.kind)]);
499            }
500            if (ts.isIndexSignatureDeclaration(node)) {
501                throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_an_index_signature, file, [jshelpers.tokenToString(modifier.kind)]);
502            }
503        }
504        switch (modifier.kind) {
505            case ts.SyntaxKind.ConstKeyword: {
506                if (ts.isEnumDeclaration(node)) {
507                    throw new DiagnosticError(node, DiagnosticCode.A_class_member_cannot_have_the_0_keyword, file, [jshelpers.tokenToString(ts.SyntaxKind.ConstKeyword)]);
508                }
509                break;
510            }
511            case ts.SyntaxKind.PublicKeyword:
512            case ts.SyntaxKind.ProtectedKeyword:
513            case ts.SyntaxKind.PrivateKeyword: {
514                const text = visibilityToString(jshelpers.modifierToFlag(modifier.kind));
515
516                if (flags & ts.ModifierFlags.AccessibilityModifier) {
517                    throw new DiagnosticError(modifier, DiagnosticCode.Accessibility_modifier_already_seen, file);
518                } else if (flags & ts.ModifierFlags.Static) {
519                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "static"]);
520                } else if (flags & ts.ModifierFlags.Readonly) {
521                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "readonly"]);
522                } else if (flags & ts.ModifierFlags.Async) {
523                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "async"]);
524                } else if (ts.isModuleBlock(node.parent) || ts.isSourceFile(node.parent)) {
525                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_module_or_namespace_element, file, [text]);
526                } else if (flags & ts.ModifierFlags.Abstract) {
527                    if (modifier.kind === ts.SyntaxKind.PrivateKeyword) {
528                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, [text, "abstract"]);
529                    } else {
530                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, [text, "abstract"]);
531                    }
532                } else if (ts.isPropertyDeclaration(node) && ts.isPrivateIdentifier(node.name)) {
533                    throw new DiagnosticError(modifier, DiagnosticCode.An_accessibility_modifier_cannot_be_used_with_a_private_identifier, file);
534                }
535                flags |= jshelpers.modifierToFlag(modifier.kind);
536                break;
537            }
538            case ts.SyntaxKind.StaticKeyword: {
539                if (flags & ts.ModifierFlags.Static) {
540                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["static"]);
541                } else if (flags & ts.ModifierFlags.Readonly) {
542                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["static", "readonly"]);
543                } else if (flags & ts.ModifierFlags.Async) {
544                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["static", "async"]);
545                } else if (ts.isModuleBlock(node.parent) || ts.isSourceFile(node.parent)) {
546                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_module_or_namespace_element, file, ["static"]);
547                } else if (ts.isParameter(node)) {
548                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["static"]);
549                } else if (flags & ts.ModifierFlags.Abstract) {
550                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["static", "abstract"]);
551                } else if (ts.isPropertyDeclaration(node) && ts.isPrivateIdentifier(node.name)) {
552                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_a_private_identifier, file, ["static"]);
553                }
554                flags |= ts.ModifierFlags.Static;
555                lastStatic = modifier;
556                break;
557            }
558            case ts.SyntaxKind.ReadonlyKeyword: {
559                if (flags & ts.ModifierFlags.Readonly) {
560                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["readonly"]);
561                } else if (!ts.isPropertyDeclaration(node) && !ts.isPropertySignature(node) && !ts.isIndexSignatureDeclaration(node) && !ts.isParameter(node)) {
562                    // If node.kind === SyntaxKind.Parameter, checkParameter report an error if it's not a parameter property.
563                    throw new DiagnosticError(modifier, DiagnosticCode.The_readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature, file);
564                }
565                flags |= ts.ModifierFlags.Readonly;
566                lastReadonly = modifier;
567                break;
568            }
569            case ts.SyntaxKind.ExportKeyword: {
570                if (flags & ts.ModifierFlags.Export) {
571                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["export"]);
572                } else if (flags & ts.ModifierFlags.Ambient) {
573                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["export", "declare"]);
574                } else if (flags & ts.ModifierFlags.Abstract) {
575                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["export", "abstract"]);
576                } else if (flags & ts.ModifierFlags.Async) {
577                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, file, ["export", "async"]);
578                } else if (ts.isClassLike(node.parent)) {
579                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_class_elements_of_this_kind, file, ["export"]);
580                } else if (ts.isParameter(node)) {
581                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["export"]);
582                }
583                flags |= ts.ModifierFlags.Export;
584                break;
585            }
586            case ts.SyntaxKind.DefaultKeyword: {
587                let container = ts.isSourceFile(node.parent) ? node.parent : node.parent.parent;
588                if (ts.isModuleDeclaration(container) && !jshelpers.isAmbientModule(container)) {
589                    throw new DiagnosticError(modifier, DiagnosticCode.A_default_export_can_only_be_used_in_an_ECMAScript_style_module, file);
590                }
591
592                flags |= ts.ModifierFlags.Default;
593                break;
594            }
595            case ts.SyntaxKind.DeclareKeyword: {
596                if (flags & ts.ModifierFlags.Ambient) {
597                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["declare"]);
598                } else if (flags & ts.ModifierFlags.Async) {
599                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_in_an_ambient_context, file, ["async"]);
600                } else if (ts.isClassLike(node.parent) && !ts.isPropertyDeclaration(node)) {
601                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_class_elements_of_this_kind, file, ["declare"]);
602                } else if (ts.isParameter(node)) {
603                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["declare"]);
604                } else if (ts.isPropertyDeclaration(node) && ts.isPrivateIdentifier(node.name)) {
605                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_a_private_identifier, file, ["declare"]);
606                }
607                flags |= ts.ModifierFlags.Ambient;
608                lastDeclare = modifier;
609                break;
610            }
611            case ts.SyntaxKind.AbstractKeyword: {
612                if (flags & ts.ModifierFlags.Abstract) {
613                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["abstract"]);
614                }
615                if (ts.isClassDeclaration(node) && ts.isConstructorTypeNode(node)) {
616                    if (!ts.isMethodDeclaration(node) && !ts.isPropertyDeclaration(node) && !ts.isGetAccessorDeclaration(node) && !ts.isSetAccessorDeclaration(node)) {
617                        throw new DiagnosticError(modifier, DiagnosticCode.The_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration, file);
618                    }
619                    if (flags & ts.ModifierFlags.Static) {
620                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["static", "abstract"]);
621                    }
622                    if (flags & ts.ModifierFlags.Private) {
623                        throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["private", "abstract"]);
624                    }
625                    if (flags & ts.ModifierFlags.Async && lastAsync) {
626                        throw new DiagnosticError(lastAsync, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["async", "abstract"]);
627                    }
628                }
629                let name = (<ts.NamedDeclaration>node).name;
630                if (name && ts.isPrivateIdentifier(name)) {
631                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_a_private_identifier, file, ["abstract"]);
632                }
633
634                flags |= ts.ModifierFlags.Abstract;
635                break;
636            }
637            case ts.SyntaxKind.AsyncKeyword: {
638                if (flags & ts.ModifierFlags.Async) {
639                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_already_seen, file, ["async"]);
640                } else if (flags & ts.ModifierFlags.Ambient) {
641                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_in_an_ambient_context, file, ["async"]);
642                } else if (ts.isParameter(node)) {
643                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, file, ["async"]);
644                }
645                if (flags & ts.ModifierFlags.Abstract) {
646                    throw new DiagnosticError(modifier, DiagnosticCode._0_modifier_cannot_be_used_with_1_modifier, file, ["async", "abstract"]);
647                }
648                flags |= ts.ModifierFlags.Async;
649                lastAsync = modifier;
650                break;
651            }
652            default:
653                break;
654        }
655    }
656
657    if (ts.isConstructorDeclaration(node)) {
658        if (flags & ts.ModifierFlags.Static) {
659            throw new DiagnosticError(lastStatic!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["static"]);
660        }
661        if (flags & ts.ModifierFlags.Abstract) {
662            throw new DiagnosticError(lastStatic!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["abstract"]);
663        } else if (flags & ts.ModifierFlags.Async) {
664            throw new DiagnosticError(lastAsync!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["async"]);
665        } else if (flags & ts.ModifierFlags.Readonly) {
666            throw new DiagnosticError(lastReadonly!, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, file, ["readonly"]);
667        }
668    } else if ((ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node)) && flags & ts.ModifierFlags.Ambient) {
669        throw new DiagnosticError(lastDeclare!, DiagnosticCode.A_0_modifier_cannot_be_used_with_an_import_declaration, file, ["declare"]);
670    } else if (ts.isParameter(node) && (flags & ts.ModifierFlags.ParameterPropertyModifier) && isBindingPattern((<ts.ParameterDeclaration>node).name)) {
671        throw new DiagnosticError(node, DiagnosticCode.A_parameter_property_may_not_be_declared_using_a_binding_pattern, file);
672    } else if (ts.isParameter(node) && (flags & ts.ModifierFlags.ParameterPropertyModifier) && (<ts.ParameterDeclaration>node).dotDotDotToken) {
673        throw new DiagnosticError(node, DiagnosticCode.A_parameter_property_cannot_be_declared_using_a_rest_parameter, file);
674    }
675
676    if (flags & ts.ModifierFlags.Async) {
677        checkAsyncModifier(node, lastAsync!);
678    }
679}
680
681function checkVariableDeclarationList(declarationList: ts.VariableDeclarationList) {
682    let declarations = declarationList.declarations;
683    if (!declarations.length) {
684        throw new DiagnosticError(declarationList, DiagnosticCode.Identifier_expected);
685    }
686
687    let decl = declarations[0].name;
688    if (isBindingPattern(decl)) {
689        checkBindingPattern(<ts.BindingPattern>decl);
690    }
691}
692
693function checkVariableStatement(node: ts.VariableStatement) {
694    checkDecorators(node);
695    checkModifiers(node);
696    checkVariableDeclarationList(node.declarationList);
697    checkDisallowedLetOrConstStatement(node);
698}
699
700function checkForInOrForOfStatement(stmt: ts.ForInOrOfStatement) {
701    let file = jshelpers.getSourceFileOfNode(stmt);
702    let leftExpr = stmt.initializer;
703    if (ts.isParenthesizedExpression(leftExpr)) {
704        leftExpr = findInnerExprOfParenthesis(leftExpr);
705    }
706    if (ts.isVariableDeclarationList(leftExpr)) {
707        let variableList = <ts.VariableDeclarationList>leftExpr;
708        checkVariableDeclarationList(variableList);
709        let declarations = variableList.declarations;
710
711        if (declarations.length > 1) {
712            if (ts.isForInStatement(stmt)) {
713                throw new DiagnosticError(variableList.declarations[1], DiagnosticCode.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement, file);
714            } else {
715                throw new DiagnosticError(variableList.declarations[1], DiagnosticCode.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement, file);
716            }
717        }
718
719        if (declarations[0].initializer) {
720            if (ts.isForInStatement(stmt)) {
721                throw new DiagnosticError(declarations[0].name, DiagnosticCode.The_variable_declaration_of_a_for_in_statement_cannot_have_an_initializer, file);
722            } else {
723                throw new DiagnosticError(declarations[0].name, DiagnosticCode.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer, file);
724            }
725        }
726
727        if (declarations[0].type) {
728            if (ts.isForInStatement(stmt)) {
729                throw new DiagnosticError(declarations[0], DiagnosticCode.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation, file);
730            } else {
731                throw new DiagnosticError(declarations[0], DiagnosticCode.The_left_hand_side_of_a_for_of_statement_cannot_use_a_type_annotation, file);
732            }
733        }
734    } else {
735        isInVaildAssignmentLeftSide(<ts.Expression>leftExpr);
736
737        if (ts.isArrayLiteralExpression(leftExpr) || ts.isObjectLiteralExpression(leftExpr)) {
738            checkDestructuringAssignmentLhs(leftExpr);
739        }
740    }
741}
742
743function checkForInOrForOfVariableDeclaration(iterationStatement: ts.ForInOrOfStatement) {
744    let variableDeclarationList = <ts.VariableDeclarationList>iterationStatement.initializer;
745    // checkGrammarForInOrForOfStatement will check that there is exactly one declaration.
746    if (variableDeclarationList.declarations.length >= 1) {
747        checkVariableDeclaration(variableDeclarationList.declarations[0]);
748    }
749}
750
751function checkForInStatement(node: ts.ForInStatement) {
752    checkForInOrForOfStatement(node);
753
754    let file = jshelpers.getSourceFileOfNode(node);
755    // for (let VarDecl in Expr) Statement
756    if (ts.isVariableDeclarationList(node.initializer)) {
757        checkForInOrForOfVariableDeclaration(node);
758    } else {
759        let varExpr = node.initializer;
760        if (ts.isArrayLiteralExpression(varExpr) || ts.isObjectLiteralExpression(varExpr)) {
761            throw new DiagnosticError(varExpr, DiagnosticCode.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern, file);
762        }
763    }
764}
765
766const enum OuterExpressionKinds {
767    Parentheses = 1 << 0,
768    TypeAssertions = 1 << 1,
769    NonNullAssertions = 1 << 2,
770    PartiallyEmittedExpressions = 1 << 3,
771    Assertions = TypeAssertions | NonNullAssertions,
772    All = Parentheses | Assertions | PartiallyEmittedExpressions
773}
774
775function checkReferenceExpression(expr: ts.Expression, invalidReferenceCode: DiagnosticCode, invalidOptionalChainCode: DiagnosticCode) {
776    let node = jshelpers.skipOuterExpressions(expr, OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses);
777    if (node.kind !== ts.SyntaxKind.Identifier && node.kind !== ts.SyntaxKind.PropertyAccessExpression && node.kind !== ts.SyntaxKind.ElementAccessExpression) {
778        throw new DiagnosticError(expr, invalidReferenceCode);
779    }
780
781    if (node.flags & ts.NodeFlags.OptionalChain) {
782        throw new DiagnosticError(expr, invalidOptionalChainCode);
783    }
784}
785
786function checkReferenceAssignment(node: ts.Expression) {
787    let invalidReferenceCode: DiagnosticCode;
788    let invalidOptionalChainCode: DiagnosticCode;
789
790    if (ts.isSpreadAssignment(node.parent)) {
791        invalidReferenceCode = DiagnosticCode.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access;
792        invalidOptionalChainCode = DiagnosticCode.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access;
793    } else {
794        invalidReferenceCode = DiagnosticCode.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access;
795        invalidOptionalChainCode = DiagnosticCode.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access;
796    }
797
798    checkReferenceExpression(node, invalidReferenceCode, invalidOptionalChainCode);
799}
800
801function checkDestructuringAssignment(node: ts.Expression | ts.ShorthandPropertyAssignment) {
802    let target: ts.Expression;
803    if (ts.isShorthandPropertyAssignment(node)) {
804        let prop = <ts.ShorthandPropertyAssignment>node;
805        target = prop.name;
806    } else {
807        target = node;
808    }
809
810    if (ts.isBinaryExpression(target) && (<ts.BinaryExpression>target).operatorToken.kind === ts.SyntaxKind.EqualsToken) {
811        checkBinaryExpression(<ts.BinaryExpression>target);
812        target = (<ts.BinaryExpression>target).left;
813    }
814
815    if (ts.isObjectLiteralExpression(target)) {
816        checkObjectLiteralExpression(target);
817    }
818
819    checkReferenceAssignment(target);
820
821}
822
823function checkForOfStatement(node: ts.ForOfStatement) {
824    checkForInOrForOfStatement(node);
825
826    if (ts.isVariableDeclarationList(node.initializer)) {
827        checkForInOrForOfVariableDeclaration(node);
828    } else {
829        let varExpr = node.initializer;
830
831        if (ts.isArrayLiteralExpression(varExpr) || ts.isObjectLiteralExpression(varExpr)) {
832            checkDestructuringAssignment(varExpr);
833        } else {
834            checkReferenceExpression(
835                varExpr,
836                DiagnosticCode.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access,
837                DiagnosticCode.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access);
838        }
839    }
840}
841
842function checkClassDeclaration(node: ts.ClassLikeDeclaration) {
843    checkClassDeclarationHeritageClauses(node);
844    let hasConstructorImplementation = false;
845    let file = jshelpers.getSourceFileOfNode(node);
846    node.members.forEach(member => {
847        switch (member.kind) {
848            case ts.SyntaxKind.Constructor: {
849                if (hasConstructorImplementation) {
850                    throw new DiagnosticError(node, DiagnosticCode.Multiple_constructor_implementations_are_not_allowed, file);
851                } else {
852                    hasConstructorImplementation = true;
853                }
854                break;
855            }
856            case ts.SyntaxKind.MethodDeclaration:
857            case ts.SyntaxKind.SetAccessor:
858                checkFunctionLikeDeclaration(<ts.FunctionLikeDeclaration | ts.MethodSignature>member);
859                break;
860            case ts.SyntaxKind.GetAccessor:
861                checkGetAccessor(<ts.GetAccessorDeclaration>member);
862                break;
863            default:
864                break;
865        }
866    });
867
868    // Class declaration not allowed in statement position
869    if (isStatement(node.parent.kind)) {
870        throw new DiagnosticError(node, DiagnosticCode.Class_declaration_not_allowed_in_statement_position, file);
871    }
872
873}
874
875function checkClassDeclarationHeritageClauses(node: ts.ClassLikeDeclaration) {
876    let hasExtendsKeyWords = false;
877    checkDecorators(node);
878    checkModifiers(node);
879    if (node.heritageClauses == undefined) {
880        return;
881    }
882
883    let file = jshelpers.getSourceFileOfNode(node);
884    for (let heritageClause of node.heritageClauses) {
885        if (heritageClause.token == ts.SyntaxKind.ExtendsKeyword) {
886            if (hasExtendsKeyWords) {
887                throw new DiagnosticError(heritageClause, DiagnosticCode.The_extends_clause_already_seen, file);
888            }
889
890            if (heritageClause.types.length > 1) {
891                throw new DiagnosticError(heritageClause, DiagnosticCode.Classes_can_only_extend_a_single_class);
892            }
893            hasExtendsKeyWords = true;
894        }
895    }
896}
897
898function checkBinaryExpression(node: ts.BinaryExpression) {
899    // AssignmentExpression
900    if (isAssignmentOperator(node.operatorToken.kind)) {
901        let leftExpr: ts.Expression = node.left;
902        if (ts.isParenthesizedExpression(leftExpr)) {
903            leftExpr = findInnerExprOfParenthesis(leftExpr);
904        }
905
906        if (node.operatorToken.kind == ts.SyntaxKind.EqualsToken) {
907            if (ts.isArrayLiteralExpression(leftExpr) || ts.isObjectLiteralExpression(leftExpr)) {
908                checkDestructuringAssignmentLhs(leftExpr);
909            }
910        }
911
912        isInVaildAssignmentLeftSide(leftExpr);
913    }
914}
915
916function isInVaildAssignmentLeftSide(leftExpr: ts.Expression) {
917    if (jshelpers.isKeyword(leftExpr.kind)
918        || leftExpr.kind == ts.SyntaxKind.NumericLiteral
919        || leftExpr.kind == ts.SyntaxKind.StringLiteral) {
920        throw new DiagnosticError(leftExpr, DiagnosticCode.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access);
921    }
922}
923
924
925function checkContextualIdentifier(node: ts.Identifier) {
926    if (jshelpers.isIdentifierName(node)) {
927        return;
928    }
929
930    let file = jshelpers.getSourceFileOfNode(node);
931    if (node.originalKeywordKind === ts.SyntaxKind.AwaitKeyword) {
932        if (jshelpers.isExternalOrCommonJsModule(file) && jshelpers.isInTopLevelContext(node)) {
933            throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, file, jshelpers.declarationNameToString(node));
934        } else if (node.flags & ts.NodeFlags.AwaitContext) {
935            throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, file, jshelpers.declarationNameToString(node));
936        }
937    } else if (node.originalKeywordKind === ts.SyntaxKind.YieldKeyword && node.flags & ts.NodeFlags.YieldContext) {
938        throw new DiagnosticError(node, DiagnosticCode.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, file, jshelpers.declarationNameToString(node));
939    }
940}
941
942function checkComputedPropertyName(node: ts.Node) {
943    if (!ts.isComputedPropertyName(node)) {
944        return;
945    }
946
947    let expression = node.expression;
948    if (ts.isBinaryExpression(expression) && expression.operatorToken.kind === ts.SyntaxKind.CommaToken) {
949        let file = jshelpers.getSourceFileOfNode(node);
950        throw new DiagnosticError(expression, DiagnosticCode.A_comma_expression_is_not_allowed_in_a_computed_property_name, file);
951    }
952}
953
954const enum DeclarationMeaning {
955    GetAccessor = 1,
956    SetAccessor = 2,
957    PropertyAssignment = 4,
958    Method = 8,
959    GetOrSetAccessor = GetAccessor | SetAccessor,
960    PropertyAssignmentOrMethod = PropertyAssignment | Method,
961}
962
963function checkObjectLiteralExpression(node: ts.ObjectLiteralExpression) {
964    let inDestructuring = jshelpers.isAssignmentTarget(node);
965    let file = jshelpers.getSourceFileOfNode(node);
966    let seen = new Map<ts.__String, DeclarationMeaning>();
967
968    for (let prop of node.properties) {
969        if (ts.isSpreadAssignment(prop)) {
970            if (inDestructuring) {
971                let expression = jshelpers.skipParentheses(prop.expression);
972                if (ts.isArrayLiteralExpression(expression) || ts.isObjectLiteralExpression(expression)) {
973                    throw new DiagnosticError(prop.expression, DiagnosticCode.A_rest_element_cannot_contain_a_binding_pattern, file);
974                }
975            }
976            continue;
977        }
978        let name = prop.name;
979        if (ts.isComputedPropertyName(name)) {
980            checkComputedPropertyName(name);
981        }
982
983        if (ts.isShorthandPropertyAssignment(prop) && !inDestructuring && prop.objectAssignmentInitializer) {
984            throw new DiagnosticError(prop.equalsToken!, 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, file);
985        }
986
987        if (ts.isPrivateIdentifier(name)) {
988            throw new DiagnosticError(name, DiagnosticCode.Private_identifiers_are_not_allowed_outside_class_bodies, file);
989        }
990
991        if (prop.modifiers) {
992            for (let mod of prop.modifiers) {
993                if (!ts.isMethodDeclaration(prop) || mod.kind != ts.SyntaxKind.AsyncKeyword) {
994                    throw new DiagnosticError(mod, DiagnosticCode._0_modifier_cannot_be_used_here, file, [jshelpers.getTextOfNode(mod)]);
995                }
996            }
997        }
998
999        /**
1000        * It is a Syntax Error if PropertyNameList of PropertyDefinitionList contains any duplicate entries for "__proto__" and
1001        * at least two of those entries were obtained from productions of the form
1002        * PropertyDefinition : PropertyName : AssignmentExpression .
1003        */
1004        let curKind = getPropertieDeclaration(prop, name);
1005        if (!curKind) continue;
1006        if (!inDestructuring) {
1007            let effectName = jshelpers.getPropertyNameForPropertyNameNode(name);
1008            if (!effectName || ts.isComputedPropertyName(name)) continue;
1009            let existKind = seen.get(effectName);
1010            if (!existKind) {
1011                seen.set(effectName, curKind);
1012            } else {
1013                if ((curKind & DeclarationMeaning.PropertyAssignmentOrMethod) && (existKind & DeclarationMeaning.PropertyAssignmentOrMethod)) {
1014                    if (effectName === "___proto__") {
1015                        throw new DiagnosticError(name, DiagnosticCode.Duplicate_identifier_0, file, [jshelpers.getTextOfNode(name)]);
1016                    }
1017                }
1018            }
1019        }
1020    }
1021}
1022
1023function checkInvalidExclamationToken(exclamationToken: ts.ExclamationToken | undefined) {
1024    if (!!exclamationToken) {
1025        let file = jshelpers.getSourceFileOfNode(exclamationToken);
1026        throw new DiagnosticError(exclamationToken, DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context, file);
1027    }
1028}
1029
1030function checkInvalidQuestionMark(questionToken: ts.QuestionToken | undefined) {
1031    if (!!questionToken) {
1032        let file = jshelpers.getSourceFileOfNode(questionToken);
1033        throw new DiagnosticError(questionToken, DiagnosticCode.An_object_member_cannot_be_declared_optional, file);
1034    }
1035}
1036
1037// @ts-ignore
1038function getPropertieDeclaration(node: ts.Node, name: ts.Node) {
1039    let decl = undefined;
1040    if (ts.isShorthandPropertyAssignment(node)) {
1041        checkInvalidExclamationToken(node.exclamationToken);
1042    } else if (ts.isPropertyAssignment(node)) {
1043        checkInvalidQuestionMark(node.questionToken);
1044        decl = DeclarationMeaning.PropertyAssignment;
1045    } else if (ts.isMethodDeclaration(node)) {
1046        decl = DeclarationMeaning.Method;
1047    } else if (ts.isGetAccessor(node)) {
1048        checkGetAccessor(node);
1049        decl = DeclarationMeaning.GetAccessor;
1050    } else if (ts.isSetAccessor(node)) {
1051        decl = DeclarationMeaning.SetAccessor;
1052    } else {
1053        LOGE("Unexpected syntax kind:" + node.kind);
1054    }
1055    return decl;
1056}
1057
1058function checkDisallowedTrailingComma(list: ts.NodeArray<ts.Node> | undefined) {
1059    if (list && list.hasTrailingComma) {
1060        let file = jshelpers.getSourceFileOfNode(list[0]);
1061        throw new DiagnosticError(list[0], DiagnosticCode.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, file);
1062    }
1063}
1064
1065function checkParameters(parameters: ts.NodeArray<ts.ParameterDeclaration>) {
1066    let count = parameters.length;
1067    let optionalParameter = false;
1068
1069    for (let i = 0; i < count; i++) {
1070        let parameter = parameters[i];
1071        let file = jshelpers.getSourceFileOfNode(parameter);
1072        if (parameter.dotDotDotToken) {
1073            if (i != count - 1) {
1074                throw new DiagnosticError(parameter.dotDotDotToken, DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list, file);
1075            }
1076
1077            checkDisallowedTrailingComma(parameters);
1078
1079            if (parameter.initializer) {
1080                throw new DiagnosticError(parameter.name, DiagnosticCode.A_rest_parameter_cannot_have_an_initializer, file);
1081            }
1082
1083            if (parameter.questionToken) {
1084                throw new DiagnosticError(parameter.questionToken, DiagnosticCode.A_rest_parameter_cannot_be_optional, file);
1085            }
1086
1087        } else if (isOptionalParameter(parameter)) {
1088            optionalParameter = true;
1089            if (parameter.questionToken && parameter.initializer) {
1090                throw new DiagnosticError(parameter.name, DiagnosticCode.Parameter_cannot_have_question_mark_and_initializer, file);
1091            }
1092        }
1093        else if (optionalParameter && !parameter.initializer) {
1094            throw new DiagnosticError(parameter.name, DiagnosticCode.A_required_parameter_cannot_follow_an_optional_parameter, file);
1095        }
1096    }
1097}
1098
1099function checkArrowFunction(node: ts.Node) {
1100    if (!ts.isArrowFunction(node)) {
1101        return;
1102    }
1103
1104    const { equalsGreaterThanToken } = node;
1105    let file = jshelpers.getSourceFileOfNode(node);
1106    const startLine = file.getLineAndCharacterOfPosition(equalsGreaterThanToken.pos).line;
1107    const endLine = file.getLineAndCharacterOfPosition(equalsGreaterThanToken.end).line;
1108    if (startLine !== endLine) {
1109        throw new DiagnosticError(equalsGreaterThanToken, DiagnosticCode.Line_terminator_not_permitted_before_arrow, file);
1110    }
1111}
1112
1113function checkFunctionLikeDeclaration(node: ts.FunctionLikeDeclaration | ts.MethodSignature) {
1114    checkDecorators(node);
1115    checkModifiers(node);
1116    checkParameters(node.parameters);
1117    checkArrowFunction(node);
1118}
1119
1120function checkLabeledStatement(node: ts.LabeledStatement) {
1121    let file = jshelpers.getSourceFileOfNode(node);
1122    jshelpers.findAncestor(node.parent, current => {
1123        if (jshelpers.isFunctionLike(current)) {
1124            return "quit";
1125        }
1126
1127        if (ts.isLabeledStatement(current) && (<ts.LabeledStatement>current).label.escapedText === node.label.escapedText) {
1128            throw new DiagnosticError(node.label, DiagnosticCode.Duplicate_label_0, file, [jshelpers.getTextOfNode(node.label)]);
1129        }
1130        return false;
1131    });
1132
1133    let statement = node.statement;
1134    if (ts.isVariableStatement(statement)) {
1135        let variableStatement = <ts.VariableStatement>statement;
1136        if (jshelpers.isLet(variableStatement.declarationList)) {
1137            throw new DiagnosticError(node, DiagnosticCode.Lexical_declaration_let_not_allowed_in_statement_position);
1138        }
1139
1140        if (jshelpers.isVarConst(variableStatement.declarationList)) {
1141            throw new DiagnosticError(node, DiagnosticCode.Lexical_declaration_const_not_allowed_in_statement_position);
1142        }
1143    }
1144}
1145
1146function checkGetAccessor(node: ts.GetAccessorDeclaration) {
1147    checkFunctionLikeDeclaration(node);
1148    if (node.parameters.length != 0) {
1149        throw new DiagnosticError(node, DiagnosticCode.Getter_must_not_have_any_formal_parameters);
1150    }
1151}
1152
1153function isValidUseSuperExpression(node: ts.Node, isCallExpression: boolean): boolean {
1154    if (!node) {
1155        return false;
1156    }
1157
1158    if (isCallExpression) {
1159        return ts.isConstructorDeclaration(node);
1160    }
1161
1162    if (!ts.isClassLike(node.parent) && !ts.isObjectLiteralExpression(node.parent)) {
1163        return false;
1164    }
1165
1166    return ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node) ||
1167        ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isConstructorDeclaration(node);
1168}
1169
1170function checkSuperExpression(node: ts.SuperExpression) {
1171    let file = jshelpers.getSourceFileOfNode(node);
1172    let isCallExpression = false;
1173    if (ts.isCallExpression(node.parent) && (<ts.CallExpression>node.parent).expression === node) {
1174        isCallExpression = true;
1175    }
1176
1177    let container = jshelpers.getSuperContainer(node, true);
1178
1179    if (!isCallExpression) {
1180        while (container && ts.isArrowFunction(container)) {
1181            container = jshelpers.getSuperContainer(container, true);
1182        }
1183    }
1184
1185    let isSuperExpCanUse = isValidUseSuperExpression(container, isCallExpression);
1186
1187    if (!isSuperExpCanUse) {
1188        let current = jshelpers.findAncestor(node, n => n === container ? "quit" : ts.isComputedPropertyName(n));
1189        if (current && ts.isComputedPropertyName(current)) {
1190            throw new DiagnosticError(node, DiagnosticCode.The_super_cannot_be_referenced_in_a_computed_property_name, file);
1191        }
1192        let containerFunc = jshelpers.findAncestor(node, ts.isConstructorDeclaration);
1193        if (containerFunc) {
1194            return;
1195        }
1196        if (isCallExpression) {
1197            throw new DiagnosticError(node, DiagnosticCode.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors, file);
1198        }
1199
1200        if (!container || !container.parent || !ts.isClassLike(container.parent) || ts.isObjectLiteralExpression(container.parent)) {
1201            throw new DiagnosticError(node, DiagnosticCode.The_super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions, file);
1202        }
1203
1204        throw new DiagnosticError(node, DiagnosticCode.The_super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class, file);
1205    }
1206}
1207
1208function checkImportExpression(node: ts.ImportExpression) {
1209    let args = (<ts.CallExpression>node.parent).arguments;
1210    if (args.length != 1) {
1211        throw new DiagnosticError(node, DiagnosticCode.Dynamic_imports_can_only_accept_a_module_specifier_optional_assertion_is_not_supported_yet);
1212    }
1213
1214    args.forEach(arg => {
1215        if (ts.isSpreadElement(arg)) {
1216            throw new DiagnosticError(node, DiagnosticCode.Argument_of_dynamic_import_cannot_be_spread_element);
1217        }
1218    });
1219}
1220
1221function checkRegularExpression(regexp: ts.RegularExpressionLiteral) {
1222    let regexpText = regexp.text;
1223    let regexpParse = require("regexpp").RegExpParser;
1224    new regexpParse().parseLiteral(regexpText);
1225}
1226
1227function checkThrowStatement(node: ts.ThrowStatement) {
1228    if (ts.isIdentifier(node.expression) && (<ts.Identifier>node.expression).text === '') {
1229        throw new DiagnosticError(node, DiagnosticCode.Line_break_not_permitted_here, jshelpers.getSourceFileOfNode(node));
1230    }
1231}
1232
1233function checkSyntaxErrorForSloppyAndStrictMode(node: ts.Node) {
1234    switch (node.kind) {
1235        case ts.SyntaxKind.BreakStatement:
1236        case ts.SyntaxKind.ContinueStatement:
1237            checkBreakOrContinueStatement(<ts.BreakOrContinueStatement>node);
1238            break;
1239        case ts.SyntaxKind.ReturnStatement:
1240            checkReturnStatement(<ts.ReturnStatement>node);
1241            break;
1242        case ts.SyntaxKind.ComputedPropertyName:
1243            checkComputedPropertyName(<ts.ComputedPropertyName>node);
1244            break;
1245        case ts.SyntaxKind.ObjectBindingPattern:
1246        case ts.SyntaxKind.ArrayBindingPattern:
1247            checkBindingPattern(<ts.BindingPattern>node);
1248            break;
1249        case ts.SyntaxKind.MetaProperty:
1250            checkMetaProperty(<ts.MetaProperty>node);
1251            break;
1252        case ts.SyntaxKind.VariableDeclaration:
1253            checkVariableDeclaration(<ts.VariableDeclaration>node);
1254            break;
1255        case ts.SyntaxKind.VariableStatement:
1256            checkVariableStatement(<ts.VariableStatement>node);
1257            break;
1258        case ts.SyntaxKind.ForInStatement:
1259            checkForInStatement(<ts.ForInStatement>node);
1260            break;
1261        case ts.SyntaxKind.ForOfStatement:
1262            checkForOfStatement(<ts.ForOfStatement>node);
1263            break;
1264        case ts.SyntaxKind.ClassDeclaration:
1265        case ts.SyntaxKind.ClassExpression:
1266            checkClassDeclaration(<ts.ClassLikeDeclaration>node);
1267            break;
1268        case ts.SyntaxKind.SuperKeyword:
1269            checkSuperExpression(<ts.SuperExpression>node);
1270            break;
1271        case ts.SyntaxKind.ImportKeyword:
1272            checkImportExpression(<ts.ImportExpression>node);
1273            break;
1274        case ts.SyntaxKind.BinaryExpression:
1275            checkBinaryExpression(<ts.BinaryExpression>node);
1276            break;
1277        case ts.SyntaxKind.Identifier:
1278            checkContextualIdentifier(<ts.Identifier>node);
1279            break;
1280        case ts.SyntaxKind.ObjectLiteralExpression:
1281            checkObjectLiteralExpression(<ts.ObjectLiteralExpression>node);
1282            break;
1283        case ts.SyntaxKind.FunctionDeclaration:
1284        case ts.SyntaxKind.MethodSignature:
1285        case ts.SyntaxKind.MethodDeclaration:
1286        case ts.SyntaxKind.SetAccessor:
1287        case ts.SyntaxKind.Constructor:
1288        case ts.SyntaxKind.FunctionExpression:
1289        case ts.SyntaxKind.ArrowFunction:
1290            checkFunctionLikeDeclaration(<ts.FunctionLikeDeclaration | ts.MethodSignature>node);
1291            break;
1292        case ts.SyntaxKind.GetAccessor:
1293            checkGetAccessor(<ts.GetAccessorDeclaration>node);
1294            break;
1295        case ts.SyntaxKind.LabeledStatement:
1296            checkLabeledStatement(<ts.LabeledStatement>node);
1297            break;
1298        case ts.SyntaxKind.RegularExpressionLiteral:
1299            checkRegularExpression(<ts.RegularExpressionLiteral>node);
1300            break;
1301        case ts.SyntaxKind.ThrowStatement:
1302            checkThrowStatement(<ts.ThrowStatement>node);
1303            break;
1304        default:
1305            break;
1306    }
1307}
1308
1309function checkDestructuringAssignmentLhs(lhs: ts.Expression) {
1310    let file = getSourceFileOfNode(lhs);
1311    if (ts.isArrayLiteralExpression(lhs)) {
1312        let elements = lhs.elements;
1313
1314        for (let i = 0; i < elements.length; i++) {
1315            let target = elements[i];
1316
1317            if (ts.isSpreadElement(target)) {
1318                if (i != elements.length - 1) {
1319                    throw new DiagnosticError(target, DiagnosticCode.A_rest_element_must_be_last_in_a_destructuring_pattern, file);
1320                }
1321
1322                if (elements.hasTrailingComma) {
1323                    throw new DiagnosticError(target, DiagnosticCode.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, file);
1324                }
1325
1326                if (ts.isArrayLiteralExpression(target.expression) || ts.isObjectLiteralExpression(target.expression)) {
1327                    checkDestructuringAssignmentLhs(target.expression);
1328                }
1329
1330                continue;
1331            }
1332
1333            target = ts.isBinaryExpression(target) ? target.left : target;
1334
1335            if (ts.isOmittedExpression(target) || ts.isElementAccessExpression(target)) {
1336                continue;
1337            }
1338
1339            if (ts.isIdentifier(target)) {
1340                let name = jshelpers.getTextOfIdentifierOrLiteral(target);
1341
1342                if (name == MandatoryArguments || name == "eval") {
1343                    throw new DiagnosticError(target, DiagnosticCode.Property_destructuring_pattern_expected, file);
1344                }
1345                continue;
1346            }
1347
1348            if (ts.isPropertyAccessExpression(target)) {
1349                if (target.questionDotToken) {
1350                    throw new DiagnosticError(target, DiagnosticCode.Property_destructuring_pattern_expected, file);
1351                }
1352
1353                continue;
1354            }
1355
1356            if (ts.isArrayLiteralExpression(target) || ts.isObjectLiteralExpression(target)) {
1357                checkDestructuringAssignmentLhs(target);
1358                continue;
1359            }
1360
1361            throw new DiagnosticError(target, DiagnosticCode.Property_destructuring_pattern_expected, file);
1362        }
1363    }
1364
1365    if (ts.isObjectLiteralExpression(lhs)) {
1366        let elements = lhs.properties;
1367
1368        for (let i = 0; i < elements.length; i++) {
1369            let element = elements[i];
1370
1371            if (ts.isSpreadAssignment(element)) {
1372                if (i != elements.length - 1) {
1373                    let file = getSourceFileOfNode(lhs);
1374                    throw new DiagnosticError(element, DiagnosticCode.A_rest_element_must_be_last_in_a_destructuring_pattern, file);
1375                }
1376                continue;
1377            }
1378
1379            if (ts.isPropertyAssignment(element)) {
1380                let target = ts.isBinaryExpression(element.initializer) ? element.initializer.left : element.initializer;
1381
1382                if (ts.isIdentifier(target) ||
1383                    ts.isElementAccessExpression(target)) {
1384                    continue;
1385                }
1386
1387                if (ts.isPropertyAccessExpression(target)) {
1388                    if (target.questionDotToken) {
1389                        throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1390                    }
1391                    continue;
1392                }
1393
1394                if (ts.isObjectLiteralExpression(target) || ts.isArrayLiteralExpression(target)) {
1395                    checkDestructuringAssignmentLhs(target);
1396                    continue;
1397                }
1398
1399                throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1400            }
1401
1402            if (ts.isShorthandPropertyAssignment(element)) {
1403                let name = jshelpers.getTextOfIdentifierOrLiteral(element.name);
1404
1405                if (name == MandatoryArguments || name == "eval") {
1406                    throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1407                }
1408
1409                continue;
1410            }
1411
1412            if (ts.isMethodDeclaration(element) ||
1413                ts.isGetAccessorDeclaration(element) ||
1414                ts.isSetAccessorDeclaration(element)) {
1415                throw new DiagnosticError(element, DiagnosticCode.Property_destructuring_pattern_expected, file);
1416            }
1417        }
1418    }
1419}
1420
1421function checkBindingPattern(node: ts.BindingPattern) {
1422    let elements = node.elements;
1423
1424    for (let i = 0; i < elements.length; i++) {
1425        let element = elements[i];
1426
1427        if (ts.isOmittedExpression(element)) {
1428            continue;
1429        }
1430
1431        if (element.dotDotDotToken) {
1432            let file = getSourceFileOfNode(node);
1433
1434            if (i != elements.length - 1) {
1435                throw new DiagnosticError(element, DiagnosticCode.A_rest_element_must_be_last_in_a_destructuring_pattern, file);
1436            }
1437
1438            if (element.initializer) {
1439                throw new DiagnosticError(element, DiagnosticCode.A_rest_parameter_cannot_have_an_initializer);
1440            }
1441        }
1442    }
1443}
1444