• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 * as astutils from "./astutils";
18import { isAnonymousFunctionDefinition } from "./base/util";
19import { CmdOptions } from "./cmdOptions";
20import { CompilerDriver } from "./compilerDriver";
21import { DiagnosticCode, DiagnosticError } from "./diagnostic";
22import { findOuterNodeOfParenthesis } from "./expression/parenthesizedExpression";
23import * as jshelpers from "./jshelpers";
24import { LOGD } from "./log";
25import { ModuleStmt } from "./modules";
26import {
27    CatchParameter,
28    ClassDecl,
29    ConstDecl,
30    Decl,
31    FuncDecl,
32    FunctionParameter,
33    FunctionScope,
34    GlobalScope,
35    LetDecl,
36    LocalScope,
37    LoopScope,
38    ModuleScope,
39    Scope,
40    VarDecl,
41    VariableScope
42} from "./scope";
43import {
44    AddCtor2Class,
45    getClassNameForConstructor,
46    extractCtorOfClass
47} from "./statement/classStatement";
48import { checkSyntaxError } from "./syntaxChecker";
49import { isGlobalIdentifier } from "./syntaxCheckHelper";
50import { TypeChecker } from "./typeChecker";
51import { VarDeclarationKind } from "./variable";
52import { TypeRecorder } from "./typeRecorder";
53import { PandaGen } from "./pandagen";
54
55export class Recorder {
56    node: ts.Node;
57    scope: Scope;
58    compilerDriver: CompilerDriver;
59    recordType: boolean;
60    private scopeMap: Map<ts.Node, Scope> = new Map<ts.Node, Scope>();
61    private hoistMap: Map<Scope, Decl[]> = new Map<Scope, Decl[]>();
62    private parametersMap: Map<ts.FunctionLikeDeclaration, FunctionParameter[]> = new Map<ts.FunctionLikeDeclaration, FunctionParameter[]>();
63    private funcNameMap: Map<string, number>;
64    private class2Ctor: Map<ts.ClassLikeDeclaration, ts.ConstructorDeclaration> = new Map<ts.ClassLikeDeclaration, ts.ConstructorDeclaration>();
65    private importStmts: Array<ModuleStmt> = [];
66    private exportStmts: Array<ModuleStmt> = [];
67    private defaultUsed: boolean = false;
68    private isTsFile: boolean;
69    private syntaxCheckStatus: boolean;
70
71    constructor(node: ts.Node, scope: Scope, compilerDriver: CompilerDriver, recordType: boolean, isTsFile: boolean, syntaxCheckStatus: boolean) {
72        this.node = node;
73        this.scope = scope;
74        this.compilerDriver = compilerDriver;
75        this.recordType = recordType;
76        this.funcNameMap = new Map<string, number>();
77        this.funcNameMap.set("main", 1);
78        this.isTsFile = isTsFile;
79        this.syntaxCheckStatus = syntaxCheckStatus;
80    }
81
82    record() {
83        this.setParent(this.node);
84        this.setScopeMap(this.node, this.scope);
85        this.recordInfo(this.node, this.scope);
86        if (this.recordType) {
87            TypeRecorder.getInstance().setTypeSummary();
88            if (CmdOptions.enableTypeLog()) {
89                TypeRecorder.getInstance().getLog();
90            }
91        } else {
92            PandaGen.clearLiteralArrayBuffer();
93        }
94        return this.node;
95    }
96
97    getCtorOfClass(node: ts.ClassLikeDeclaration) {
98        return this.class2Ctor.get(node);
99    }
100
101    setCtorOfClass(node: ts.ClassLikeDeclaration, ctor: ts.ConstructorDeclaration) {
102        if (!this.class2Ctor.has(node)) {
103            this.class2Ctor.set(node, ctor);
104        }
105    }
106
107    private setParent(node: ts.Node) {
108        node.forEachChild(childNode => {
109            if (!this.isTsFile || childNode!.parent == undefined || childNode.parent.kind != node.kind) {
110                childNode = jshelpers.setParent(childNode, node)!;
111                let originNode = ts.getOriginalNode(childNode);
112                childNode = ts.setTextRange(childNode, originNode);
113            }
114            this.setParent(childNode);
115        });
116    }
117
118    private recordInfo(node: ts.Node, scope: Scope) {
119        node.forEachChild(childNode => {
120            if (this.syntaxCheckStatus) {
121                checkSyntaxError(childNode);
122            }
123            switch (childNode.kind) {
124                case ts.SyntaxKind.FunctionExpression:
125                case ts.SyntaxKind.MethodDeclaration:
126                case ts.SyntaxKind.Constructor:
127                case ts.SyntaxKind.GetAccessor:
128                case ts.SyntaxKind.SetAccessor:
129                case ts.SyntaxKind.ArrowFunction: {
130                    let functionScope = this.buildVariableScope(scope, <ts.FunctionLikeDeclaration>childNode);
131                    this.recordOtherFunc(<ts.FunctionLikeDeclaration>childNode, functionScope);
132                    this.recordInfo(childNode, functionScope);
133                    break;
134                }
135                case ts.SyntaxKind.FunctionDeclaration: {
136                    let functionScope = this.buildVariableScope(scope, <ts.FunctionLikeDeclaration>childNode);
137                    this.recordFuncDecl(<ts.FunctionDeclaration>childNode, scope);
138                    if (this.recordType) {
139                        TypeChecker.getInstance().formatNodeType(childNode);
140                    }
141                    this.recordInfo(childNode, functionScope);
142                    break;
143                }
144                case ts.SyntaxKind.Block:
145                case ts.SyntaxKind.IfStatement:
146                case ts.SyntaxKind.SwitchStatement:
147                case ts.SyntaxKind.LabeledStatement:
148                case ts.SyntaxKind.ThrowStatement:
149                case ts.SyntaxKind.TryStatement:
150                case ts.SyntaxKind.CatchClause: {
151                    let localScope = new LocalScope(scope);
152                    this.setScopeMap(childNode, localScope);
153                    this.recordInfo(childNode, localScope);
154                    break;
155                }
156                case ts.SyntaxKind.DoStatement:
157                case ts.SyntaxKind.WhileStatement:
158                case ts.SyntaxKind.ForStatement:
159                case ts.SyntaxKind.ForInStatement:
160                case ts.SyntaxKind.ForOfStatement: {
161                    let loopScope: LoopScope = new LoopScope(scope);;
162                    this.setScopeMap(childNode, loopScope);
163                    this.recordInfo(childNode, loopScope);
164                    break;
165                }
166                case ts.SyntaxKind.ClassDeclaration:
167                case ts.SyntaxKind.ClassExpression: {
168                    this.recordClassInfo(<ts.ClassLikeDeclaration>childNode, scope);
169                    if (this.recordType) {
170                        TypeChecker.getInstance().formatNodeType(childNode);
171                    }
172                    break;
173                }
174                case ts.SyntaxKind.InterfaceDeclaration: {
175                    if (this.recordType) {
176                        TypeChecker.getInstance().formatNodeType(childNode);
177                    }
178                    break;
179                }
180                case ts.SyntaxKind.Identifier: {
181                    this.recordVariableDecl(<ts.Identifier>childNode, scope);
182                    break;
183                }
184                case ts.SyntaxKind.ImportDeclaration: {
185                    if (!CmdOptions.isModules()) {
186                        throw new DiagnosticError(childNode, DiagnosticCode.An_import_declaration_can_only_be_used_in_a_namespace_or_module, jshelpers.getSourceFileOfNode(childNode));
187                    }
188                    if (!(scope instanceof ModuleScope)) {
189                        throw new Error("SyntaxError: import statement cannot in other scope except ModuleScope");
190                    }
191                    let importStmt = this.recordImportInfo(<ts.ImportDeclaration>childNode, scope);
192                    if (this.recordType) {
193                        TypeChecker.getInstance().formatNodeType(childNode, importStmt);
194                    }
195                    break;
196                }
197                case ts.SyntaxKind.ExportDeclaration: {
198                    if (!CmdOptions.isModules()) {
199                        throw new DiagnosticError(childNode, DiagnosticCode.An_export_declaration_can_only_be_used_in_a_module, jshelpers.getSourceFileOfNode(childNode));
200                    }
201                    if (!(scope instanceof ModuleScope)) {
202                        throw new Error("SyntaxError: export statement cannot in other scope except ModuleScope");
203                    }
204                    let exportStmt = this.recordExportInfo(<ts.ExportDeclaration>childNode);
205                    if (this.recordType) {
206                        TypeChecker.getInstance().formatNodeType(childNode, exportStmt);
207                    }
208                    break;
209                }
210                case ts.SyntaxKind.ExportAssignment: {
211                    if (this.defaultUsed) {
212                        throw new DiagnosticError(childNode, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(childNode), ["default"]);
213                    }
214                    this.defaultUsed = true;
215                    this.recordInfo(childNode, scope);
216                    if (this.recordType) {
217                        TypeChecker.getInstance().formatNodeType(childNode);
218                    }
219                    break;
220                }
221                case ts.SyntaxKind.VariableStatement: {
222                    if (this.recordType) {
223                        TypeChecker.getInstance().formatNodeType(childNode);
224                    }
225                    this.recordInfo(childNode, scope);
226                    break;
227                }
228                default:
229                    this.recordInfo(childNode, scope);
230            }
231        });
232    }
233
234    private recordClassInfo(childNode: ts.ClassLikeDeclaration, scope: Scope) {
235        let localScope = new LocalScope(scope);
236        this.setScopeMap(childNode, localScope);
237        let ctor = extractCtorOfClass(childNode);
238        if (!ctor) {
239            AddCtor2Class(this, childNode, localScope);
240        } else {
241            this.setCtorOfClass(childNode, ctor);
242        }
243        if (childNode.name) {
244            let name = jshelpers.getTextOfIdentifierOrLiteral(childNode.name);
245            let calssDecl = new ClassDecl(name, childNode);
246            scope.setDecls(calssDecl);
247        }
248        this.recordInfo(childNode, localScope);
249    }
250
251    buildVariableScope(curScope: Scope, node: ts.FunctionLikeDeclaration) {
252        let functionScope = new FunctionScope(curScope, <ts.FunctionLikeDeclaration>node);
253        let parentVariableScope = <VariableScope>curScope.getNearestVariableScope();
254        functionScope.setParentVariableScope(parentVariableScope);
255        parentVariableScope.addChildVariableScope(functionScope);
256        this.setScopeMap(node, functionScope);
257        return functionScope;
258    }
259
260    private recordVariableDecl(id: ts.Identifier, scope: Scope) {
261        let name = jshelpers.getTextOfIdentifierOrLiteral(id);
262        let parent = this.getDeclarationNodeOfId(id);
263
264        if (parent) {
265            let declKind = astutils.getVarDeclarationKind(<ts.VariableDeclaration>parent);
266
267            // collect declaration information to corresponding scope
268            let decl = this.addVariableDeclToScope(scope, id, parent, name, declKind);
269            if (declKind == VarDeclarationKind.VAR) {
270                let variableScopeParent = <VariableScope>scope.getNearestVariableScope();
271                this.collectHoistDecls(id, variableScopeParent, decl);
272            }
273        } else {
274            let declScope = scope.findDeclPos(name);
275            if (declScope) {
276                let decl = <Decl>declScope.getDecl(name);
277
278                if ((decl instanceof LetDecl || decl instanceof ConstDecl)) {
279                    let nearestRefVariableScope = <VariableScope>scope.getNearestVariableScope();
280                    let nearestDefLexicalScope = <VariableScope | LoopScope>declScope.getNearestLexicalScope();
281
282                    let tmp: Scope | undefined = nearestRefVariableScope.getNearestLexicalScope();
283                    let needCreateLoopEnv: boolean = false;
284                    if (nearestDefLexicalScope instanceof LoopScope) {
285                        while (tmp) {
286                            if (tmp == nearestDefLexicalScope) {
287                                needCreateLoopEnv = true;
288                                break;
289                            }
290
291                            tmp = tmp.getParent();
292                        }
293
294                        if (needCreateLoopEnv) {
295                            nearestDefLexicalScope.pendingCreateEnv();
296                        }
297                    }
298                }
299            }
300        }
301
302        if (name == "arguments") {
303            let varialbeScope = scope.getNearestVariableScope();
304            varialbeScope?.setUseArgs(true);
305        }
306    }
307
308    private addVariableDeclToScope(scope: Scope, node: ts.Node, parent: ts.Node, name: string, declKind: VarDeclarationKind): Decl {
309        let decl = new VarDecl(name, node);
310        switch (declKind) {
311            case VarDeclarationKind.VAR:
312                break;
313            case VarDeclarationKind.LET:
314                    if (parent.parent.kind == ts.SyntaxKind.CatchClause) {
315                    decl = new CatchParameter(name, node);
316                } else {
317                    decl = new LetDecl(name, node);
318                }
319                break;
320            case VarDeclarationKind.CONST:
321                decl = new ConstDecl(name, node);
322                break;
323            default:
324                throw new Error("Wrong type of declaration");
325        }
326        scope.setDecls(decl);
327        return decl;
328    }
329
330    private getDeclarationNodeOfId(id: ts.Identifier): ts.VariableDeclaration | undefined {
331        let parent = id.parent;
332        if (ts.isVariableDeclaration(parent) &&
333            parent.name == id) {
334            return <ts.VariableDeclaration>parent;
335        } else if (ts.isBindingElement(parent) &&
336            parent.name == id) {
337            while (parent && !ts.isVariableDeclaration(parent)) {
338                parent = parent.parent;
339            }
340
341            return parent ? <ts.VariableDeclaration>parent : undefined;
342        } else {
343            return undefined;
344        }
345    }
346
347    private recordImportInfo(node: ts.ImportDeclaration, scope: ModuleScope): ModuleStmt {
348        if (!ts.isStringLiteral(node.moduleSpecifier)) {
349            throw new Error("moduleSpecifier must be a stringLiteral");
350        }
351        let importStmt: ModuleStmt;
352        if (node.moduleSpecifier) {
353            let moduleRequest = jshelpers.getTextOfIdentifierOrLiteral(node.moduleSpecifier);
354            importStmt = new ModuleStmt(node, moduleRequest);
355        } else {
356            importStmt = new ModuleStmt(node);
357        }
358        if (node.importClause) {
359            let importClause: ts.ImportClause = node.importClause;
360
361            // import defaultExport from "a.js"
362            if (importClause.name) {
363                let name = jshelpers.getTextOfIdentifierOrLiteral(importClause.name);
364                scope.setDecls(new ConstDecl(name, importClause.name));
365                importStmt.addLocalName(name, "default");
366                importStmt.addNodeMap(importClause.name, importClause.name);
367            }
368
369            // import { ... } from "a.js"
370            // import * as a from "a.js"
371            // import defaultExport, * as a from "a.js"
372            if (importClause.namedBindings) {
373                let namedBindings = importClause.namedBindings;
374                // import * as a from "a.js"
375                if (ts.isNamespaceImport(namedBindings)) {
376                    let nameSpace = jshelpers.getTextOfIdentifierOrLiteral((<ts.NamespaceImport>namedBindings).name);
377                    scope.setDecls(new ConstDecl(nameSpace, namedBindings));
378                    importStmt.setNameSpace(nameSpace);
379                }
380
381                // import { ... } from "a.js"
382                if (ts.isNamedImports(namedBindings)) {
383                    namedBindings.elements.forEach((element) => {
384                        let name: string = jshelpers.getTextOfIdentifierOrLiteral(element.name);
385                        let exoticName: string = element.propertyName ? jshelpers.getTextOfIdentifierOrLiteral(element.propertyName) : name;
386                        scope.setDecls(new ConstDecl(name, element));
387                        importStmt.addLocalName(name, exoticName);
388                        importStmt.addNodeMap(element.name, element.propertyName ? element.propertyName : element.name);
389                    });
390                }
391            }
392        }
393
394        this.importStmts.push(importStmt);
395        return importStmt;
396    }
397
398    private recordExportInfo(node: ts.ExportDeclaration): ModuleStmt {
399        let origNode = <ts.ExportDeclaration>ts.getOriginalNode(node);
400        let exportStmt: ModuleStmt;
401        if (origNode.moduleSpecifier) {
402            if (!ts.isStringLiteral(origNode.moduleSpecifier)) {
403                throw new Error("moduleSpecifier must be a stringLiteral");
404            }
405            exportStmt = new ModuleStmt(origNode, jshelpers.getTextOfIdentifierOrLiteral(origNode.moduleSpecifier));
406        } else {
407            exportStmt = new ModuleStmt(origNode);
408        }
409
410        if (origNode.exportClause) {
411            exportStmt.setCopyFlag(false);
412            let namedBindings: ts.NamedExportBindings = origNode.exportClause;
413            if (ts.isNamespaceExport(namedBindings)) {
414                exportStmt.setNameSpace(jshelpers.getTextOfIdentifierOrLiteral((<ts.NamespaceExport>namedBindings).name));
415            }
416
417            if (ts.isNamedExports(namedBindings)) {
418                namedBindings.elements.forEach((element) => {
419                    let name: string = jshelpers.getTextOfIdentifierOrLiteral(element.name);
420                    if (name == 'default') {
421                        if (this.defaultUsed) {
422                            throw new DiagnosticError(origNode, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(origNode), [name]);
423                        } else {
424                            this.defaultUsed = true;
425                        }
426                    }
427                    let exoticName: string = element.propertyName ? jshelpers.getTextOfIdentifierOrLiteral(element.propertyName) : name;
428                    exportStmt.addLocalName(name, exoticName);
429                    exportStmt.addNodeMap(element.name, element.propertyName ? element.propertyName : element.name);
430                });
431            }
432        }
433        this.exportStmts.push(exportStmt);
434        return exportStmt;
435    }
436
437    private recordFuncDecl(node: ts.FunctionDeclaration, scope: Scope) {
438        this.recordFuncInfo(node);
439
440        let funcId = <ts.Identifier>(node).name;
441        if (!funcId) {
442            // function declaration without name doesn't need to record hoisting.
443            return;
444        }
445        let funcName = jshelpers.getTextOfIdentifierOrLiteral(funcId);
446        let funcDecl = new FuncDecl(funcName, node);
447        let hoistScope = scope;
448        let need2AddDecls: boolean = true;
449        if (scope instanceof GlobalScope || scope instanceof ModuleScope) {
450            this.collectHoistDecls(node, <GlobalScope | ModuleScope>hoistScope, funcDecl);
451        } else if (scope instanceof LocalScope) {
452            hoistScope = <Scope>scope.getNearestVariableScope();
453            let expectHoistScope = this.getScopeOfNode(node.parent.parent);
454            if ((hoistScope == expectHoistScope) && (hoistScope instanceof FunctionScope)) {
455                need2AddDecls = this.collectHoistDecls(node, hoistScope, funcDecl);
456            }
457        } else {
458            LOGD("Function declaration", " in function is collected in its body block");
459        }
460        if (need2AddDecls) {
461            scope.setDecls(funcDecl);
462        }
463    }
464
465    private recordOtherFunc(node: ts.FunctionLikeDeclaration, scope: Scope) { // functionlikedecalration except function declaration
466        this.recordFuncInfo(node);
467        if (!ts.isFunctionExpression(node) && !ts.isMethodDeclaration(node)) {
468            return;
469        }
470        if (node.name && ts.isIdentifier(node.name)) {
471            let funcName = jshelpers.getTextOfIdentifierOrLiteral(node.name);
472            let funcDecl = new FuncDecl(funcName, node);
473            scope.setDecls(funcDecl);
474        }
475    }
476
477    private recordFuncInfo(node: ts.FunctionLikeDeclaration) {
478        this.recordFunctionParameters(node);
479        this.recordFuncName(node);
480    }
481
482    recordFuncName(node: ts.FunctionLikeDeclaration) {
483        let name: string = '';
484        if (ts.isConstructorDeclaration(node)) {
485            let classNode = node.parent;
486            name = getClassNameForConstructor(classNode);
487        } else {
488            if (isAnonymousFunctionDefinition(node)) {
489                let outerNode = findOuterNodeOfParenthesis(node);
490
491                if (ts.isVariableDeclaration(outerNode)) {
492                    // @ts-ignore
493                    let id = outerNode.name;
494                    if (ts.isIdentifier(id)) {
495                        name = jshelpers.getTextOfIdentifierOrLiteral(id);
496                    }
497                } else if (ts.isBinaryExpression(outerNode)) {
498                    // @ts-ignore
499                    if (outerNode.operatorToken.kind == ts.SyntaxKind.EqualsToken && ts.isIdentifier(outerNode.left)) {
500                        // @ts-ignore
501                        name = jshelpers.getTextOfIdentifierOrLiteral(outerNode.left);
502                    }
503                } else if (ts.isPropertyAssignment(outerNode)) {
504                    // @ts-ignore
505                    let propName = outerNode.name;
506                    if (ts.isIdentifier(propName) || ts.isStringLiteral(propName) || ts.isNumericLiteral(propName)) {
507                        name = jshelpers.getTextOfIdentifierOrLiteral(propName);
508                        if (name == "__proto__") {
509                            name = '';
510                        }
511                    }
512                }
513            } else {
514                if (ts.isIdentifier(node.name!)) {
515                    name = jshelpers.getTextOfIdentifierOrLiteral(node.name);
516                }
517            }
518        }
519
520        (<FunctionScope>this.getScopeOfNode(node)).setFuncName(name);
521
522        if (name != '') {
523            let funcNameMap = this.funcNameMap;
524            if (funcNameMap.has(name)) {
525                let nums = <number>funcNameMap.get(name);
526                funcNameMap.set(name, ++nums);
527            } else {
528                funcNameMap.set(name, 1);
529            }
530        }
531    }
532
533    recordFunctionParameters(node: ts.FunctionLikeDeclaration) {
534        let parameters = node.parameters;
535        let funcParams: FunctionParameter[] = [];
536        let length = 0;
537        let lengthFlag = true;
538
539        if (parameters) {
540            parameters.forEach(parameter => {
541                // record function.length
542                if (parameter.initializer || this.isRestParameter(parameter)) {
543                    lengthFlag = false;
544                }
545                if (lengthFlag) {
546                    length++;
547                }
548
549                if (ts.isIdentifier(parameter.name)) {
550                    let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>parameter.name);
551                    funcParams.push(new FunctionParameter(name, parameter.name));
552                } else { // parameter is binding pattern
553                    this.recordPatternParameter(<ts.BindingPattern>parameter.name, funcParams);
554                }
555            });
556        }
557        (<FunctionScope>this.getScopeOfNode(node)).setParameterLength(length);
558        this.setParametersMap(node, funcParams);
559    }
560
561    recordPatternParameter(pattern: ts.BindingPattern, funcParams: Array<FunctionParameter>) {
562        let name: string = '';
563        pattern.elements.forEach(bindingElement => {
564            if (ts.isOmittedExpression(bindingElement)) {
565                return;
566            }
567
568            bindingElement = <ts.BindingElement>bindingElement;
569            if (ts.isIdentifier(bindingElement.name)) {
570                name = jshelpers.getTextOfIdentifierOrLiteral(bindingElement.name);
571                funcParams.push(new FunctionParameter(name, bindingElement.name));
572            } else { // case of binding pattern
573                let innerPattern = <ts.BindingPattern>bindingElement.name;
574                this.recordPatternParameter(innerPattern, funcParams);
575            }
576        });
577    }
578
579
580    isRestParameter(parameter: ts.ParameterDeclaration) {
581        return parameter.dotDotDotToken ? true : false;
582    }
583
584    private collectHoistDecls(node: ts.Node, scope: VariableScope, decl: Decl): boolean {
585        let declName = decl.name;
586
587        // if variable share a same name with the parameter of its contained function, it should not be hoisted
588        if (scope instanceof FunctionScope) {
589            let nearestFunc = jshelpers.getContainingFunctionDeclaration(node);
590            let functionParameters = this.getParametersOfFunction(<ts.FunctionLikeDeclaration>nearestFunc);
591            if (functionParameters) {
592                for (let i = 0; i < functionParameters.length; i++) {
593                    if (functionParameters[i].name == declName) {
594                        return false;
595                    }
596                }
597            }
598        }
599
600        // Variable named of global identifier should not be hoisted.
601        if (isGlobalIdentifier(declName) && (scope instanceof GlobalScope)) {
602            return true;
603        }
604
605        this.setHoistMap(scope, decl);
606        return false;
607    }
608
609    setScopeMap(node: ts.Node, scope: Scope) {
610        this.scopeMap.set(node, scope);
611    }
612
613    getScopeMap() {
614        return this.scopeMap;
615    }
616
617    getScopeOfNode(node: ts.Node) {
618        return this.scopeMap.get(node);
619    }
620
621    getImportStmts() {
622        return this.importStmts;
623    }
624
625    getExportStmts() {
626        return this.exportStmts;
627    }
628
629    setHoistMap(scope: VariableScope, decl: Decl) {
630        if (!this.hoistMap.has(scope)) {
631            this.hoistMap.set(scope, [decl]);
632            return;
633        }
634
635        let hoistDecls = <Decl[]>this.hoistMap.get(scope);
636        for (let i = 0; i < hoistDecls.length; i++) {
637            if (decl.name == hoistDecls[i].name) {
638                if (decl instanceof FuncDecl) {
639                    hoistDecls[i] = decl;
640                }
641                return;
642            }
643        }
644        hoistDecls.push(decl);
645    }
646
647    getHoistMap() {
648        return this.hoistMap;
649    }
650
651    getHoistDeclsOfScope(scope: VariableScope) {
652        return this.hoistMap.get(scope);
653    }
654
655    setParametersMap(node: ts.FunctionLikeDeclaration, parameters: FunctionParameter[]) {
656        this.parametersMap.set(node, parameters);
657    }
658
659    getParametersOfFunction(node: ts.FunctionLikeDeclaration) {
660        return this.parametersMap.get(node);
661    }
662
663    getFuncNameMap() {
664        return this.funcNameMap;
665    }
666}