13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ciimport {
173af6ab5fSopenharmony_ci  forEachChild,
183af6ab5fSopenharmony_ci  getModifiers,
193af6ab5fSopenharmony_ci  isCatchClause,
203af6ab5fSopenharmony_ci  isClassDeclaration,
213af6ab5fSopenharmony_ci  isConstructorDeclaration,
223af6ab5fSopenharmony_ci  isFunctionDeclaration,
233af6ab5fSopenharmony_ci  isFunctionLike,
243af6ab5fSopenharmony_ci  isIdentifier,
253af6ab5fSopenharmony_ci  isMethodDeclaration,
263af6ab5fSopenharmony_ci  SyntaxKind,
273af6ab5fSopenharmony_ci  isVariableDeclaration,
283af6ab5fSopenharmony_ci  isFunctionExpression,
293af6ab5fSopenharmony_ci  isArrowFunction,
303af6ab5fSopenharmony_ci  isGetAccessor,
313af6ab5fSopenharmony_ci  isSetAccessor,
323af6ab5fSopenharmony_ci  isPropertyDeclaration,
333af6ab5fSopenharmony_ci  getOriginalNode
343af6ab5fSopenharmony_ci} from 'typescript';
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ciimport type {
373af6ab5fSopenharmony_ci  BreakOrContinueStatement,
383af6ab5fSopenharmony_ci  CaseBlock,
393af6ab5fSopenharmony_ci  CatchClause,
403af6ab5fSopenharmony_ci  ClassDeclaration,
413af6ab5fSopenharmony_ci  ClassElement,
423af6ab5fSopenharmony_ci  ClassExpression,
433af6ab5fSopenharmony_ci  EnumDeclaration,
443af6ab5fSopenharmony_ci  ExportSpecifier,
453af6ab5fSopenharmony_ci  ForInOrOfStatement,
463af6ab5fSopenharmony_ci  ForStatement,
473af6ab5fSopenharmony_ci  FunctionLikeDeclaration,
483af6ab5fSopenharmony_ci  Identifier,
493af6ab5fSopenharmony_ci  ImportEqualsDeclaration,
503af6ab5fSopenharmony_ci  ImportSpecifier,
513af6ab5fSopenharmony_ci  InterfaceDeclaration,
523af6ab5fSopenharmony_ci  LabeledStatement,
533af6ab5fSopenharmony_ci  ModuleDeclaration,
543af6ab5fSopenharmony_ci  NamespaceExport,
553af6ab5fSopenharmony_ci  Node,
563af6ab5fSopenharmony_ci  ObjectBindingPattern,
573af6ab5fSopenharmony_ci  ObjectLiteralExpression,
583af6ab5fSopenharmony_ci  ParameterDeclaration,
593af6ab5fSopenharmony_ci  SourceFile,
603af6ab5fSopenharmony_ci  Symbol,
613af6ab5fSopenharmony_ci  SymbolTable,
623af6ab5fSopenharmony_ci  TypeAliasDeclaration,
633af6ab5fSopenharmony_ci  TypeChecker,
643af6ab5fSopenharmony_ci  TypeElement
653af6ab5fSopenharmony_ci} from 'typescript';
663af6ab5fSopenharmony_ci
673af6ab5fSopenharmony_ciimport {NodeUtils} from './NodeUtils';
683af6ab5fSopenharmony_ciimport {isParameterPropertyModifier, isViewPUBasedClass} from './OhsUtil';
693af6ab5fSopenharmony_ci/**
703af6ab5fSopenharmony_ci * kind of a scope
713af6ab5fSopenharmony_ci */
723af6ab5fSopenharmony_cinamespace secharmony {
733af6ab5fSopenharmony_ci  type ForLikeStatement = ForStatement | ForInOrOfStatement;
743af6ab5fSopenharmony_ci  type ClassLikeDeclaration = ClassDeclaration | ClassExpression;
753af6ab5fSopenharmony_ci  export const noSymbolIdentifier: Set<string> = new Set();
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci  /**
783af6ab5fSopenharmony_ci   * type of scope
793af6ab5fSopenharmony_ci   */
803af6ab5fSopenharmony_ci  export enum ScopeKind {
813af6ab5fSopenharmony_ci    GLOBAL,
823af6ab5fSopenharmony_ci    MODULE,
833af6ab5fSopenharmony_ci    FUNCTION,
843af6ab5fSopenharmony_ci    CLASS,
853af6ab5fSopenharmony_ci    FOR,
863af6ab5fSopenharmony_ci    SWITCH,
873af6ab5fSopenharmony_ci    BLOCK,
883af6ab5fSopenharmony_ci    INTERFACE,
893af6ab5fSopenharmony_ci    CATCH,
903af6ab5fSopenharmony_ci    ENUM,
913af6ab5fSopenharmony_ci    OBJECT_LITERAL
923af6ab5fSopenharmony_ci  }
933af6ab5fSopenharmony_ci
943af6ab5fSopenharmony_ci  export function isGlobalScope(scope: Scope): boolean {
953af6ab5fSopenharmony_ci    return scope.kind === ScopeKind.GLOBAL;
963af6ab5fSopenharmony_ci  }
973af6ab5fSopenharmony_ci
983af6ab5fSopenharmony_ci  export function isFunctionScope(scope: Scope): boolean {
993af6ab5fSopenharmony_ci    return scope.kind === ScopeKind.FUNCTION;
1003af6ab5fSopenharmony_ci  }
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_ci  export function isClassScope(scope: Scope): boolean {
1033af6ab5fSopenharmony_ci    return scope.kind === ScopeKind.CLASS;
1043af6ab5fSopenharmony_ci  }
1053af6ab5fSopenharmony_ci
1063af6ab5fSopenharmony_ci  export function isInterfaceScope(scope: Scope): boolean {
1073af6ab5fSopenharmony_ci    return scope.kind === ScopeKind.INTERFACE;
1083af6ab5fSopenharmony_ci  }
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_ci  export function isEnumScope(scope: Scope): boolean {
1113af6ab5fSopenharmony_ci    return scope.kind === ScopeKind.ENUM;
1123af6ab5fSopenharmony_ci  }
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_ci  export function isObjectLiteralScope(scope: Scope): boolean {
1153af6ab5fSopenharmony_ci    return scope.kind === ScopeKind.OBJECT_LITERAL;
1163af6ab5fSopenharmony_ci  }
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_ci  /**
1193af6ab5fSopenharmony_ci   * get a new scope.
1203af6ab5fSopenharmony_ci   * @param name - name of the scope.
1213af6ab5fSopenharmony_ci   * @param node - node of a current scope in ast.
1223af6ab5fSopenharmony_ci   * @param type - type of the scope.
1233af6ab5fSopenharmony_ci   * @param lexicalScope - indicates if the scope is a lexical scope.
1243af6ab5fSopenharmony_ci   * @param upper - parent scope of the current scope.
1253af6ab5fSopenharmony_ci   */
1263af6ab5fSopenharmony_ci  export class Scope {
1273af6ab5fSopenharmony_ci    // scope name
1283af6ab5fSopenharmony_ci    name: string;
1293af6ab5fSopenharmony_ci    // kind of a scope, such as global ,function like, block ..
1303af6ab5fSopenharmony_ci    kind: ScopeKind;
1313af6ab5fSopenharmony_ci    // node of a current scope in ast.
1323af6ab5fSopenharmony_ci    block: Node;
1333af6ab5fSopenharmony_ci    // parent scope of current scope
1343af6ab5fSopenharmony_ci    parent: Scope | undefined;
1353af6ab5fSopenharmony_ci    // sub scopes of current scope
1363af6ab5fSopenharmony_ci    children: Scope[];
1373af6ab5fSopenharmony_ci
1383af6ab5fSopenharmony_ci    // symbols define in current scope
1393af6ab5fSopenharmony_ci    defs: Set<Symbol>;
1403af6ab5fSopenharmony_ci
1413af6ab5fSopenharmony_ci    // labels in current scope
1423af6ab5fSopenharmony_ci    labels: Label[];
1433af6ab5fSopenharmony_ci
1443af6ab5fSopenharmony_ci    importNames: Set<string>;
1453af6ab5fSopenharmony_ci    exportNames: Set<string>;
1463af6ab5fSopenharmony_ci    fileExportNames?: Set<string>;
1473af6ab5fSopenharmony_ci    fileImportNames?: Set<string>;
1483af6ab5fSopenharmony_ci    mangledNames: Set<string>;
1493af6ab5fSopenharmony_ci    // location path
1503af6ab5fSopenharmony_ci    loc: string;
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_ci    constructor(name: string, node: Node, type: ScopeKind, lexicalScope: boolean = false, upper?: Scope) {
1533af6ab5fSopenharmony_ci      this.name = name;
1543af6ab5fSopenharmony_ci      this.kind = type;
1553af6ab5fSopenharmony_ci      this.block = node;
1563af6ab5fSopenharmony_ci      this.parent = upper;
1573af6ab5fSopenharmony_ci      this.children = [];
1583af6ab5fSopenharmony_ci      this.defs = new Set<Symbol>();
1593af6ab5fSopenharmony_ci      this.labels = [];
1603af6ab5fSopenharmony_ci      this.importNames = new Set<string>();
1613af6ab5fSopenharmony_ci      this.exportNames = new Set<string>();
1623af6ab5fSopenharmony_ci      this.mangledNames = new Set<string>();
1633af6ab5fSopenharmony_ci      this.loc = this.parent?.loc ? this.parent.loc + '#' + this.name : this.name;
1643af6ab5fSopenharmony_ci
1653af6ab5fSopenharmony_ci      this.parent?.addChild(this);
1663af6ab5fSopenharmony_ci    }
1673af6ab5fSopenharmony_ci
1683af6ab5fSopenharmony_ci    /**
1693af6ab5fSopenharmony_ci     * add a sub scope to current scope
1703af6ab5fSopenharmony_ci     *
1713af6ab5fSopenharmony_ci     * @param child
1723af6ab5fSopenharmony_ci     */
1733af6ab5fSopenharmony_ci    addChild(child: Scope): void {
1743af6ab5fSopenharmony_ci      this.children.push(child);
1753af6ab5fSopenharmony_ci    }
1763af6ab5fSopenharmony_ci
1773af6ab5fSopenharmony_ci    /**
1783af6ab5fSopenharmony_ci     * add definition symbol into current scope
1793af6ab5fSopenharmony_ci     *
1803af6ab5fSopenharmony_ci     * @param def definition symbol
1813af6ab5fSopenharmony_ci     */
1823af6ab5fSopenharmony_ci    addDefinition(def: Symbol, obfuscateAsProperty: boolean = false): void {
1833af6ab5fSopenharmony_ci      if (this.kind === ScopeKind.GLOBAL || obfuscateAsProperty) {
1843af6ab5fSopenharmony_ci        Reflect.set(def, 'obfuscateAsProperty', true);
1853af6ab5fSopenharmony_ci      }
1863af6ab5fSopenharmony_ci      this.defs.add(def);
1873af6ab5fSopenharmony_ci    }
1883af6ab5fSopenharmony_ci
1893af6ab5fSopenharmony_ci    /**
1903af6ab5fSopenharmony_ci     * add label to current scope
1913af6ab5fSopenharmony_ci     *
1923af6ab5fSopenharmony_ci     * @param label label statement
1933af6ab5fSopenharmony_ci     */
1943af6ab5fSopenharmony_ci    addLabel(label: Label): void {
1953af6ab5fSopenharmony_ci      this.labels.push(label);
1963af6ab5fSopenharmony_ci    }
1973af6ab5fSopenharmony_ci
1983af6ab5fSopenharmony_ci    /**
1993af6ab5fSopenharmony_ci     * get symbol location
2003af6ab5fSopenharmony_ci     *
2013af6ab5fSopenharmony_ci     * @param sym symbol
2023af6ab5fSopenharmony_ci     */
2033af6ab5fSopenharmony_ci    getSymbolLocation(sym: Symbol): string {
2043af6ab5fSopenharmony_ci      if (!this.defs.has(sym)) {
2053af6ab5fSopenharmony_ci        return '';
2063af6ab5fSopenharmony_ci      }
2073af6ab5fSopenharmony_ci
2083af6ab5fSopenharmony_ci      return this.loc ? sym.name : this.loc + '#' + sym.name;
2093af6ab5fSopenharmony_ci    }
2103af6ab5fSopenharmony_ci
2113af6ab5fSopenharmony_ci    /**
2123af6ab5fSopenharmony_ci     * get label location
2133af6ab5fSopenharmony_ci     *
2143af6ab5fSopenharmony_ci     * @param label
2153af6ab5fSopenharmony_ci     */
2163af6ab5fSopenharmony_ci    getLabelLocation(label: Label): string {
2173af6ab5fSopenharmony_ci      if (!this.labels.includes(label)) {
2183af6ab5fSopenharmony_ci        return '';
2193af6ab5fSopenharmony_ci      }
2203af6ab5fSopenharmony_ci
2213af6ab5fSopenharmony_ci      let index: number = this.labels.findIndex((lb: Label) => lb === label);
2223af6ab5fSopenharmony_ci      return this.loc ? label.name : this.loc + '#' + index + label.name;
2233af6ab5fSopenharmony_ci    }
2243af6ab5fSopenharmony_ci  }
2253af6ab5fSopenharmony_ci
2263af6ab5fSopenharmony_ci  export interface Label {
2273af6ab5fSopenharmony_ci    name: string;
2283af6ab5fSopenharmony_ci    locInfo: string;
2293af6ab5fSopenharmony_ci    refs: Identifier[];
2303af6ab5fSopenharmony_ci    parent: Label | undefined;
2313af6ab5fSopenharmony_ci    children: Label[];
2323af6ab5fSopenharmony_ci    scope: Scope;
2333af6ab5fSopenharmony_ci  }
2343af6ab5fSopenharmony_ci
2353af6ab5fSopenharmony_ci  export function createLabel(node: LabeledStatement, scope: Scope, parent?: Label | undefined): Label {
2363af6ab5fSopenharmony_ci    let labelName: string = '$' + scope.labels.length + '_' + node.label.text;
2373af6ab5fSopenharmony_ci    let label: Label = {
2383af6ab5fSopenharmony_ci      'name': node.label.text,
2393af6ab5fSopenharmony_ci      'locInfo': labelName,
2403af6ab5fSopenharmony_ci      'refs': [node.label],
2413af6ab5fSopenharmony_ci      'parent': parent,
2423af6ab5fSopenharmony_ci      'children': [],
2433af6ab5fSopenharmony_ci      'scope': scope,
2443af6ab5fSopenharmony_ci    };
2453af6ab5fSopenharmony_ci
2463af6ab5fSopenharmony_ci    scope.labels.push(label);
2473af6ab5fSopenharmony_ci    parent?.children.push(label);
2483af6ab5fSopenharmony_ci
2493af6ab5fSopenharmony_ci    return label;
2503af6ab5fSopenharmony_ci  }
2513af6ab5fSopenharmony_ci
2523af6ab5fSopenharmony_ci  export interface ScopeManager {
2533af6ab5fSopenharmony_ci
2543af6ab5fSopenharmony_ci    /**
2553af6ab5fSopenharmony_ci     * get reserved names like ViewPU component class name
2563af6ab5fSopenharmony_ci     */
2573af6ab5fSopenharmony_ci    getReservedNames(): Set<string>;
2583af6ab5fSopenharmony_ci
2593af6ab5fSopenharmony_ci    /**
2603af6ab5fSopenharmony_ci     * do scope analysis
2613af6ab5fSopenharmony_ci     *
2623af6ab5fSopenharmony_ci     * @param ast ast tree of a source file
2633af6ab5fSopenharmony_ci     * @param checker
2643af6ab5fSopenharmony_ci     */
2653af6ab5fSopenharmony_ci    analyze(ast: SourceFile, checker: TypeChecker, isEnabledExportObfuscation: boolean): void;
2663af6ab5fSopenharmony_ci
2673af6ab5fSopenharmony_ci    /**
2683af6ab5fSopenharmony_ci     * get root scope of a file
2693af6ab5fSopenharmony_ci     */
2703af6ab5fSopenharmony_ci    getRootScope(): Scope;
2713af6ab5fSopenharmony_ci
2723af6ab5fSopenharmony_ci    /**
2733af6ab5fSopenharmony_ci     * find block Scope of a node
2743af6ab5fSopenharmony_ci     * @param node
2753af6ab5fSopenharmony_ci     */
2763af6ab5fSopenharmony_ci    getScopeOfNode(node: Node): Scope | undefined;
2773af6ab5fSopenharmony_ci  }
2783af6ab5fSopenharmony_ci
2793af6ab5fSopenharmony_ci  export function createScopeManager(): ScopeManager {
2803af6ab5fSopenharmony_ci    let reservedNames: Set<string> = new Set<string>();
2813af6ab5fSopenharmony_ci    let root: Scope;
2823af6ab5fSopenharmony_ci    let current: Scope;
2833af6ab5fSopenharmony_ci    let scopes: Scope[] = [];
2843af6ab5fSopenharmony_ci
2853af6ab5fSopenharmony_ci    let checker: TypeChecker = null;
2863af6ab5fSopenharmony_ci    let upperLabel: Label | undefined = undefined;
2873af6ab5fSopenharmony_ci    let exportObfuscation: boolean = false;
2883af6ab5fSopenharmony_ci
2893af6ab5fSopenharmony_ci    return {
2903af6ab5fSopenharmony_ci      getReservedNames,
2913af6ab5fSopenharmony_ci      analyze,
2923af6ab5fSopenharmony_ci      getRootScope,
2933af6ab5fSopenharmony_ci      getScopeOfNode,
2943af6ab5fSopenharmony_ci    };
2953af6ab5fSopenharmony_ci
2963af6ab5fSopenharmony_ci    function analyze(ast: SourceFile, typeChecker: TypeChecker, isEnabledExportObfuscation = false): void {
2973af6ab5fSopenharmony_ci      checker = typeChecker;
2983af6ab5fSopenharmony_ci      exportObfuscation = isEnabledExportObfuscation;
2993af6ab5fSopenharmony_ci      analyzeScope(ast);
3003af6ab5fSopenharmony_ci    }
3013af6ab5fSopenharmony_ci
3023af6ab5fSopenharmony_ci    function getReservedNames(): Set<string> {
3033af6ab5fSopenharmony_ci      return reservedNames;
3043af6ab5fSopenharmony_ci    }
3053af6ab5fSopenharmony_ci
3063af6ab5fSopenharmony_ci    function getRootScope(): Scope {
3073af6ab5fSopenharmony_ci      return root;
3083af6ab5fSopenharmony_ci    }
3093af6ab5fSopenharmony_ci
3103af6ab5fSopenharmony_ci    function addSymbolInScope(node: Node): void {
3113af6ab5fSopenharmony_ci      let defSymbols: SymbolTable = node?.locals;
3123af6ab5fSopenharmony_ci      if (!defSymbols) {
3133af6ab5fSopenharmony_ci        return;
3143af6ab5fSopenharmony_ci      }
3153af6ab5fSopenharmony_ci
3163af6ab5fSopenharmony_ci      defSymbols.forEach((def: Symbol) => {
3173af6ab5fSopenharmony_ci        // with export identification, special handling.
3183af6ab5fSopenharmony_ci        if (def.exportSymbol) {
3193af6ab5fSopenharmony_ci          current.exportNames.add(def.name);
3203af6ab5fSopenharmony_ci          root.fileExportNames.add(def.name);
3213af6ab5fSopenharmony_ci          if (def.exportSymbol.name === def.name) {
3223af6ab5fSopenharmony_ci            /* For export declaration, `def` and its `exportSymbol` has same name,
3233af6ab5fSopenharmony_ci                eg. export class Ability {}
3243af6ab5fSopenharmony_ci                  def.name: "Ability"
3253af6ab5fSopenharmony_ci                  def.exportSymbol.name: "Ability"
3263af6ab5fSopenharmony_ci                Collect the `def.exportSymbol` since import symbol is asscociated with it.
3273af6ab5fSopenharmony_ci            */
3283af6ab5fSopenharmony_ci            current.addDefinition(def.exportSymbol, true);
3293af6ab5fSopenharmony_ci          } else {
3303af6ab5fSopenharmony_ci            /* For default exports, `def` and its `exportSymbol` has different name,
3313af6ab5fSopenharmony_ci                eg. export default class Ability {}
3323af6ab5fSopenharmony_ci                  def.name: "Ability"
3333af6ab5fSopenharmony_ci                  def.exportSymbol.name: "default"
3343af6ab5fSopenharmony_ci              Collect the `def` symbol since we should obfuscate "Ability" instead of "default".
3353af6ab5fSopenharmony_ci            */
3363af6ab5fSopenharmony_ci            current.addDefinition(def);
3373af6ab5fSopenharmony_ci          }
3383af6ab5fSopenharmony_ci        } else {
3393af6ab5fSopenharmony_ci          current.addDefinition(def);
3403af6ab5fSopenharmony_ci        }
3413af6ab5fSopenharmony_ci      });
3423af6ab5fSopenharmony_ci    }
3433af6ab5fSopenharmony_ci
3443af6ab5fSopenharmony_ci    function addExportSymbolInScope(node: Node): void {
3453af6ab5fSopenharmony_ci      let defSymbols: Symbol = node?.symbol;
3463af6ab5fSopenharmony_ci
3473af6ab5fSopenharmony_ci      if (!defSymbols) {
3483af6ab5fSopenharmony_ci        return;
3493af6ab5fSopenharmony_ci      }
3503af6ab5fSopenharmony_ci      current.addDefinition(defSymbols);
3513af6ab5fSopenharmony_ci    }
3523af6ab5fSopenharmony_ci
3533af6ab5fSopenharmony_ci    /**
3543af6ab5fSopenharmony_ci     * analyze chain of scopes
3553af6ab5fSopenharmony_ci     * @param node
3563af6ab5fSopenharmony_ci     */
3573af6ab5fSopenharmony_ci    function analyzeScope(node: Node): void {
3583af6ab5fSopenharmony_ci      switch (node.kind) {
3593af6ab5fSopenharmony_ci        // global
3603af6ab5fSopenharmony_ci        case SyntaxKind.SourceFile:
3613af6ab5fSopenharmony_ci          analyzeSourceFile(node as SourceFile);
3623af6ab5fSopenharmony_ci          break;
3633af6ab5fSopenharmony_ci
3643af6ab5fSopenharmony_ci        // namespace or module
3653af6ab5fSopenharmony_ci        case SyntaxKind.ModuleDeclaration:
3663af6ab5fSopenharmony_ci          analyzeModule(node as ModuleDeclaration);
3673af6ab5fSopenharmony_ci          break;
3683af6ab5fSopenharmony_ci
3693af6ab5fSopenharmony_ci        // function like
3703af6ab5fSopenharmony_ci        case SyntaxKind.FunctionDeclaration:
3713af6ab5fSopenharmony_ci        case SyntaxKind.MethodDeclaration:
3723af6ab5fSopenharmony_ci        case SyntaxKind.GetAccessor:
3733af6ab5fSopenharmony_ci        case SyntaxKind.SetAccessor:
3743af6ab5fSopenharmony_ci        case SyntaxKind.Constructor:
3753af6ab5fSopenharmony_ci        case SyntaxKind.FunctionExpression:
3763af6ab5fSopenharmony_ci        case SyntaxKind.ArrowFunction:
3773af6ab5fSopenharmony_ci          analyzeFunctionLike(node as FunctionLikeDeclaration);
3783af6ab5fSopenharmony_ci          break;
3793af6ab5fSopenharmony_ci
3803af6ab5fSopenharmony_ci        // class like
3813af6ab5fSopenharmony_ci        case SyntaxKind.ClassExpression:
3823af6ab5fSopenharmony_ci        case SyntaxKind.ClassDeclaration:
3833af6ab5fSopenharmony_ci        case SyntaxKind.StructDeclaration:
3843af6ab5fSopenharmony_ci          analyzeClassLike(node as ClassLikeDeclaration);
3853af6ab5fSopenharmony_ci          break;
3863af6ab5fSopenharmony_ci
3873af6ab5fSopenharmony_ci        // for like
3883af6ab5fSopenharmony_ci        case SyntaxKind.ForStatement:
3893af6ab5fSopenharmony_ci        case SyntaxKind.ForInStatement:
3903af6ab5fSopenharmony_ci        case SyntaxKind.ForOfStatement:
3913af6ab5fSopenharmony_ci          analyzeForLike(node as ForLikeStatement);
3923af6ab5fSopenharmony_ci          break;
3933af6ab5fSopenharmony_ci        case SyntaxKind.CaseBlock:
3943af6ab5fSopenharmony_ci          // caseBlock property in switch statement
3953af6ab5fSopenharmony_ci          analyzeSwitch(node as CaseBlock);
3963af6ab5fSopenharmony_ci          break;
3973af6ab5fSopenharmony_ci        case SyntaxKind.Block:
3983af6ab5fSopenharmony_ci          // while, do ...while, block, if/else..
3993af6ab5fSopenharmony_ci          analyzeBlock(node);
4003af6ab5fSopenharmony_ci          break;
4013af6ab5fSopenharmony_ci
4023af6ab5fSopenharmony_ci        case SyntaxKind.InterfaceDeclaration:
4033af6ab5fSopenharmony_ci          analyzeInterface(node as InterfaceDeclaration);
4043af6ab5fSopenharmony_ci          break;
4053af6ab5fSopenharmony_ci
4063af6ab5fSopenharmony_ci        case SyntaxKind.EnumDeclaration:
4073af6ab5fSopenharmony_ci          analyzeEnum(node as EnumDeclaration);
4083af6ab5fSopenharmony_ci          break;
4093af6ab5fSopenharmony_ci
4103af6ab5fSopenharmony_ci        case SyntaxKind.Identifier:
4113af6ab5fSopenharmony_ci          analyzeSymbol(node as Identifier);
4123af6ab5fSopenharmony_ci          break;
4133af6ab5fSopenharmony_ci
4143af6ab5fSopenharmony_ci        case SyntaxKind.TypeAliasDeclaration:
4153af6ab5fSopenharmony_ci          analyzeTypeAliasDeclaration(node as TypeAliasDeclaration);
4163af6ab5fSopenharmony_ci          break;
4173af6ab5fSopenharmony_ci
4183af6ab5fSopenharmony_ci        case SyntaxKind.LabeledStatement:
4193af6ab5fSopenharmony_ci          analyzeLabel(node as LabeledStatement);
4203af6ab5fSopenharmony_ci          break;
4213af6ab5fSopenharmony_ci
4223af6ab5fSopenharmony_ci        case SyntaxKind.BreakStatement:
4233af6ab5fSopenharmony_ci        case SyntaxKind.ContinueStatement:
4243af6ab5fSopenharmony_ci          analyzeBreakOrContinue(node as BreakOrContinueStatement);
4253af6ab5fSopenharmony_ci          break;
4263af6ab5fSopenharmony_ci        case SyntaxKind.ImportSpecifier:
4273af6ab5fSopenharmony_ci          analyzeImportNames(node as ImportSpecifier);
4283af6ab5fSopenharmony_ci          break;
4293af6ab5fSopenharmony_ci
4303af6ab5fSopenharmony_ci        case SyntaxKind.ObjectBindingPattern:
4313af6ab5fSopenharmony_ci          analyzeObjectBindingPatternRequire(node as ObjectBindingPattern);
4323af6ab5fSopenharmony_ci          break;
4333af6ab5fSopenharmony_ci
4343af6ab5fSopenharmony_ci        case SyntaxKind.ObjectLiteralExpression:
4353af6ab5fSopenharmony_ci          analyzeObjectLiteralExpression(node as ObjectLiteralExpression);
4363af6ab5fSopenharmony_ci          break;
4373af6ab5fSopenharmony_ci
4383af6ab5fSopenharmony_ci        case SyntaxKind.ExportSpecifier:
4393af6ab5fSopenharmony_ci          analyzeExportNames(node as ExportSpecifier);
4403af6ab5fSopenharmony_ci          break;
4413af6ab5fSopenharmony_ci
4423af6ab5fSopenharmony_ci        case SyntaxKind.NamespaceExport:
4433af6ab5fSopenharmony_ci          analyzeNamespaceExport(node as NamespaceExport);
4443af6ab5fSopenharmony_ci          break;
4453af6ab5fSopenharmony_ci
4463af6ab5fSopenharmony_ci        case SyntaxKind.CatchClause:
4473af6ab5fSopenharmony_ci          analyzeCatchClause(node as CatchClause);
4483af6ab5fSopenharmony_ci          break;
4493af6ab5fSopenharmony_ci
4503af6ab5fSopenharmony_ci        case SyntaxKind.ImportEqualsDeclaration:
4513af6ab5fSopenharmony_ci          analyzeImportEqualsDeclaration(node as ImportEqualsDeclaration);
4523af6ab5fSopenharmony_ci          break;
4533af6ab5fSopenharmony_ci
4543af6ab5fSopenharmony_ci        default:
4553af6ab5fSopenharmony_ci          forEachChild(node, analyzeScope);
4563af6ab5fSopenharmony_ci          break;
4573af6ab5fSopenharmony_ci      }
4583af6ab5fSopenharmony_ci    }
4593af6ab5fSopenharmony_ci
4603af6ab5fSopenharmony_ci    function analyzeImportNames(node: ImportSpecifier): void {
4613af6ab5fSopenharmony_ci      try {
4623af6ab5fSopenharmony_ci        const propetyNameNode: Identifier | undefined = node.propertyName;
4633af6ab5fSopenharmony_ci        if (exportObfuscation && propetyNameNode && isIdentifier(propetyNameNode)) {
4643af6ab5fSopenharmony_ci          let propertySymbol = checker.getSymbolAtLocation(propetyNameNode);
4653af6ab5fSopenharmony_ci          if (!propertySymbol) {
4663af6ab5fSopenharmony_ci            noSymbolIdentifier.add(propetyNameNode.text);
4673af6ab5fSopenharmony_ci          } else {
4683af6ab5fSopenharmony_ci            current.addDefinition(propertySymbol);
4693af6ab5fSopenharmony_ci          }
4703af6ab5fSopenharmony_ci
4713af6ab5fSopenharmony_ci          const nameSymbol = checker.getSymbolAtLocation(node.name);
4723af6ab5fSopenharmony_ci          if (nameSymbol) {
4733af6ab5fSopenharmony_ci            current.addDefinition(nameSymbol);
4743af6ab5fSopenharmony_ci          }
4753af6ab5fSopenharmony_ci        } else {
4763af6ab5fSopenharmony_ci          const nameText = propetyNameNode ? propetyNameNode.text : node.name.text;
4773af6ab5fSopenharmony_ci          current.importNames.add(nameText);
4783af6ab5fSopenharmony_ci          root.fileImportNames.add(nameText);
4793af6ab5fSopenharmony_ci        }
4803af6ab5fSopenharmony_ci        forEachChild(node, analyzeScope);
4813af6ab5fSopenharmony_ci      } catch (e) {
4823af6ab5fSopenharmony_ci        console.error(e);
4833af6ab5fSopenharmony_ci      }
4843af6ab5fSopenharmony_ci    }
4853af6ab5fSopenharmony_ci
4863af6ab5fSopenharmony_ci    /** example
4873af6ab5fSopenharmony_ci     * const { x1, y: customY, z = 0 }: { x: number; y?: number; z?: number } = { x: 1, y: 2 };
4883af6ab5fSopenharmony_ci     * bindingElement.name is x1 for the first element.
4893af6ab5fSopenharmony_ci     * bindingElement.name is customY for the second element.
4903af6ab5fSopenharmony_ci     */
4913af6ab5fSopenharmony_ci    function analyzeObjectBindingPatternRequire(node: ObjectBindingPattern): void {
4923af6ab5fSopenharmony_ci      if (!NodeUtils.isObjectBindingPatternAssignment(node)) {
4933af6ab5fSopenharmony_ci        forEachChild(node, analyzeScope);
4943af6ab5fSopenharmony_ci        return;
4953af6ab5fSopenharmony_ci      }
4963af6ab5fSopenharmony_ci
4973af6ab5fSopenharmony_ci      if (!node.elements) {
4983af6ab5fSopenharmony_ci        return;
4993af6ab5fSopenharmony_ci      }
5003af6ab5fSopenharmony_ci
5013af6ab5fSopenharmony_ci      node.elements.forEach((bindingElement) => {
5023af6ab5fSopenharmony_ci        if (!bindingElement) {
5033af6ab5fSopenharmony_ci          return;
5043af6ab5fSopenharmony_ci        }
5053af6ab5fSopenharmony_ci
5063af6ab5fSopenharmony_ci        findNoSymbolIdentifiers(bindingElement);
5073af6ab5fSopenharmony_ci
5083af6ab5fSopenharmony_ci        if (!bindingElement.name || !isIdentifier(bindingElement.name)) {
5093af6ab5fSopenharmony_ci          return;
5103af6ab5fSopenharmony_ci        }
5113af6ab5fSopenharmony_ci
5123af6ab5fSopenharmony_ci        if (bindingElement.propertyName) {
5133af6ab5fSopenharmony_ci          return;
5143af6ab5fSopenharmony_ci        }
5153af6ab5fSopenharmony_ci
5163af6ab5fSopenharmony_ci        current.importNames.add(bindingElement.name.text);
5173af6ab5fSopenharmony_ci        root.fileImportNames.add(bindingElement.name.text);
5183af6ab5fSopenharmony_ci      });
5193af6ab5fSopenharmony_ci    }
5203af6ab5fSopenharmony_ci
5213af6ab5fSopenharmony_ci    function analyzeObjectLiteralExpression(node: ObjectLiteralExpression): void {
5223af6ab5fSopenharmony_ci      let scopeName: string = '$' + current.children.length;
5233af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.OBJECT_LITERAL, false, current);
5243af6ab5fSopenharmony_ci      scopes.push(current);
5253af6ab5fSopenharmony_ci
5263af6ab5fSopenharmony_ci      addSymbolInScope(node);
5273af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
5283af6ab5fSopenharmony_ci      current = current.parent || current;
5293af6ab5fSopenharmony_ci    }
5303af6ab5fSopenharmony_ci
5313af6ab5fSopenharmony_ci    function analyzeExportNames(node: ExportSpecifier): void {
5323af6ab5fSopenharmony_ci      // get export names.
5333af6ab5fSopenharmony_ci      current.exportNames.add(node.name.text);
5343af6ab5fSopenharmony_ci      root.fileExportNames.add(node.name.text);
5353af6ab5fSopenharmony_ci      addExportSymbolInScope(node);
5363af6ab5fSopenharmony_ci      const propetyNameNode: Identifier | undefined = node.propertyName;
5373af6ab5fSopenharmony_ci      if (exportObfuscation && propetyNameNode && isIdentifier(propetyNameNode)) {
5383af6ab5fSopenharmony_ci        let propertySymbol = checker.getSymbolAtLocation(propetyNameNode);
5393af6ab5fSopenharmony_ci        if (!propertySymbol) {
5403af6ab5fSopenharmony_ci          noSymbolIdentifier.add(propetyNameNode.text);
5413af6ab5fSopenharmony_ci        }
5423af6ab5fSopenharmony_ci      }
5433af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
5443af6ab5fSopenharmony_ci    }
5453af6ab5fSopenharmony_ci
5463af6ab5fSopenharmony_ci    function analyzeNamespaceExport(node: NamespaceExport): void {
5473af6ab5fSopenharmony_ci      if (!exportObfuscation) {
5483af6ab5fSopenharmony_ci        return;
5493af6ab5fSopenharmony_ci      }
5503af6ab5fSopenharmony_ci
5513af6ab5fSopenharmony_ci      let symbol = checker.getSymbolAtLocation(node.name);
5523af6ab5fSopenharmony_ci      if (symbol) {
5533af6ab5fSopenharmony_ci        current.addDefinition(symbol, true);
5543af6ab5fSopenharmony_ci      }
5553af6ab5fSopenharmony_ci    }
5563af6ab5fSopenharmony_ci
5573af6ab5fSopenharmony_ci    function analyzeBreakOrContinue(node: BreakOrContinueStatement): void {
5583af6ab5fSopenharmony_ci      let labelName: string = node?.label?.text ?? '';
5593af6ab5fSopenharmony_ci      let label: Label = findTargetLabel(labelName);
5603af6ab5fSopenharmony_ci      if (!label) {
5613af6ab5fSopenharmony_ci        return;
5623af6ab5fSopenharmony_ci      }
5633af6ab5fSopenharmony_ci
5643af6ab5fSopenharmony_ci      if (node.label) {
5653af6ab5fSopenharmony_ci        label?.refs.push(node.label);
5663af6ab5fSopenharmony_ci      }
5673af6ab5fSopenharmony_ci
5683af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
5693af6ab5fSopenharmony_ci    }
5703af6ab5fSopenharmony_ci
5713af6ab5fSopenharmony_ci    function findTargetLabel(labelName: string): Label | null {
5723af6ab5fSopenharmony_ci      if (!labelName) {
5733af6ab5fSopenharmony_ci        return null;
5743af6ab5fSopenharmony_ci      }
5753af6ab5fSopenharmony_ci
5763af6ab5fSopenharmony_ci      let label: Label | undefined = upperLabel;
5773af6ab5fSopenharmony_ci      // avoid loop
5783af6ab5fSopenharmony_ci      while (label && label?.name !== labelName) {
5793af6ab5fSopenharmony_ci        label = label?.parent;
5803af6ab5fSopenharmony_ci      }
5813af6ab5fSopenharmony_ci
5823af6ab5fSopenharmony_ci      return label;
5833af6ab5fSopenharmony_ci    }
5843af6ab5fSopenharmony_ci
5853af6ab5fSopenharmony_ci    function analyzeSourceFile(node: SourceFile): void {
5863af6ab5fSopenharmony_ci      let scopeName: string = '';
5873af6ab5fSopenharmony_ci      root = new Scope(scopeName, node, ScopeKind.GLOBAL, true);
5883af6ab5fSopenharmony_ci      root.fileExportNames = new Set<string>();
5893af6ab5fSopenharmony_ci      root.fileImportNames = new Set<string>();
5903af6ab5fSopenharmony_ci      current = root;
5913af6ab5fSopenharmony_ci      scopes.push(current);
5923af6ab5fSopenharmony_ci      // locals of a node(scope) is symbol that defines in current scope(node).
5933af6ab5fSopenharmony_ci      addSymbolInScope(node);
5943af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
5953af6ab5fSopenharmony_ci      current = current.parent || current;
5963af6ab5fSopenharmony_ci      extractImportExports();
5973af6ab5fSopenharmony_ci    }
5983af6ab5fSopenharmony_ci
5993af6ab5fSopenharmony_ci    function analyzeCatchClause(node: CatchClause): void {
6003af6ab5fSopenharmony_ci      let scopeName: string = '$' + current.children.length;
6013af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.CATCH, false, current);
6023af6ab5fSopenharmony_ci      scopes.push(current);
6033af6ab5fSopenharmony_ci      // add in catch declaration.
6043af6ab5fSopenharmony_ci      addSymbolInScope(node);
6053af6ab5fSopenharmony_ci      if (node.block) {
6063af6ab5fSopenharmony_ci        // add in block declaration.
6073af6ab5fSopenharmony_ci        addSymbolInScope(node.block);
6083af6ab5fSopenharmony_ci      }
6093af6ab5fSopenharmony_ci
6103af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
6113af6ab5fSopenharmony_ci      current = current.parent || current;
6123af6ab5fSopenharmony_ci    }
6133af6ab5fSopenharmony_ci
6143af6ab5fSopenharmony_ci    function extractImportExports(): void {
6153af6ab5fSopenharmony_ci      for (const def of current.defs) {
6163af6ab5fSopenharmony_ci        if (def.exportSymbol) {
6173af6ab5fSopenharmony_ci          if (!current.exportNames.has(def.name)) {
6183af6ab5fSopenharmony_ci            current.exportNames.add(def.name);
6193af6ab5fSopenharmony_ci            root.fileExportNames.add(def.name);
6203af6ab5fSopenharmony_ci          }
6213af6ab5fSopenharmony_ci          const name: string = def.exportSymbol.name;
6223af6ab5fSopenharmony_ci          if (!current.exportNames.has(name)) {
6233af6ab5fSopenharmony_ci            current.exportNames.add(name);
6243af6ab5fSopenharmony_ci            root.fileExportNames.add(def.name);
6253af6ab5fSopenharmony_ci          }
6263af6ab5fSopenharmony_ci        }
6273af6ab5fSopenharmony_ci      }
6283af6ab5fSopenharmony_ci    }
6293af6ab5fSopenharmony_ci
6303af6ab5fSopenharmony_ci    function analyzeTypeAliasDeclaration(node: TypeAliasDeclaration): void {
6313af6ab5fSopenharmony_ci      let scopeName: string = node.name.text ?? '$' + current.children.length;
6323af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.INTERFACE, true, current);
6333af6ab5fSopenharmony_ci      scopes.push(current);
6343af6ab5fSopenharmony_ci      addSymbolInScope(node);
6353af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
6363af6ab5fSopenharmony_ci      current = current.parent || current;
6373af6ab5fSopenharmony_ci    }
6383af6ab5fSopenharmony_ci
6393af6ab5fSopenharmony_ci    /**
6403af6ab5fSopenharmony_ci     * namespace ns {
6413af6ab5fSopenharmony_ci     *     ...
6423af6ab5fSopenharmony_ci     * }
6433af6ab5fSopenharmony_ci     * @param node
6443af6ab5fSopenharmony_ci     */
6453af6ab5fSopenharmony_ci    function analyzeModule(node: ModuleDeclaration): void {
6463af6ab5fSopenharmony_ci      /**
6473af6ab5fSopenharmony_ci       * if it is an anonymous scope, generate the scope name with a number,
6483af6ab5fSopenharmony_ci       * which is based on the order of its child scopes in the upper scope
6493af6ab5fSopenharmony_ci       */
6503af6ab5fSopenharmony_ci      let scopeName: string = node.name.text ?? '$' + current.children.length;
6513af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.MODULE, true, current);
6523af6ab5fSopenharmony_ci      scopes.push(current);
6533af6ab5fSopenharmony_ci      addSymbolInScope(node);
6543af6ab5fSopenharmony_ci      node.forEachChild((sub: Node) => {
6553af6ab5fSopenharmony_ci        if (isIdentifier(sub)) {
6563af6ab5fSopenharmony_ci          return;
6573af6ab5fSopenharmony_ci        }
6583af6ab5fSopenharmony_ci        analyzeScope(sub);
6593af6ab5fSopenharmony_ci      });
6603af6ab5fSopenharmony_ci      current = current.parent || current;
6613af6ab5fSopenharmony_ci    }
6623af6ab5fSopenharmony_ci
6633af6ab5fSopenharmony_ci    /**
6643af6ab5fSopenharmony_ci     * exclude constructor's parameter witch should be treated as property, example:
6653af6ab5fSopenharmony_ci     *  constructor(public name){}, name should be treated as property
6663af6ab5fSopenharmony_ci     * @param node
6673af6ab5fSopenharmony_ci     */
6683af6ab5fSopenharmony_ci    function excludeConstructorParameter(node: Node): void {
6693af6ab5fSopenharmony_ci      if (!isConstructorDeclaration(node)) {
6703af6ab5fSopenharmony_ci        return;
6713af6ab5fSopenharmony_ci      }
6723af6ab5fSopenharmony_ci
6733af6ab5fSopenharmony_ci      const visitParam = (param: ParameterDeclaration): void => {
6743af6ab5fSopenharmony_ci        const modifiers = getModifiers(param);
6753af6ab5fSopenharmony_ci        if (!modifiers || modifiers.length <= 0) {
6763af6ab5fSopenharmony_ci          return;
6773af6ab5fSopenharmony_ci        }
6783af6ab5fSopenharmony_ci
6793af6ab5fSopenharmony_ci        const findRet = modifiers.find(modifier => isParameterPropertyModifier(modifier));
6803af6ab5fSopenharmony_ci        if (!isIdentifier(param.name) || findRet === undefined) {
6813af6ab5fSopenharmony_ci          return;
6823af6ab5fSopenharmony_ci        }
6833af6ab5fSopenharmony_ci
6843af6ab5fSopenharmony_ci        current.defs.forEach((def) => {
6853af6ab5fSopenharmony_ci          if (isIdentifier(param.name) && (def.name === param.name.text)) {
6863af6ab5fSopenharmony_ci            current.defs.delete(def);
6873af6ab5fSopenharmony_ci            current.mangledNames.add(def.name);
6883af6ab5fSopenharmony_ci          }
6893af6ab5fSopenharmony_ci        });
6903af6ab5fSopenharmony_ci      };
6913af6ab5fSopenharmony_ci
6923af6ab5fSopenharmony_ci      node.parameters.forEach((param) => {
6933af6ab5fSopenharmony_ci        visitParam(param);
6943af6ab5fSopenharmony_ci      });
6953af6ab5fSopenharmony_ci    }
6963af6ab5fSopenharmony_ci
6973af6ab5fSopenharmony_ci    /**
6983af6ab5fSopenharmony_ci     * function func(param1...) {
6993af6ab5fSopenharmony_ci     *     ...
7003af6ab5fSopenharmony_ci     * }
7013af6ab5fSopenharmony_ci     * @param node
7023af6ab5fSopenharmony_ci     */
7033af6ab5fSopenharmony_ci    function analyzeFunctionLike(node: FunctionLikeDeclaration): void {
7043af6ab5fSopenharmony_ci      // For example, the constructor of the StructDeclaration, inserted by arkui, will add a virtual attribute.
7053af6ab5fSopenharmony_ci      // @ts-ignore
7063af6ab5fSopenharmony_ci      if (getOriginalNode(node).virtual) {
7073af6ab5fSopenharmony_ci        return;
7083af6ab5fSopenharmony_ci      }
7093af6ab5fSopenharmony_ci      let scopeName: string = (node?.name as Identifier)?.text ?? '$' + current.children.length;
7103af6ab5fSopenharmony_ci      let loc: string = current?.loc ? current.loc + '#' + scopeName : scopeName;
7113af6ab5fSopenharmony_ci      let overloading: boolean = false;
7123af6ab5fSopenharmony_ci      for (const sub of current.children) {
7133af6ab5fSopenharmony_ci        if (sub.loc === loc) {
7143af6ab5fSopenharmony_ci          overloading = true;
7153af6ab5fSopenharmony_ci          current = sub;
7163af6ab5fSopenharmony_ci          break;
7173af6ab5fSopenharmony_ci        }
7183af6ab5fSopenharmony_ci      }
7193af6ab5fSopenharmony_ci
7203af6ab5fSopenharmony_ci      if (!overloading) {
7213af6ab5fSopenharmony_ci        current = new Scope(scopeName, node, ScopeKind.FUNCTION, true, current);
7223af6ab5fSopenharmony_ci        scopes.push(current);
7233af6ab5fSopenharmony_ci      }
7243af6ab5fSopenharmony_ci
7253af6ab5fSopenharmony_ci      let symbol: Symbol;
7263af6ab5fSopenharmony_ci      if ((isFunctionExpression(node) || isArrowFunction(node)) && isVariableDeclaration(node.parent)) {
7273af6ab5fSopenharmony_ci        symbol = checker.getSymbolAtLocation(node.name ? node.name : node.parent.name);
7283af6ab5fSopenharmony_ci      } else {
7293af6ab5fSopenharmony_ci        if (isFunctionDeclaration(node)) {
7303af6ab5fSopenharmony_ci          symbol = NodeUtils.findSymbolOfIdentifier(checker, node.name);
7313af6ab5fSopenharmony_ci        } else {
7323af6ab5fSopenharmony_ci          symbol = checker.getSymbolAtLocation(node.name);
7333af6ab5fSopenharmony_ci        }
7343af6ab5fSopenharmony_ci      }
7353af6ab5fSopenharmony_ci      if (symbol) {
7363af6ab5fSopenharmony_ci        Reflect.set(symbol, 'isFunction', true);
7373af6ab5fSopenharmony_ci      }
7383af6ab5fSopenharmony_ci
7393af6ab5fSopenharmony_ci      addSymbolInScope(node);
7403af6ab5fSopenharmony_ci      /**
7413af6ab5fSopenharmony_ci       * {
7423af6ab5fSopenharmony_ci       *   get name(): "INT";
7433af6ab5fSopenharmony_ci       *   set orignal(): 0;
7443af6ab5fSopenharmony_ci       * }
7453af6ab5fSopenharmony_ci       * // the above getaccessor and setaccessor were obfuscated as identifiers.
7463af6ab5fSopenharmony_ci       */
7473af6ab5fSopenharmony_ci      if (!(isGetAccessor(node) || isSetAccessor(node)) && symbol && current.parent && !current.parent.defs.has(symbol)) {
7483af6ab5fSopenharmony_ci        /*
7493af6ab5fSopenharmony_ci          Handle the case when `FunctionLikeDeclaration` node is as initializer of variable declaration.
7503af6ab5fSopenharmony_ci          eg. const foo = function bar() {};
7513af6ab5fSopenharmony_ci          The `current` scope is the function's scope, the `current.parent` scope is where the function is defined.
7523af6ab5fSopenharmony_ci          `foo` has already added in the parent scope, we need to add `bar` here too.
7533af6ab5fSopenharmony_ci         */
7543af6ab5fSopenharmony_ci        current.parent.defs.add(symbol);
7553af6ab5fSopenharmony_ci      }
7563af6ab5fSopenharmony_ci
7573af6ab5fSopenharmony_ci      if (isFunctionDeclaration(node) || isMethodDeclaration(node)) {
7583af6ab5fSopenharmony_ci        // function declaration requires skipping function names
7593af6ab5fSopenharmony_ci        node.forEachChild((sub: Node) => {
7603af6ab5fSopenharmony_ci          if (isIdentifier(sub)) {
7613af6ab5fSopenharmony_ci            tryAddNoSymbolIdentifiers(sub);
7623af6ab5fSopenharmony_ci            return;
7633af6ab5fSopenharmony_ci          }
7643af6ab5fSopenharmony_ci
7653af6ab5fSopenharmony_ci          analyzeScope(sub);
7663af6ab5fSopenharmony_ci        });
7673af6ab5fSopenharmony_ci      } else {
7683af6ab5fSopenharmony_ci        forEachChild(node, analyzeScope);
7693af6ab5fSopenharmony_ci      }
7703af6ab5fSopenharmony_ci
7713af6ab5fSopenharmony_ci      excludeConstructorParameter(node);
7723af6ab5fSopenharmony_ci      current = current.parent || current;
7733af6ab5fSopenharmony_ci    }
7743af6ab5fSopenharmony_ci
7753af6ab5fSopenharmony_ci    function analyzeSwitch(node: CaseBlock): void {
7763af6ab5fSopenharmony_ci      let scopeName: string = '$' + current.children.length;
7773af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.SWITCH, false, current);
7783af6ab5fSopenharmony_ci      scopes.push(current);
7793af6ab5fSopenharmony_ci      addSymbolInScope(node);
7803af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
7813af6ab5fSopenharmony_ci      current = current.parent || current;
7823af6ab5fSopenharmony_ci    }
7833af6ab5fSopenharmony_ci
7843af6ab5fSopenharmony_ci    /**
7853af6ab5fSopenharmony_ci     * ES6+ class like scope, The members of a class aren't not allow to rename in rename identifiers transformer, but
7863af6ab5fSopenharmony_ci     * rename in rename properties transformer.
7873af6ab5fSopenharmony_ci     *
7883af6ab5fSopenharmony_ci     * @param node
7893af6ab5fSopenharmony_ci     */
7903af6ab5fSopenharmony_ci    function analyzeClassLike(node: ClassLikeDeclaration): void {
7913af6ab5fSopenharmony_ci      if (isClassDeclaration(node) && isViewPUBasedClass(node)) {
7923af6ab5fSopenharmony_ci        reservedNames.add(node.name.text);
7933af6ab5fSopenharmony_ci      }
7943af6ab5fSopenharmony_ci
7953af6ab5fSopenharmony_ci      try {
7963af6ab5fSopenharmony_ci        let scopeName: string = node?.name?.text ?? '$' + current.children.length;
7973af6ab5fSopenharmony_ci        current = new Scope(scopeName, node, ScopeKind.CLASS, true, current);
7983af6ab5fSopenharmony_ci        scopes.push(current);
7993af6ab5fSopenharmony_ci        addSymbolInScope(node);
8003af6ab5fSopenharmony_ci        // Class members are seen as attribute names, and  the reference of external symbols can be renamed as the same
8013af6ab5fSopenharmony_ci        node.members?.forEach((elm: ClassElement) => {
8023af6ab5fSopenharmony_ci          // @ts-ignore
8033af6ab5fSopenharmony_ci          if (elm?.symbol && !getOriginalNode(elm).virtual) {
8043af6ab5fSopenharmony_ci            current.addDefinition(elm.symbol);
8053af6ab5fSopenharmony_ci          }
8063af6ab5fSopenharmony_ci        });
8073af6ab5fSopenharmony_ci
8083af6ab5fSopenharmony_ci        forEachChild(node, analyzeScope);
8093af6ab5fSopenharmony_ci      } catch (e) {
8103af6ab5fSopenharmony_ci        console.error(e);
8113af6ab5fSopenharmony_ci      }
8123af6ab5fSopenharmony_ci
8133af6ab5fSopenharmony_ci      current = current.parent || current;
8143af6ab5fSopenharmony_ci    }
8153af6ab5fSopenharmony_ci
8163af6ab5fSopenharmony_ci    function analyzeForLike(node: ForLikeStatement): void {
8173af6ab5fSopenharmony_ci      let scopeName: string = '$' + current.children.length;
8183af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.FOR, false, current);
8193af6ab5fSopenharmony_ci      scopes.push(current);
8203af6ab5fSopenharmony_ci      addSymbolInScope(node);
8213af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
8223af6ab5fSopenharmony_ci      current = current.parent || current;
8233af6ab5fSopenharmony_ci    }
8243af6ab5fSopenharmony_ci
8253af6ab5fSopenharmony_ci    function analyzeBlock(node: Node): void {
8263af6ab5fSopenharmony_ci      // when block is body of a function
8273af6ab5fSopenharmony_ci      if ((isFunctionScope(current) && isFunctionLike(node.parent)) || isCatchClause(node.parent)) {
8283af6ab5fSopenharmony_ci        // skip direct block scope in function scope
8293af6ab5fSopenharmony_ci        forEachChild(node, analyzeScope);
8303af6ab5fSopenharmony_ci        return;
8313af6ab5fSopenharmony_ci      }
8323af6ab5fSopenharmony_ci
8333af6ab5fSopenharmony_ci      let scopeName: string = '$' + current.children.length;
8343af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.BLOCK, false, current);
8353af6ab5fSopenharmony_ci      scopes.push(current);
8363af6ab5fSopenharmony_ci      addSymbolInScope(node);
8373af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
8383af6ab5fSopenharmony_ci      current = current.parent || current;
8393af6ab5fSopenharmony_ci    }
8403af6ab5fSopenharmony_ci
8413af6ab5fSopenharmony_ci    function analyzeInterface(node: InterfaceDeclaration): void {
8423af6ab5fSopenharmony_ci      let scopeName: string = node.name.text;
8433af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.INTERFACE, true, current);
8443af6ab5fSopenharmony_ci      scopes.push(current);
8453af6ab5fSopenharmony_ci      try {
8463af6ab5fSopenharmony_ci        addSymbolInScope(node);
8473af6ab5fSopenharmony_ci      } catch (e) {
8483af6ab5fSopenharmony_ci        console.error('');
8493af6ab5fSopenharmony_ci      }
8503af6ab5fSopenharmony_ci
8513af6ab5fSopenharmony_ci      node.members?.forEach((elm: TypeElement) => {
8523af6ab5fSopenharmony_ci        if (elm?.symbol) {
8533af6ab5fSopenharmony_ci          current.addDefinition(elm.symbol);
8543af6ab5fSopenharmony_ci        }
8553af6ab5fSopenharmony_ci      });
8563af6ab5fSopenharmony_ci
8573af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
8583af6ab5fSopenharmony_ci      current = current.parent || current;
8593af6ab5fSopenharmony_ci    }
8603af6ab5fSopenharmony_ci
8613af6ab5fSopenharmony_ci    function analyzeEnum(node: EnumDeclaration): void {
8623af6ab5fSopenharmony_ci      let scopeName: string = node.name.text;
8633af6ab5fSopenharmony_ci      current = new Scope(scopeName, node, ScopeKind.ENUM, true, current);
8643af6ab5fSopenharmony_ci      scopes.push(current);
8653af6ab5fSopenharmony_ci      for (const member of node.members) {
8663af6ab5fSopenharmony_ci        if (member.symbol) {
8673af6ab5fSopenharmony_ci          current.addDefinition(member.symbol);
8683af6ab5fSopenharmony_ci        }
8693af6ab5fSopenharmony_ci      }
8703af6ab5fSopenharmony_ci
8713af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
8723af6ab5fSopenharmony_ci      current = current.parent || current;
8733af6ab5fSopenharmony_ci    }
8743af6ab5fSopenharmony_ci
8753af6ab5fSopenharmony_ci    function analyzeSymbol(node: Identifier): void {
8763af6ab5fSopenharmony_ci      // ignore all identifiers that treat as property in property access
8773af6ab5fSopenharmony_ci      if (NodeUtils.isPropertyAccessNode(node)) {
8783af6ab5fSopenharmony_ci        return;
8793af6ab5fSopenharmony_ci      }
8803af6ab5fSopenharmony_ci
8813af6ab5fSopenharmony_ci      let symbol: Symbol = null;
8823af6ab5fSopenharmony_ci
8833af6ab5fSopenharmony_ci      try {
8843af6ab5fSopenharmony_ci        symbol = NodeUtils.findSymbolOfIdentifier(checker, node);
8853af6ab5fSopenharmony_ci      } catch (e) {
8863af6ab5fSopenharmony_ci        console.error(e);
8873af6ab5fSopenharmony_ci        return;
8883af6ab5fSopenharmony_ci      }
8893af6ab5fSopenharmony_ci
8903af6ab5fSopenharmony_ci      if (!symbol) {
8913af6ab5fSopenharmony_ci        current.mangledNames.add(node.text);
8923af6ab5fSopenharmony_ci        return;
8933af6ab5fSopenharmony_ci      }
8943af6ab5fSopenharmony_ci
8953af6ab5fSopenharmony_ci      // ignore all identifiers that treat as property in property declaration
8963af6ab5fSopenharmony_ci      if (NodeUtils.isPropertyDeclarationNode(node)) {
8973af6ab5fSopenharmony_ci        return;
8983af6ab5fSopenharmony_ci      }
8993af6ab5fSopenharmony_ci
9003af6ab5fSopenharmony_ci      // add def symbol that don't found in current defs.
9013af6ab5fSopenharmony_ci      addSymbolIntoDefsIfNeeded(node, symbol, current.defs);
9023af6ab5fSopenharmony_ci    }
9033af6ab5fSopenharmony_ci
9043af6ab5fSopenharmony_ci    function addSymbolIntoDefsIfNeeded(node: Identifier, symbol: Symbol, currentDefs: Set<Symbol>): boolean {
9053af6ab5fSopenharmony_ci      // process a new def not in currentDefs
9063af6ab5fSopenharmony_ci      let isSameName: boolean = false;
9073af6ab5fSopenharmony_ci      for (const def of currentDefs) {
9083af6ab5fSopenharmony_ci        if (def.name === node.text) {
9093af6ab5fSopenharmony_ci          isSameName = true;
9103af6ab5fSopenharmony_ci          break;
9113af6ab5fSopenharmony_ci        }
9123af6ab5fSopenharmony_ci      }
9133af6ab5fSopenharmony_ci
9143af6ab5fSopenharmony_ci      if (isSameName) {
9153af6ab5fSopenharmony_ci        // exclude the possibility of external symbols, as those with duplicate names have been added to currentDefs (this avoids the possibility of omissions)
9163af6ab5fSopenharmony_ci        if (!currentDefs.has(symbol)) {
9173af6ab5fSopenharmony_ci          currentDefs.add(symbol);
9183af6ab5fSopenharmony_ci        }
9193af6ab5fSopenharmony_ci
9203af6ab5fSopenharmony_ci        if (symbol.exportSymbol && !currentDefs.has(symbol.exportSymbol)) {
9213af6ab5fSopenharmony_ci          Reflect.set(symbol, 'obfuscateAsProperty', true);
9223af6ab5fSopenharmony_ci          currentDefs.add(symbol);
9233af6ab5fSopenharmony_ci        }
9243af6ab5fSopenharmony_ci      }
9253af6ab5fSopenharmony_ci
9263af6ab5fSopenharmony_ci      return isSameName;
9273af6ab5fSopenharmony_ci    }
9283af6ab5fSopenharmony_ci
9293af6ab5fSopenharmony_ci    function analyzeLabel(node: LabeledStatement): void {
9303af6ab5fSopenharmony_ci      // labels within the same scope are allowed to be duplicated, so label names need to have numbering information to distinguish them
9313af6ab5fSopenharmony_ci      upperLabel = upperLabel ? createLabel(node, current, upperLabel) : createLabel(node, current);
9323af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
9333af6ab5fSopenharmony_ci      upperLabel = upperLabel?.parent;
9343af6ab5fSopenharmony_ci    }
9353af6ab5fSopenharmony_ci
9363af6ab5fSopenharmony_ci    function getScopeOfNode(node: Node): Scope | undefined {
9373af6ab5fSopenharmony_ci      if (!isIdentifier(node)) {
9383af6ab5fSopenharmony_ci        return undefined;
9393af6ab5fSopenharmony_ci      }
9403af6ab5fSopenharmony_ci
9413af6ab5fSopenharmony_ci      let sym: Symbol = checker.getSymbolAtLocation(node);
9423af6ab5fSopenharmony_ci      if (!sym) {
9433af6ab5fSopenharmony_ci        return undefined;
9443af6ab5fSopenharmony_ci      }
9453af6ab5fSopenharmony_ci
9463af6ab5fSopenharmony_ci      for (const scope of scopes) {
9473af6ab5fSopenharmony_ci        if (scope?.defs.has(sym)) {
9483af6ab5fSopenharmony_ci          return scope;
9493af6ab5fSopenharmony_ci        }
9503af6ab5fSopenharmony_ci      }
9513af6ab5fSopenharmony_ci
9523af6ab5fSopenharmony_ci      return undefined;
9533af6ab5fSopenharmony_ci    }
9543af6ab5fSopenharmony_ci
9553af6ab5fSopenharmony_ci    function analyzeImportEqualsDeclaration(node: ImportEqualsDeclaration): void {
9563af6ab5fSopenharmony_ci      let hasExport: boolean = false;
9573af6ab5fSopenharmony_ci      if (node.modifiers) {
9583af6ab5fSopenharmony_ci        for (const modifier of node.modifiers) {
9593af6ab5fSopenharmony_ci          if (modifier.kind === SyntaxKind.ExportKeyword) {
9603af6ab5fSopenharmony_ci            hasExport = true;
9613af6ab5fSopenharmony_ci            break;
9623af6ab5fSopenharmony_ci          }
9633af6ab5fSopenharmony_ci        }
9643af6ab5fSopenharmony_ci      }
9653af6ab5fSopenharmony_ci      if (hasExport) {
9663af6ab5fSopenharmony_ci        current.exportNames.add(node.name.text);
9673af6ab5fSopenharmony_ci        root.fileExportNames.add(node.name.text);
9683af6ab5fSopenharmony_ci        let sym: Symbol | undefined = checker.getSymbolAtLocation(node.name);
9693af6ab5fSopenharmony_ci        if (sym) {
9703af6ab5fSopenharmony_ci          current.addDefinition(sym, true);
9713af6ab5fSopenharmony_ci        }
9723af6ab5fSopenharmony_ci      }
9733af6ab5fSopenharmony_ci      forEachChild(node, analyzeScope);
9743af6ab5fSopenharmony_ci    }
9753af6ab5fSopenharmony_ci
9763af6ab5fSopenharmony_ci    function tryAddNoSymbolIdentifiers(node: Identifier): void {
9773af6ab5fSopenharmony_ci      if (!isIdentifier(node)) {
9783af6ab5fSopenharmony_ci        return;
9793af6ab5fSopenharmony_ci      }
9803af6ab5fSopenharmony_ci
9813af6ab5fSopenharmony_ci      // skip property in property access expression
9823af6ab5fSopenharmony_ci      if (NodeUtils.isPropertyAccessNode(node)) {
9833af6ab5fSopenharmony_ci        return;
9843af6ab5fSopenharmony_ci      }
9853af6ab5fSopenharmony_ci
9863af6ab5fSopenharmony_ci      const sym: Symbol | undefined = checker.getSymbolAtLocation(node);
9873af6ab5fSopenharmony_ci      if (!sym) {
9883af6ab5fSopenharmony_ci        current.mangledNames.add((node as Identifier).text);
9893af6ab5fSopenharmony_ci      }
9903af6ab5fSopenharmony_ci    }
9913af6ab5fSopenharmony_ci
9923af6ab5fSopenharmony_ci    function findNoSymbolIdentifiers(node: Node): void {
9933af6ab5fSopenharmony_ci      const noSymbolVisit = (targetNode: Node): void => {
9943af6ab5fSopenharmony_ci        if (!isIdentifier(targetNode)) {
9953af6ab5fSopenharmony_ci          forEachChild(targetNode, noSymbolVisit);
9963af6ab5fSopenharmony_ci          return;
9973af6ab5fSopenharmony_ci        }
9983af6ab5fSopenharmony_ci        tryAddNoSymbolIdentifiers(targetNode);
9993af6ab5fSopenharmony_ci      };
10003af6ab5fSopenharmony_ci
10013af6ab5fSopenharmony_ci      noSymbolVisit(node);
10023af6ab5fSopenharmony_ci    }
10033af6ab5fSopenharmony_ci  }
10043af6ab5fSopenharmony_ci}
10053af6ab5fSopenharmony_ci
10063af6ab5fSopenharmony_ciexport = secharmony;
1007