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