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 * as ts from 'typescript';
173af6ab5fSopenharmony_ciimport { TsUtils } from '../utils/TsUtils';
183af6ab5fSopenharmony_ciimport { scopeContainsThis } from '../utils/functions/ContainsThis';
193af6ab5fSopenharmony_ciimport { forEachNodeInSubtree } from '../utils/functions/ForEachNodeInSubtree';
203af6ab5fSopenharmony_ciimport { NameGenerator } from '../utils/functions/NameGenerator';
213af6ab5fSopenharmony_ciimport { isAssignmentOperator } from '../utils/functions/isAssignmentOperator';
223af6ab5fSopenharmony_ciimport { SymbolCache } from './SymbolCache';
233af6ab5fSopenharmony_ci
243af6ab5fSopenharmony_ciconst GENERATED_OBJECT_LITERAL_INTERFACE_NAME = 'GeneratedObjectLiteralInterface_';
253af6ab5fSopenharmony_ciconst GENERATED_OBJECT_LITERAL_INTERFACE_TRESHOLD = 1000;
263af6ab5fSopenharmony_ci
273af6ab5fSopenharmony_ciconst GENERATED_TYPE_LITERAL_INTERFACE_NAME = 'GeneratedTypeLiteralInterface_';
283af6ab5fSopenharmony_ciconst GENERATED_TYPE_LITERAL_INTERFACE_TRESHOLD = 1000;
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_ciexport interface Autofix {
313af6ab5fSopenharmony_ci  replacementText: string;
323af6ab5fSopenharmony_ci  start: number;
333af6ab5fSopenharmony_ci  end: number;
343af6ab5fSopenharmony_ci}
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ciexport class Autofixer {
373af6ab5fSopenharmony_ci  constructor(
383af6ab5fSopenharmony_ci    private readonly typeChecker: ts.TypeChecker,
393af6ab5fSopenharmony_ci    private readonly utils: TsUtils,
403af6ab5fSopenharmony_ci    readonly sourceFile: ts.SourceFile,
413af6ab5fSopenharmony_ci    readonly cancellationToken?: ts.CancellationToken
423af6ab5fSopenharmony_ci  ) {
433af6ab5fSopenharmony_ci    this.symbolCache = new SymbolCache(this.typeChecker, this.utils, sourceFile, cancellationToken);
443af6ab5fSopenharmony_ci  }
453af6ab5fSopenharmony_ci
463af6ab5fSopenharmony_ci  fixLiteralAsPropertyNamePropertyAssignment(node: ts.PropertyAssignment): Autofix[] | undefined {
473af6ab5fSopenharmony_ci    const contextualType = this.typeChecker.getContextualType(node.parent);
483af6ab5fSopenharmony_ci    if (contextualType === undefined) {
493af6ab5fSopenharmony_ci      return undefined;
503af6ab5fSopenharmony_ci    }
513af6ab5fSopenharmony_ci
523af6ab5fSopenharmony_ci    const symbol = this.utils.getPropertySymbol(contextualType, node);
533af6ab5fSopenharmony_ci    if (symbol === undefined) {
543af6ab5fSopenharmony_ci      return undefined;
553af6ab5fSopenharmony_ci    }
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_ci    return this.renameSymbolAsIdentifier(symbol);
583af6ab5fSopenharmony_ci  }
593af6ab5fSopenharmony_ci
603af6ab5fSopenharmony_ci  fixLiteralAsPropertyNamePropertyName(node: ts.PropertyName): Autofix[] | undefined {
613af6ab5fSopenharmony_ci    const symbol = this.typeChecker.getSymbolAtLocation(node);
623af6ab5fSopenharmony_ci    if (symbol === undefined) {
633af6ab5fSopenharmony_ci      return undefined;
643af6ab5fSopenharmony_ci    }
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci    return this.renameSymbolAsIdentifier(symbol);
673af6ab5fSopenharmony_ci  }
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci  fixPropertyAccessByIndex(node: ts.ElementAccessExpression): Autofix[] | undefined {
703af6ab5fSopenharmony_ci    const symbol = this.typeChecker.getSymbolAtLocation(node.argumentExpression);
713af6ab5fSopenharmony_ci    if (symbol === undefined) {
723af6ab5fSopenharmony_ci      return undefined;
733af6ab5fSopenharmony_ci    }
743af6ab5fSopenharmony_ci
753af6ab5fSopenharmony_ci    return this.renameSymbolAsIdentifier(symbol);
763af6ab5fSopenharmony_ci  }
773af6ab5fSopenharmony_ci
783af6ab5fSopenharmony_ci  private renameSymbolAsIdentifier(symbol: ts.Symbol): Autofix[] | undefined {
793af6ab5fSopenharmony_ci    if (this.renameSymbolAsIdentifierCache.has(symbol)) {
803af6ab5fSopenharmony_ci      return this.renameSymbolAsIdentifierCache.get(symbol);
813af6ab5fSopenharmony_ci    }
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    if (!TsUtils.isPropertyOfInternalClassOrInterface(symbol)) {
843af6ab5fSopenharmony_ci      this.renameSymbolAsIdentifierCache.set(symbol, undefined);
853af6ab5fSopenharmony_ci      return undefined;
863af6ab5fSopenharmony_ci    }
873af6ab5fSopenharmony_ci
883af6ab5fSopenharmony_ci    const newName = this.utils.findIdentifierNameForSymbol(symbol);
893af6ab5fSopenharmony_ci    if (newName === undefined) {
903af6ab5fSopenharmony_ci      this.renameSymbolAsIdentifierCache.set(symbol, undefined);
913af6ab5fSopenharmony_ci      return undefined;
923af6ab5fSopenharmony_ci    }
933af6ab5fSopenharmony_ci
943af6ab5fSopenharmony_ci    let result: Autofix[] | undefined = [];
953af6ab5fSopenharmony_ci    this.symbolCache.getReferences(symbol).forEach((node) => {
963af6ab5fSopenharmony_ci      if (result === undefined) {
973af6ab5fSopenharmony_ci        return;
983af6ab5fSopenharmony_ci      }
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_ci      let autofix: Autofix[] | undefined;
1013af6ab5fSopenharmony_ci      if (ts.isPropertyDeclaration(node) || ts.isPropertyAssignment(node) || ts.isPropertySignature(node)) {
1023af6ab5fSopenharmony_ci        autofix = Autofixer.renamePropertyName(node.name, newName);
1033af6ab5fSopenharmony_ci      } else if (ts.isElementAccessExpression(node)) {
1043af6ab5fSopenharmony_ci        autofix = Autofixer.renameElementAccessExpression(node, newName);
1053af6ab5fSopenharmony_ci      }
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ci      if (autofix === undefined) {
1083af6ab5fSopenharmony_ci        result = undefined;
1093af6ab5fSopenharmony_ci        return;
1103af6ab5fSopenharmony_ci      }
1113af6ab5fSopenharmony_ci
1123af6ab5fSopenharmony_ci      result.push(...autofix);
1133af6ab5fSopenharmony_ci    });
1143af6ab5fSopenharmony_ci    if (!result?.length) {
1153af6ab5fSopenharmony_ci      result = undefined;
1163af6ab5fSopenharmony_ci    }
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_ci    this.renameSymbolAsIdentifierCache.set(symbol, result);
1193af6ab5fSopenharmony_ci    return result;
1203af6ab5fSopenharmony_ci  }
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci  private readonly renameSymbolAsIdentifierCache = new Map<ts.Symbol, Autofix[] | undefined>();
1233af6ab5fSopenharmony_ci
1243af6ab5fSopenharmony_ci  private static renamePropertyName(node: ts.PropertyName, newName: string): Autofix[] | undefined {
1253af6ab5fSopenharmony_ci    if (ts.isComputedPropertyName(node)) {
1263af6ab5fSopenharmony_ci      return undefined;
1273af6ab5fSopenharmony_ci    }
1283af6ab5fSopenharmony_ci
1293af6ab5fSopenharmony_ci    if (ts.isMemberName(node)) {
1303af6ab5fSopenharmony_ci      if (ts.idText(node) !== newName) {
1313af6ab5fSopenharmony_ci        return undefined;
1323af6ab5fSopenharmony_ci      }
1333af6ab5fSopenharmony_ci
1343af6ab5fSopenharmony_ci      return [];
1353af6ab5fSopenharmony_ci    }
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    return [{ replacementText: newName, start: node.getStart(), end: node.getEnd() }];
1383af6ab5fSopenharmony_ci  }
1393af6ab5fSopenharmony_ci
1403af6ab5fSopenharmony_ci  private static renameElementAccessExpression(
1413af6ab5fSopenharmony_ci    node: ts.ElementAccessExpression,
1423af6ab5fSopenharmony_ci    newName: string
1433af6ab5fSopenharmony_ci  ): Autofix[] | undefined {
1443af6ab5fSopenharmony_ci    const argExprKind = node.argumentExpression.kind;
1453af6ab5fSopenharmony_ci    if (argExprKind !== ts.SyntaxKind.NumericLiteral && argExprKind !== ts.SyntaxKind.StringLiteral) {
1463af6ab5fSopenharmony_ci      return undefined;
1473af6ab5fSopenharmony_ci    }
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_ci    return [
1503af6ab5fSopenharmony_ci      {
1513af6ab5fSopenharmony_ci        replacementText: node.expression.getText() + '.' + newName,
1523af6ab5fSopenharmony_ci        start: node.getStart(),
1533af6ab5fSopenharmony_ci        end: node.getEnd()
1543af6ab5fSopenharmony_ci      }
1553af6ab5fSopenharmony_ci    ];
1563af6ab5fSopenharmony_ci  }
1573af6ab5fSopenharmony_ci
1583af6ab5fSopenharmony_ci  fixFunctionExpression(
1593af6ab5fSopenharmony_ci    funcExpr: ts.FunctionExpression,
1603af6ab5fSopenharmony_ci    // eslint-disable-next-line default-param-last
1613af6ab5fSopenharmony_ci    retType: ts.TypeNode | undefined = funcExpr.type,
1623af6ab5fSopenharmony_ci    modifiers: readonly ts.Modifier[] | undefined,
1633af6ab5fSopenharmony_ci    isGenerator: boolean,
1643af6ab5fSopenharmony_ci    hasUnfixableReturnType: boolean
1653af6ab5fSopenharmony_ci  ): Autofix[] | undefined {
1663af6ab5fSopenharmony_ci    const hasThisKeyword = scopeContainsThis(funcExpr.body);
1673af6ab5fSopenharmony_ci    const isCalledRecursively = this.utils.isFunctionCalledRecursively(funcExpr);
1683af6ab5fSopenharmony_ci    if (isGenerator || hasThisKeyword || isCalledRecursively || hasUnfixableReturnType) {
1693af6ab5fSopenharmony_ci      return undefined;
1703af6ab5fSopenharmony_ci    }
1713af6ab5fSopenharmony_ci
1723af6ab5fSopenharmony_ci    let arrowFunc: ts.Expression = ts.factory.createArrowFunction(
1733af6ab5fSopenharmony_ci      modifiers,
1743af6ab5fSopenharmony_ci      funcExpr.typeParameters,
1753af6ab5fSopenharmony_ci      funcExpr.parameters,
1763af6ab5fSopenharmony_ci      retType,
1773af6ab5fSopenharmony_ci      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1783af6ab5fSopenharmony_ci      funcExpr.body
1793af6ab5fSopenharmony_ci    );
1803af6ab5fSopenharmony_ci    if (Autofixer.needsParentheses(funcExpr)) {
1813af6ab5fSopenharmony_ci      arrowFunc = ts.factory.createParenthesizedExpression(arrowFunc);
1823af6ab5fSopenharmony_ci    }
1833af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, arrowFunc, funcExpr.getSourceFile());
1843af6ab5fSopenharmony_ci    return [{ start: funcExpr.getStart(), end: funcExpr.getEnd(), replacementText: text }];
1853af6ab5fSopenharmony_ci  }
1863af6ab5fSopenharmony_ci
1873af6ab5fSopenharmony_ci  private static isNodeInWhileOrIf(node: ts.Node): boolean {
1883af6ab5fSopenharmony_ci    return (
1893af6ab5fSopenharmony_ci      node.kind === ts.SyntaxKind.WhileStatement ||
1903af6ab5fSopenharmony_ci      node.kind === ts.SyntaxKind.DoStatement ||
1913af6ab5fSopenharmony_ci      node.kind === ts.SyntaxKind.IfStatement
1923af6ab5fSopenharmony_ci    );
1933af6ab5fSopenharmony_ci  }
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_ci  private static isNodeInForLoop(node: ts.Node): boolean {
1963af6ab5fSopenharmony_ci    return (
1973af6ab5fSopenharmony_ci      node.kind === ts.SyntaxKind.ForInStatement ||
1983af6ab5fSopenharmony_ci      node.kind === ts.SyntaxKind.ForOfStatement ||
1993af6ab5fSopenharmony_ci      node.kind === ts.SyntaxKind.ForStatement
2003af6ab5fSopenharmony_ci    );
2013af6ab5fSopenharmony_ci  }
2023af6ab5fSopenharmony_ci
2033af6ab5fSopenharmony_ci  private static parentInFor(node: ts.Node): ts.Node | undefined {
2043af6ab5fSopenharmony_ci    let parentNode = node.parent;
2053af6ab5fSopenharmony_ci    while (parentNode) {
2063af6ab5fSopenharmony_ci      if (Autofixer.isNodeInForLoop(parentNode)) {
2073af6ab5fSopenharmony_ci        return parentNode;
2083af6ab5fSopenharmony_ci      }
2093af6ab5fSopenharmony_ci      parentNode = parentNode.parent;
2103af6ab5fSopenharmony_ci    }
2113af6ab5fSopenharmony_ci    return undefined;
2123af6ab5fSopenharmony_ci  }
2133af6ab5fSopenharmony_ci
2143af6ab5fSopenharmony_ci  private static parentInCaseOrWhile(varDeclList: ts.VariableDeclarationList): boolean {
2153af6ab5fSopenharmony_ci    let parentNode: ts.Node = varDeclList.parent;
2163af6ab5fSopenharmony_ci    while (parentNode) {
2173af6ab5fSopenharmony_ci      if (parentNode.kind === ts.SyntaxKind.CaseClause || Autofixer.isNodeInWhileOrIf(parentNode)) {
2183af6ab5fSopenharmony_ci        return false;
2193af6ab5fSopenharmony_ci      }
2203af6ab5fSopenharmony_ci      parentNode = parentNode.parent;
2213af6ab5fSopenharmony_ci    }
2223af6ab5fSopenharmony_ci    return true;
2233af6ab5fSopenharmony_ci  }
2243af6ab5fSopenharmony_ci
2253af6ab5fSopenharmony_ci  private static isFunctionLikeDeclarationKind(node: ts.Node): boolean {
2263af6ab5fSopenharmony_ci    switch (node.kind) {
2273af6ab5fSopenharmony_ci      case ts.SyntaxKind.FunctionDeclaration:
2283af6ab5fSopenharmony_ci      case ts.SyntaxKind.MethodDeclaration:
2293af6ab5fSopenharmony_ci      case ts.SyntaxKind.Constructor:
2303af6ab5fSopenharmony_ci      case ts.SyntaxKind.GetAccessor:
2313af6ab5fSopenharmony_ci      case ts.SyntaxKind.SetAccessor:
2323af6ab5fSopenharmony_ci      case ts.SyntaxKind.FunctionExpression:
2333af6ab5fSopenharmony_ci      case ts.SyntaxKind.ArrowFunction:
2343af6ab5fSopenharmony_ci        return true;
2353af6ab5fSopenharmony_ci      default:
2363af6ab5fSopenharmony_ci        return false;
2373af6ab5fSopenharmony_ci    }
2383af6ab5fSopenharmony_ci  }
2393af6ab5fSopenharmony_ci
2403af6ab5fSopenharmony_ci  private static findVarScope(node: ts.Node): ts.Node {
2413af6ab5fSopenharmony_ci    while (node !== undefined) {
2423af6ab5fSopenharmony_ci      if (node.kind === ts.SyntaxKind.Block || node.kind === ts.SyntaxKind.SourceFile) {
2433af6ab5fSopenharmony_ci        break;
2443af6ab5fSopenharmony_ci      }
2453af6ab5fSopenharmony_ci      // eslint-disable-next-line no-param-reassign
2463af6ab5fSopenharmony_ci      node = node.parent;
2473af6ab5fSopenharmony_ci    }
2483af6ab5fSopenharmony_ci    return node;
2493af6ab5fSopenharmony_ci  }
2503af6ab5fSopenharmony_ci
2513af6ab5fSopenharmony_ci  private static varHasScope(node: ts.Node, scope: ts.Node): boolean {
2523af6ab5fSopenharmony_ci    while (node !== undefined) {
2533af6ab5fSopenharmony_ci      if (node === scope) {
2543af6ab5fSopenharmony_ci        return true;
2553af6ab5fSopenharmony_ci      }
2563af6ab5fSopenharmony_ci      // eslint-disable-next-line no-param-reassign
2573af6ab5fSopenharmony_ci      node = node.parent;
2583af6ab5fSopenharmony_ci    }
2593af6ab5fSopenharmony_ci    return false;
2603af6ab5fSopenharmony_ci  }
2613af6ab5fSopenharmony_ci
2623af6ab5fSopenharmony_ci  private static varInFunctionForScope(node: ts.Node, scope: ts.Node): boolean {
2633af6ab5fSopenharmony_ci    while (node !== undefined) {
2643af6ab5fSopenharmony_ci      if (Autofixer.isFunctionLikeDeclarationKind(node)) {
2653af6ab5fSopenharmony_ci        break;
2663af6ab5fSopenharmony_ci      }
2673af6ab5fSopenharmony_ci      // eslint-disable-next-line no-param-reassign
2683af6ab5fSopenharmony_ci      node = node.parent;
2693af6ab5fSopenharmony_ci    }
2703af6ab5fSopenharmony_ci    // node now Function like declaration
2713af6ab5fSopenharmony_ci
2723af6ab5fSopenharmony_ci    // node need to check that function like declaration is in scope
2733af6ab5fSopenharmony_ci    if (Autofixer.varHasScope(node, scope)) {
2743af6ab5fSopenharmony_ci      // var use is in function scope, which is in for scope
2753af6ab5fSopenharmony_ci      return true;
2763af6ab5fSopenharmony_ci    }
2773af6ab5fSopenharmony_ci    return false;
2783af6ab5fSopenharmony_ci  }
2793af6ab5fSopenharmony_ci
2803af6ab5fSopenharmony_ci  private static selfDeclared(decl: ts.Node, ident: ts.Node): boolean {
2813af6ab5fSopenharmony_ci    // Do not check the same node
2823af6ab5fSopenharmony_ci    if (ident === decl) {
2833af6ab5fSopenharmony_ci      return false;
2843af6ab5fSopenharmony_ci    }
2853af6ab5fSopenharmony_ci
2863af6ab5fSopenharmony_ci    while (ident !== undefined) {
2873af6ab5fSopenharmony_ci      if (ident.kind === ts.SyntaxKind.VariableDeclaration) {
2883af6ab5fSopenharmony_ci        const declName = (ident as ts.VariableDeclaration).name;
2893af6ab5fSopenharmony_ci        if (declName === decl) {
2903af6ab5fSopenharmony_ci          return true;
2913af6ab5fSopenharmony_ci        }
2923af6ab5fSopenharmony_ci      }
2933af6ab5fSopenharmony_ci      // eslint-disable-next-line no-param-reassign
2943af6ab5fSopenharmony_ci      ident = ident.parent;
2953af6ab5fSopenharmony_ci    }
2963af6ab5fSopenharmony_ci    return false;
2973af6ab5fSopenharmony_ci  }
2983af6ab5fSopenharmony_ci
2993af6ab5fSopenharmony_ci  private static analizeTDZ(decl: ts.VariableDeclaration, identifiers: ts.Node[]): boolean {
3003af6ab5fSopenharmony_ci    for (const ident of identifiers) {
3013af6ab5fSopenharmony_ci      if (Autofixer.selfDeclared(decl.name, ident)) {
3023af6ab5fSopenharmony_ci        return false;
3033af6ab5fSopenharmony_ci      }
3043af6ab5fSopenharmony_ci      if (ident.pos < decl.pos) {
3053af6ab5fSopenharmony_ci        return false;
3063af6ab5fSopenharmony_ci      }
3073af6ab5fSopenharmony_ci    }
3083af6ab5fSopenharmony_ci    return true;
3093af6ab5fSopenharmony_ci  }
3103af6ab5fSopenharmony_ci
3113af6ab5fSopenharmony_ci  private static analizeScope(decl: ts.VariableDeclaration, identifiers: ts.Node[]): boolean {
3123af6ab5fSopenharmony_ci    const scope = Autofixer.findVarScope(decl);
3133af6ab5fSopenharmony_ci    if (scope === undefined) {
3143af6ab5fSopenharmony_ci      return false;
3153af6ab5fSopenharmony_ci    } else if (scope.kind === ts.SyntaxKind.Block) {
3163af6ab5fSopenharmony_ci      for (const ident of identifiers) {
3173af6ab5fSopenharmony_ci        if (!Autofixer.varHasScope(ident, scope)) {
3183af6ab5fSopenharmony_ci          return false;
3193af6ab5fSopenharmony_ci        }
3203af6ab5fSopenharmony_ci      }
3213af6ab5fSopenharmony_ci    } else if (scope.kind === ts.SyntaxKind.SourceFile) {
3223af6ab5fSopenharmony_ci      // Do nothing
3233af6ab5fSopenharmony_ci    } else {
3243af6ab5fSopenharmony_ci      // Unreachable, but check it
3253af6ab5fSopenharmony_ci      return false;
3263af6ab5fSopenharmony_ci    }
3273af6ab5fSopenharmony_ci    return true;
3283af6ab5fSopenharmony_ci  }
3293af6ab5fSopenharmony_ci
3303af6ab5fSopenharmony_ci  private static analizeFor(decl: ts.VariableDeclaration, identifiers: ts.Node[]): boolean {
3313af6ab5fSopenharmony_ci    const forNode = Autofixer.parentInFor(decl);
3323af6ab5fSopenharmony_ci    if (forNode) {
3333af6ab5fSopenharmony_ci      // analize that var is initialized
3343af6ab5fSopenharmony_ci      if (forNode.kind === ts.SyntaxKind.ForInStatement || forNode.kind === ts.SyntaxKind.ForOfStatement) {
3353af6ab5fSopenharmony_ci        const typedForNode = forNode as ts.ForInOrOfStatement;
3363af6ab5fSopenharmony_ci        const forVarDeclarations = (typedForNode.initializer as ts.VariableDeclarationList).declarations;
3373af6ab5fSopenharmony_ci        if (forVarDeclarations.length !== 1) {
3383af6ab5fSopenharmony_ci          return false;
3393af6ab5fSopenharmony_ci        }
3403af6ab5fSopenharmony_ci        const forVarDecl = forVarDeclarations[0];
3413af6ab5fSopenharmony_ci
3423af6ab5fSopenharmony_ci        // our goal to skip declarations in for of/in initializer
3433af6ab5fSopenharmony_ci        if (forVarDecl !== decl && decl.initializer === undefined) {
3443af6ab5fSopenharmony_ci          return false;
3453af6ab5fSopenharmony_ci        }
3463af6ab5fSopenharmony_ci      } else if (decl.initializer === undefined) {
3473af6ab5fSopenharmony_ci        return false;
3483af6ab5fSopenharmony_ci      }
3493af6ab5fSopenharmony_ci
3503af6ab5fSopenharmony_ci      // analize that var uses are only in function block
3513af6ab5fSopenharmony_ci      for (const ident of identifiers) {
3523af6ab5fSopenharmony_ci        if (ident !== decl && !Autofixer.varHasScope(ident, forNode)) {
3533af6ab5fSopenharmony_ci          return false;
3543af6ab5fSopenharmony_ci        }
3553af6ab5fSopenharmony_ci      }
3563af6ab5fSopenharmony_ci
3573af6ab5fSopenharmony_ci      // analize that var is not in function
3583af6ab5fSopenharmony_ci      for (const ident of identifiers) {
3593af6ab5fSopenharmony_ci        if (ident !== decl && Autofixer.varInFunctionForScope(ident, forNode)) {
3603af6ab5fSopenharmony_ci          return false;
3613af6ab5fSopenharmony_ci        }
3623af6ab5fSopenharmony_ci      }
3633af6ab5fSopenharmony_ci    }
3643af6ab5fSopenharmony_ci    return true;
3653af6ab5fSopenharmony_ci  }
3663af6ab5fSopenharmony_ci
3673af6ab5fSopenharmony_ci  private checkVarDeclarations(varDeclList: ts.VariableDeclarationList): boolean {
3683af6ab5fSopenharmony_ci    for (const decl of varDeclList.declarations) {
3693af6ab5fSopenharmony_ci      const symbol = this.typeChecker.getSymbolAtLocation(decl.name);
3703af6ab5fSopenharmony_ci      if (!symbol) {
3713af6ab5fSopenharmony_ci        return false;
3723af6ab5fSopenharmony_ci      }
3733af6ab5fSopenharmony_ci
3743af6ab5fSopenharmony_ci      const identifiers = this.symbolCache.getReferences(symbol);
3753af6ab5fSopenharmony_ci
3763af6ab5fSopenharmony_ci      const declLength = symbol.declarations?.length;
3773af6ab5fSopenharmony_ci      if (!declLength || declLength >= 2) {
3783af6ab5fSopenharmony_ci        return false;
3793af6ab5fSopenharmony_ci      }
3803af6ab5fSopenharmony_ci
3813af6ab5fSopenharmony_ci      // Check for var use in tdz oe self declaration
3823af6ab5fSopenharmony_ci      if (!Autofixer.analizeTDZ(decl, identifiers)) {
3833af6ab5fSopenharmony_ci        return false;
3843af6ab5fSopenharmony_ci      }
3853af6ab5fSopenharmony_ci
3863af6ab5fSopenharmony_ci      // Has use outside scope of declaration?
3873af6ab5fSopenharmony_ci      if (!Autofixer.analizeScope(decl, identifiers)) {
3883af6ab5fSopenharmony_ci        return false;
3893af6ab5fSopenharmony_ci      }
3903af6ab5fSopenharmony_ci
3913af6ab5fSopenharmony_ci      // For analisys
3923af6ab5fSopenharmony_ci      if (!Autofixer.analizeFor(decl, identifiers)) {
3933af6ab5fSopenharmony_ci        return false;
3943af6ab5fSopenharmony_ci      }
3953af6ab5fSopenharmony_ci
3963af6ab5fSopenharmony_ci      if (symbol.getName() === 'let') {
3973af6ab5fSopenharmony_ci        return false;
3983af6ab5fSopenharmony_ci      }
3993af6ab5fSopenharmony_ci    }
4003af6ab5fSopenharmony_ci    return true;
4013af6ab5fSopenharmony_ci  }
4023af6ab5fSopenharmony_ci
4033af6ab5fSopenharmony_ci  private canAutofixNoVar(varDeclList: ts.VariableDeclarationList): boolean {
4043af6ab5fSopenharmony_ci    if (!Autofixer.parentInCaseOrWhile(varDeclList)) {
4053af6ab5fSopenharmony_ci      return false;
4063af6ab5fSopenharmony_ci    }
4073af6ab5fSopenharmony_ci
4083af6ab5fSopenharmony_ci    if (!this.checkVarDeclarations(varDeclList)) {
4093af6ab5fSopenharmony_ci      return false;
4103af6ab5fSopenharmony_ci    }
4113af6ab5fSopenharmony_ci
4123af6ab5fSopenharmony_ci    return true;
4133af6ab5fSopenharmony_ci  }
4143af6ab5fSopenharmony_ci
4153af6ab5fSopenharmony_ci  fixVarDeclaration(node: ts.VariableDeclarationList): Autofix[] | undefined {
4163af6ab5fSopenharmony_ci    const newNode = ts.factory.createVariableDeclarationList(node.declarations, ts.NodeFlags.Let);
4173af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, newNode, node.getSourceFile());
4183af6ab5fSopenharmony_ci    return this.canAutofixNoVar(node) ?
4193af6ab5fSopenharmony_ci      [{ start: node.getStart(), end: node.getEnd(), replacementText: text }] :
4203af6ab5fSopenharmony_ci      undefined;
4213af6ab5fSopenharmony_ci  }
4223af6ab5fSopenharmony_ci
4233af6ab5fSopenharmony_ci  private getFixReturnTypeArrowFunction(funcLikeDecl: ts.FunctionLikeDeclaration, typeNode: ts.TypeNode): string {
4243af6ab5fSopenharmony_ci    if (!funcLikeDecl.body) {
4253af6ab5fSopenharmony_ci      return '';
4263af6ab5fSopenharmony_ci    }
4273af6ab5fSopenharmony_ci    const node = ts.factory.createArrowFunction(
4283af6ab5fSopenharmony_ci      undefined,
4293af6ab5fSopenharmony_ci      funcLikeDecl.typeParameters,
4303af6ab5fSopenharmony_ci      funcLikeDecl.parameters,
4313af6ab5fSopenharmony_ci      typeNode,
4323af6ab5fSopenharmony_ci      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
4333af6ab5fSopenharmony_ci      funcLikeDecl.body
4343af6ab5fSopenharmony_ci    );
4353af6ab5fSopenharmony_ci    return this.printer.printNode(ts.EmitHint.Unspecified, node, funcLikeDecl.getSourceFile());
4363af6ab5fSopenharmony_ci  }
4373af6ab5fSopenharmony_ci
4383af6ab5fSopenharmony_ci  fixMissingReturnType(funcLikeDecl: ts.FunctionLikeDeclaration, typeNode: ts.TypeNode): Autofix[] {
4393af6ab5fSopenharmony_ci    if (ts.isArrowFunction(funcLikeDecl)) {
4403af6ab5fSopenharmony_ci      const text = this.getFixReturnTypeArrowFunction(funcLikeDecl, typeNode);
4413af6ab5fSopenharmony_ci      const startPos = funcLikeDecl.getStart();
4423af6ab5fSopenharmony_ci      const endPos = funcLikeDecl.getEnd();
4433af6ab5fSopenharmony_ci      return [{ start: startPos, end: endPos, replacementText: text }];
4443af6ab5fSopenharmony_ci    }
4453af6ab5fSopenharmony_ci    const text = ': ' + this.printer.printNode(ts.EmitHint.Unspecified, typeNode, funcLikeDecl.getSourceFile());
4463af6ab5fSopenharmony_ci    const pos = Autofixer.getReturnTypePosition(funcLikeDecl);
4473af6ab5fSopenharmony_ci    return [{ start: pos, end: pos, replacementText: text }];
4483af6ab5fSopenharmony_ci  }
4493af6ab5fSopenharmony_ci
4503af6ab5fSopenharmony_ci  dropTypeOnVarDecl(varDecl: ts.VariableDeclaration): Autofix[] {
4513af6ab5fSopenharmony_ci    const newVarDecl = ts.factory.createVariableDeclaration(varDecl.name, undefined, undefined, undefined);
4523af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, newVarDecl, varDecl.getSourceFile());
4533af6ab5fSopenharmony_ci    return [{ start: varDecl.getStart(), end: varDecl.getEnd(), replacementText: text }];
4543af6ab5fSopenharmony_ci  }
4553af6ab5fSopenharmony_ci
4563af6ab5fSopenharmony_ci  fixTypeAssertion(typeAssertion: ts.TypeAssertion): Autofix[] {
4573af6ab5fSopenharmony_ci    const asExpr = ts.factory.createAsExpression(typeAssertion.expression, typeAssertion.type);
4583af6ab5fSopenharmony_ci    const text = this.nonCommentPrinter.printNode(ts.EmitHint.Unspecified, asExpr, typeAssertion.getSourceFile());
4593af6ab5fSopenharmony_ci    return [{ start: typeAssertion.getStart(), end: typeAssertion.getEnd(), replacementText: text }];
4603af6ab5fSopenharmony_ci  }
4613af6ab5fSopenharmony_ci
4623af6ab5fSopenharmony_ci  fixCommaOperator(tsNode: ts.Node): Autofix[] {
4633af6ab5fSopenharmony_ci    const tsExprNode = tsNode as ts.BinaryExpression;
4643af6ab5fSopenharmony_ci    const text = this.recursiveCommaOperator(tsExprNode);
4653af6ab5fSopenharmony_ci    return [{ start: tsExprNode.parent.getFullStart(), end: tsExprNode.parent.getEnd(), replacementText: text }];
4663af6ab5fSopenharmony_ci  }
4673af6ab5fSopenharmony_ci
4683af6ab5fSopenharmony_ci  private recursiveCommaOperator(tsExprNode: ts.BinaryExpression): string {
4693af6ab5fSopenharmony_ci    let text = '';
4703af6ab5fSopenharmony_ci    if (tsExprNode.operatorToken.kind !== ts.SyntaxKind.CommaToken) {
4713af6ab5fSopenharmony_ci      return tsExprNode.getFullText() + ';';
4723af6ab5fSopenharmony_ci    }
4733af6ab5fSopenharmony_ci
4743af6ab5fSopenharmony_ci    if (tsExprNode.left.kind === ts.SyntaxKind.BinaryExpression) {
4753af6ab5fSopenharmony_ci      text += this.recursiveCommaOperator(tsExprNode.left as ts.BinaryExpression);
4763af6ab5fSopenharmony_ci      text += '\n' + tsExprNode.right.getFullText() + ';';
4773af6ab5fSopenharmony_ci    } else {
4783af6ab5fSopenharmony_ci      const leftText = tsExprNode.left.getFullText();
4793af6ab5fSopenharmony_ci      const rightText = tsExprNode.right.getFullText();
4803af6ab5fSopenharmony_ci      text = leftText + ';\n' + rightText + ';';
4813af6ab5fSopenharmony_ci    }
4823af6ab5fSopenharmony_ci
4833af6ab5fSopenharmony_ci    return text;
4843af6ab5fSopenharmony_ci  }
4853af6ab5fSopenharmony_ci
4863af6ab5fSopenharmony_ci  private getEnumMembers(node: ts.Node, enumDeclsInFile: ts.Declaration[], result: Autofix[] | undefined): void {
4873af6ab5fSopenharmony_ci    if (result === undefined || !ts.isEnumDeclaration(node)) {
4883af6ab5fSopenharmony_ci      return;
4893af6ab5fSopenharmony_ci    }
4903af6ab5fSopenharmony_ci
4913af6ab5fSopenharmony_ci    if (result.length) {
4923af6ab5fSopenharmony_ci      result.push({ start: node.getStart(), end: node.getEnd(), replacementText: '' });
4933af6ab5fSopenharmony_ci      return;
4943af6ab5fSopenharmony_ci    }
4953af6ab5fSopenharmony_ci
4963af6ab5fSopenharmony_ci    const members: ts.EnumMember[] = [];
4973af6ab5fSopenharmony_ci    for (const decl of enumDeclsInFile) {
4983af6ab5fSopenharmony_ci      for (const member of (decl as ts.EnumDeclaration).members) {
4993af6ab5fSopenharmony_ci        if (
5003af6ab5fSopenharmony_ci          member.initializer &&
5013af6ab5fSopenharmony_ci          member.initializer.kind !== ts.SyntaxKind.NumericLiteral &&
5023af6ab5fSopenharmony_ci          member.initializer.kind !== ts.SyntaxKind.StringLiteral
5033af6ab5fSopenharmony_ci        ) {
5043af6ab5fSopenharmony_ci          result = undefined;
5053af6ab5fSopenharmony_ci          return;
5063af6ab5fSopenharmony_ci        }
5073af6ab5fSopenharmony_ci      }
5083af6ab5fSopenharmony_ci      members.push(...(decl as ts.EnumDeclaration).members);
5093af6ab5fSopenharmony_ci    }
5103af6ab5fSopenharmony_ci
5113af6ab5fSopenharmony_ci    const fullEnum = ts.factory.createEnumDeclaration(node.modifiers, node.name, members);
5123af6ab5fSopenharmony_ci    const fullText = this.printer.printNode(ts.EmitHint.Unspecified, fullEnum, node.getSourceFile());
5133af6ab5fSopenharmony_ci    result.push({ start: node.getStart(), end: node.getEnd(), replacementText: fullText });
5143af6ab5fSopenharmony_ci  }
5153af6ab5fSopenharmony_ci
5163af6ab5fSopenharmony_ci  fixEnumMerging(enumSymbol: ts.Symbol, enumDeclsInFile: ts.Declaration[]): Autofix[] | undefined {
5173af6ab5fSopenharmony_ci    if (this.enumMergingCache.has(enumSymbol)) {
5183af6ab5fSopenharmony_ci      return this.enumMergingCache.get(enumSymbol);
5193af6ab5fSopenharmony_ci    }
5203af6ab5fSopenharmony_ci
5213af6ab5fSopenharmony_ci    if (enumDeclsInFile.length <= 1) {
5223af6ab5fSopenharmony_ci      this.enumMergingCache.set(enumSymbol, undefined);
5233af6ab5fSopenharmony_ci      return undefined;
5243af6ab5fSopenharmony_ci    }
5253af6ab5fSopenharmony_ci
5263af6ab5fSopenharmony_ci    let result: Autofix[] | undefined = [];
5273af6ab5fSopenharmony_ci    this.symbolCache.getReferences(enumSymbol).forEach((node) => {
5283af6ab5fSopenharmony_ci      this.getEnumMembers(node, enumDeclsInFile, result);
5293af6ab5fSopenharmony_ci    });
5303af6ab5fSopenharmony_ci    if (!result?.length) {
5313af6ab5fSopenharmony_ci      result = undefined;
5323af6ab5fSopenharmony_ci    }
5333af6ab5fSopenharmony_ci
5343af6ab5fSopenharmony_ci    this.enumMergingCache.set(enumSymbol, result);
5353af6ab5fSopenharmony_ci    return result;
5363af6ab5fSopenharmony_ci  }
5373af6ab5fSopenharmony_ci
5383af6ab5fSopenharmony_ci  private readonly enumMergingCache = new Map<ts.Symbol, Autofix[] | undefined>();
5393af6ab5fSopenharmony_ci
5403af6ab5fSopenharmony_ci  private readonly printer: ts.Printer = ts.createPrinter({
5413af6ab5fSopenharmony_ci    omitTrailingSemicolon: false,
5423af6ab5fSopenharmony_ci    removeComments: false,
5433af6ab5fSopenharmony_ci    newLine: ts.NewLineKind.LineFeed
5443af6ab5fSopenharmony_ci  });
5453af6ab5fSopenharmony_ci
5463af6ab5fSopenharmony_ci  private readonly nonCommentPrinter: ts.Printer = ts.createPrinter({
5473af6ab5fSopenharmony_ci    omitTrailingSemicolon: false,
5483af6ab5fSopenharmony_ci    removeComments: true,
5493af6ab5fSopenharmony_ci    newLine: ts.NewLineKind.LineFeed
5503af6ab5fSopenharmony_ci  });
5513af6ab5fSopenharmony_ci
5523af6ab5fSopenharmony_ci  private static getReturnTypePosition(funcLikeDecl: ts.FunctionLikeDeclaration): number {
5533af6ab5fSopenharmony_ci    if (funcLikeDecl.body) {
5543af6ab5fSopenharmony_ci
5553af6ab5fSopenharmony_ci      /*
5563af6ab5fSopenharmony_ci       * Find position of the first node or token that follows parameters.
5573af6ab5fSopenharmony_ci       * After that, iterate over child nodes in reverse order, until found
5583af6ab5fSopenharmony_ci       * first closing parenthesis.
5593af6ab5fSopenharmony_ci       */
5603af6ab5fSopenharmony_ci      const postParametersPosition = ts.isArrowFunction(funcLikeDecl) ?
5613af6ab5fSopenharmony_ci        funcLikeDecl.equalsGreaterThanToken.getStart() :
5623af6ab5fSopenharmony_ci        funcLikeDecl.body.getStart();
5633af6ab5fSopenharmony_ci
5643af6ab5fSopenharmony_ci      const children = funcLikeDecl.getChildren();
5653af6ab5fSopenharmony_ci      for (let i = children.length - 1; i >= 0; i--) {
5663af6ab5fSopenharmony_ci        const child = children[i];
5673af6ab5fSopenharmony_ci        if (child.kind === ts.SyntaxKind.CloseParenToken && child.getEnd() <= postParametersPosition) {
5683af6ab5fSopenharmony_ci          return child.getEnd();
5693af6ab5fSopenharmony_ci        }
5703af6ab5fSopenharmony_ci      }
5713af6ab5fSopenharmony_ci    }
5723af6ab5fSopenharmony_ci
5733af6ab5fSopenharmony_ci    // Shouldn't get here.
5743af6ab5fSopenharmony_ci    return -1;
5753af6ab5fSopenharmony_ci  }
5763af6ab5fSopenharmony_ci
5773af6ab5fSopenharmony_ci  private static needsParentheses(node: ts.FunctionExpression): boolean {
5783af6ab5fSopenharmony_ci    const parent = node.parent;
5793af6ab5fSopenharmony_ci    return (
5803af6ab5fSopenharmony_ci      ts.isPrefixUnaryExpression(parent) ||
5813af6ab5fSopenharmony_ci      ts.isPostfixUnaryExpression(parent) ||
5823af6ab5fSopenharmony_ci      ts.isPropertyAccessExpression(parent) ||
5833af6ab5fSopenharmony_ci      ts.isElementAccessExpression(parent) ||
5843af6ab5fSopenharmony_ci      ts.isTypeOfExpression(parent) ||
5853af6ab5fSopenharmony_ci      ts.isVoidExpression(parent) ||
5863af6ab5fSopenharmony_ci      ts.isAwaitExpression(parent) ||
5873af6ab5fSopenharmony_ci      ts.isCallExpression(parent) && node === parent.expression ||
5883af6ab5fSopenharmony_ci      ts.isBinaryExpression(parent) && !isAssignmentOperator(parent.operatorToken)
5893af6ab5fSopenharmony_ci    );
5903af6ab5fSopenharmony_ci  }
5913af6ab5fSopenharmony_ci
5923af6ab5fSopenharmony_ci  fixCtorParameterProperties(
5933af6ab5fSopenharmony_ci    ctorDecl: ts.ConstructorDeclaration,
5943af6ab5fSopenharmony_ci    paramTypes: ts.TypeNode[] | undefined
5953af6ab5fSopenharmony_ci  ): Autofix[] | undefined {
5963af6ab5fSopenharmony_ci    if (paramTypes === undefined) {
5973af6ab5fSopenharmony_ci      return undefined;
5983af6ab5fSopenharmony_ci    }
5993af6ab5fSopenharmony_ci
6003af6ab5fSopenharmony_ci    const fieldInitStmts: ts.Statement[] = [];
6013af6ab5fSopenharmony_ci    const newFieldPos = ctorDecl.getStart();
6023af6ab5fSopenharmony_ci    const autofixes: Autofix[] = [{ start: newFieldPos, end: newFieldPos, replacementText: '' }];
6033af6ab5fSopenharmony_ci
6043af6ab5fSopenharmony_ci    for (let i = 0; i < ctorDecl.parameters.length; i++) {
6053af6ab5fSopenharmony_ci      this.fixCtorParameterPropertiesProcessParam(
6063af6ab5fSopenharmony_ci        ctorDecl.parameters[i],
6073af6ab5fSopenharmony_ci        paramTypes[i],
6083af6ab5fSopenharmony_ci        ctorDecl.getSourceFile(),
6093af6ab5fSopenharmony_ci        fieldInitStmts,
6103af6ab5fSopenharmony_ci        autofixes
6113af6ab5fSopenharmony_ci      );
6123af6ab5fSopenharmony_ci    }
6133af6ab5fSopenharmony_ci
6143af6ab5fSopenharmony_ci    // Note: Bodyless ctors can't have parameter properties.
6153af6ab5fSopenharmony_ci    if (ctorDecl.body) {
6163af6ab5fSopenharmony_ci      const newBody = ts.factory.createBlock(fieldInitStmts.concat(ctorDecl.body.statements), true);
6173af6ab5fSopenharmony_ci      const newBodyText = this.printer.printNode(ts.EmitHint.Unspecified, newBody, ctorDecl.getSourceFile());
6183af6ab5fSopenharmony_ci      autofixes.push({ start: ctorDecl.body.getStart(), end: ctorDecl.body.getEnd(), replacementText: newBodyText });
6193af6ab5fSopenharmony_ci    }
6203af6ab5fSopenharmony_ci
6213af6ab5fSopenharmony_ci    return autofixes;
6223af6ab5fSopenharmony_ci  }
6233af6ab5fSopenharmony_ci
6243af6ab5fSopenharmony_ci  private fixCtorParameterPropertiesProcessParam(
6253af6ab5fSopenharmony_ci    param: ts.ParameterDeclaration,
6263af6ab5fSopenharmony_ci    paramType: ts.TypeNode,
6273af6ab5fSopenharmony_ci    sourceFile: ts.SourceFile,
6283af6ab5fSopenharmony_ci    fieldInitStmts: ts.Statement[],
6293af6ab5fSopenharmony_ci    autofixes: Autofix[]
6303af6ab5fSopenharmony_ci  ): void {
6313af6ab5fSopenharmony_ci    // Parameter property can not be a destructuring parameter.
6323af6ab5fSopenharmony_ci    if (!ts.isIdentifier(param.name)) {
6333af6ab5fSopenharmony_ci      return;
6343af6ab5fSopenharmony_ci    }
6353af6ab5fSopenharmony_ci
6363af6ab5fSopenharmony_ci    if (this.utils.hasAccessModifier(param)) {
6373af6ab5fSopenharmony_ci      const propIdent = ts.factory.createIdentifier(param.name.text);
6383af6ab5fSopenharmony_ci
6393af6ab5fSopenharmony_ci      const newFieldNode = ts.factory.createPropertyDeclaration(
6403af6ab5fSopenharmony_ci        ts.getModifiers(param),
6413af6ab5fSopenharmony_ci        propIdent,
6423af6ab5fSopenharmony_ci        undefined,
6433af6ab5fSopenharmony_ci        paramType,
6443af6ab5fSopenharmony_ci        undefined
6453af6ab5fSopenharmony_ci      );
6463af6ab5fSopenharmony_ci      const newFieldText = this.printer.printNode(ts.EmitHint.Unspecified, newFieldNode, sourceFile) + '\n';
6473af6ab5fSopenharmony_ci      autofixes[0].replacementText += newFieldText;
6483af6ab5fSopenharmony_ci
6493af6ab5fSopenharmony_ci      const newParamDecl = ts.factory.createParameterDeclaration(
6503af6ab5fSopenharmony_ci        undefined,
6513af6ab5fSopenharmony_ci        undefined,
6523af6ab5fSopenharmony_ci        param.name,
6533af6ab5fSopenharmony_ci        param.questionToken,
6543af6ab5fSopenharmony_ci        param.type,
6553af6ab5fSopenharmony_ci        param.initializer
6563af6ab5fSopenharmony_ci      );
6573af6ab5fSopenharmony_ci      const newParamText = this.printer.printNode(ts.EmitHint.Unspecified, newParamDecl, sourceFile);
6583af6ab5fSopenharmony_ci      autofixes.push({ start: param.getStart(), end: param.getEnd(), replacementText: newParamText });
6593af6ab5fSopenharmony_ci
6603af6ab5fSopenharmony_ci      fieldInitStmts.push(
6613af6ab5fSopenharmony_ci        ts.factory.createExpressionStatement(
6623af6ab5fSopenharmony_ci          ts.factory.createAssignment(
6633af6ab5fSopenharmony_ci            ts.factory.createPropertyAccessExpression(ts.factory.createThis(), propIdent),
6643af6ab5fSopenharmony_ci            propIdent
6653af6ab5fSopenharmony_ci          )
6663af6ab5fSopenharmony_ci        )
6673af6ab5fSopenharmony_ci      );
6683af6ab5fSopenharmony_ci    }
6693af6ab5fSopenharmony_ci  }
6703af6ab5fSopenharmony_ci
6713af6ab5fSopenharmony_ci  fixPrivateIdentifier(node: ts.PrivateIdentifier): Autofix[] | undefined {
6723af6ab5fSopenharmony_ci    const classMember = this.typeChecker.getSymbolAtLocation(node);
6733af6ab5fSopenharmony_ci    if (!classMember || (classMember.getFlags() & ts.SymbolFlags.ClassMember) === 0 || !classMember.valueDeclaration) {
6743af6ab5fSopenharmony_ci      return undefined;
6753af6ab5fSopenharmony_ci    }
6763af6ab5fSopenharmony_ci
6773af6ab5fSopenharmony_ci    if (this.privateIdentifierCache.has(classMember)) {
6783af6ab5fSopenharmony_ci      return this.privateIdentifierCache.get(classMember);
6793af6ab5fSopenharmony_ci    }
6803af6ab5fSopenharmony_ci
6813af6ab5fSopenharmony_ci    const memberDecl = classMember.valueDeclaration as ts.ClassElement;
6823af6ab5fSopenharmony_ci    const parentDecl = memberDecl.parent;
6833af6ab5fSopenharmony_ci    if (!ts.isClassLike(parentDecl) || this.utils.classMemberHasDuplicateName(memberDecl, parentDecl, true)) {
6843af6ab5fSopenharmony_ci      this.privateIdentifierCache.set(classMember, undefined);
6853af6ab5fSopenharmony_ci      return undefined;
6863af6ab5fSopenharmony_ci    }
6873af6ab5fSopenharmony_ci
6883af6ab5fSopenharmony_ci    let result: Autofix[] | undefined = [];
6893af6ab5fSopenharmony_ci    this.symbolCache.getReferences(classMember).forEach((ident) => {
6903af6ab5fSopenharmony_ci      if (ts.isPrivateIdentifier(ident)) {
6913af6ab5fSopenharmony_ci        result!.push(this.fixSinglePrivateIdentifier(ident));
6923af6ab5fSopenharmony_ci      }
6933af6ab5fSopenharmony_ci    });
6943af6ab5fSopenharmony_ci    if (!result.length) {
6953af6ab5fSopenharmony_ci      result = undefined;
6963af6ab5fSopenharmony_ci    }
6973af6ab5fSopenharmony_ci
6983af6ab5fSopenharmony_ci    this.privateIdentifierCache.set(classMember, result);
6993af6ab5fSopenharmony_ci    return result;
7003af6ab5fSopenharmony_ci  }
7013af6ab5fSopenharmony_ci
7023af6ab5fSopenharmony_ci  private isFunctionDeclarationFirst(tsFunctionDeclaration: ts.FunctionDeclaration): boolean {
7033af6ab5fSopenharmony_ci    if (tsFunctionDeclaration.name === undefined) {
7043af6ab5fSopenharmony_ci      return false;
7053af6ab5fSopenharmony_ci    }
7063af6ab5fSopenharmony_ci
7073af6ab5fSopenharmony_ci    const symbol = this.typeChecker.getSymbolAtLocation(tsFunctionDeclaration.name);
7083af6ab5fSopenharmony_ci    if (symbol === undefined) {
7093af6ab5fSopenharmony_ci      return false;
7103af6ab5fSopenharmony_ci    }
7113af6ab5fSopenharmony_ci
7123af6ab5fSopenharmony_ci    let minPos = tsFunctionDeclaration.pos;
7133af6ab5fSopenharmony_ci    this.symbolCache.getReferences(symbol).forEach((ident) => {
7143af6ab5fSopenharmony_ci      if (ident.pos < minPos) {
7153af6ab5fSopenharmony_ci        minPos = ident.pos;
7163af6ab5fSopenharmony_ci      }
7173af6ab5fSopenharmony_ci    });
7183af6ab5fSopenharmony_ci
7193af6ab5fSopenharmony_ci    return minPos >= tsFunctionDeclaration.pos;
7203af6ab5fSopenharmony_ci  }
7213af6ab5fSopenharmony_ci
7223af6ab5fSopenharmony_ci  fixNestedFunction(tsFunctionDeclaration: ts.FunctionDeclaration): Autofix[] | undefined {
7233af6ab5fSopenharmony_ci    const isGenerator = tsFunctionDeclaration.asteriskToken !== undefined;
7243af6ab5fSopenharmony_ci    const hasThisKeyword =
7253af6ab5fSopenharmony_ci      tsFunctionDeclaration.body === undefined ? false : scopeContainsThis(tsFunctionDeclaration.body);
7263af6ab5fSopenharmony_ci    const canBeFixed = !isGenerator && !hasThisKeyword;
7273af6ab5fSopenharmony_ci    if (!canBeFixed) {
7283af6ab5fSopenharmony_ci      return undefined;
7293af6ab5fSopenharmony_ci    }
7303af6ab5fSopenharmony_ci
7313af6ab5fSopenharmony_ci    const name = tsFunctionDeclaration.name?.escapedText;
7323af6ab5fSopenharmony_ci    const type = tsFunctionDeclaration.type;
7333af6ab5fSopenharmony_ci    const body = tsFunctionDeclaration.body;
7343af6ab5fSopenharmony_ci    if (!name || !type || !body) {
7353af6ab5fSopenharmony_ci      return undefined;
7363af6ab5fSopenharmony_ci    }
7373af6ab5fSopenharmony_ci
7383af6ab5fSopenharmony_ci    // Check only illegal decorators, cause all decorators for function declaration are illegal
7393af6ab5fSopenharmony_ci    if (ts.getIllegalDecorators(tsFunctionDeclaration)) {
7403af6ab5fSopenharmony_ci      return undefined;
7413af6ab5fSopenharmony_ci    }
7423af6ab5fSopenharmony_ci
7433af6ab5fSopenharmony_ci    if (!this.isFunctionDeclarationFirst(tsFunctionDeclaration)) {
7443af6ab5fSopenharmony_ci      return undefined;
7453af6ab5fSopenharmony_ci    }
7463af6ab5fSopenharmony_ci
7473af6ab5fSopenharmony_ci    const typeParameters = tsFunctionDeclaration.typeParameters;
7483af6ab5fSopenharmony_ci    const parameters = tsFunctionDeclaration.parameters;
7493af6ab5fSopenharmony_ci    const modifiers = ts.getModifiers(tsFunctionDeclaration);
7503af6ab5fSopenharmony_ci
7513af6ab5fSopenharmony_ci    const token = ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken);
7523af6ab5fSopenharmony_ci    const typeDecl = ts.factory.createFunctionTypeNode(typeParameters, parameters, type);
7533af6ab5fSopenharmony_ci    const arrowFunc = ts.factory.createArrowFunction(modifiers, typeParameters, parameters, type, token, body);
7543af6ab5fSopenharmony_ci
7553af6ab5fSopenharmony_ci    const declaration: ts.VariableDeclaration = ts.factory.createVariableDeclaration(
7563af6ab5fSopenharmony_ci      name,
7573af6ab5fSopenharmony_ci      undefined,
7583af6ab5fSopenharmony_ci      typeDecl,
7593af6ab5fSopenharmony_ci      arrowFunc
7603af6ab5fSopenharmony_ci    );
7613af6ab5fSopenharmony_ci    const list: ts.VariableDeclarationList = ts.factory.createVariableDeclarationList([declaration], ts.NodeFlags.Let);
7623af6ab5fSopenharmony_ci
7633af6ab5fSopenharmony_ci    const statement = ts.factory.createVariableStatement(modifiers, list);
7643af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, statement, tsFunctionDeclaration.getSourceFile());
7653af6ab5fSopenharmony_ci    return [{ start: tsFunctionDeclaration.getStart(), end: tsFunctionDeclaration.getEnd(), replacementText: text }];
7663af6ab5fSopenharmony_ci  }
7673af6ab5fSopenharmony_ci
7683af6ab5fSopenharmony_ci  fixMultipleStaticBlocks(nodes: ts.Node[]): Autofix[] | undefined {
7693af6ab5fSopenharmony_ci    const autofix: Autofix[] | undefined = [];
7703af6ab5fSopenharmony_ci    let body = (nodes[0] as ts.ClassStaticBlockDeclaration).body;
7713af6ab5fSopenharmony_ci    let bodyStatements: ts.Statement[] = [];
7723af6ab5fSopenharmony_ci    bodyStatements = bodyStatements.concat(body.statements);
7733af6ab5fSopenharmony_ci    for (let i = 1; i < nodes.length; i++) {
7743af6ab5fSopenharmony_ci      bodyStatements = bodyStatements.concat((nodes[i] as ts.ClassStaticBlockDeclaration).body.statements);
7753af6ab5fSopenharmony_ci      autofix[i] = { start: nodes[i].getStart(), end: nodes[i].getEnd(), replacementText: '' };
7763af6ab5fSopenharmony_ci    }
7773af6ab5fSopenharmony_ci    body = ts.factory.createBlock(bodyStatements, true);
7783af6ab5fSopenharmony_ci    // static blocks shouldn't have modifiers
7793af6ab5fSopenharmony_ci    const statickBlock = ts.factory.createClassStaticBlockDeclaration(body);
7803af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, statickBlock, nodes[0].getSourceFile());
7813af6ab5fSopenharmony_ci    autofix[0] = { start: nodes[0].getStart(), end: nodes[0].getEnd(), replacementText: text };
7823af6ab5fSopenharmony_ci    return autofix;
7833af6ab5fSopenharmony_ci  }
7843af6ab5fSopenharmony_ci
7853af6ab5fSopenharmony_ci  private readonly privateIdentifierCache = new Map<ts.Symbol, Autofix[] | undefined>();
7863af6ab5fSopenharmony_ci
7873af6ab5fSopenharmony_ci  private fixSinglePrivateIdentifier(ident: ts.PrivateIdentifier): Autofix {
7883af6ab5fSopenharmony_ci    if (
7893af6ab5fSopenharmony_ci      ts.isPropertyDeclaration(ident.parent) ||
7903af6ab5fSopenharmony_ci      ts.isMethodDeclaration(ident.parent) ||
7913af6ab5fSopenharmony_ci      ts.isGetAccessorDeclaration(ident.parent) ||
7923af6ab5fSopenharmony_ci      ts.isSetAccessorDeclaration(ident.parent)
7933af6ab5fSopenharmony_ci    ) {
7943af6ab5fSopenharmony_ci      // Note: 'private' modifier should always be first.
7953af6ab5fSopenharmony_ci      const mods = ts.getModifiers(ident.parent);
7963af6ab5fSopenharmony_ci      const newMods: ts.Modifier[] = [ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword)];
7973af6ab5fSopenharmony_ci      if (mods) {
7983af6ab5fSopenharmony_ci        for (const mod of mods) {
7993af6ab5fSopenharmony_ci          newMods.push(ts.factory.createModifier(mod.kind));
8003af6ab5fSopenharmony_ci        }
8013af6ab5fSopenharmony_ci      }
8023af6ab5fSopenharmony_ci
8033af6ab5fSopenharmony_ci      const newName = ident.text.slice(1, ident.text.length);
8043af6ab5fSopenharmony_ci      const newDecl = Autofixer.replacePrivateIdentInDeclarationName(newMods, newName, ident.parent);
8053af6ab5fSopenharmony_ci      const text = this.printer.printNode(ts.EmitHint.Unspecified, newDecl, ident.getSourceFile());
8063af6ab5fSopenharmony_ci      return { start: ident.parent.getStart(), end: ident.parent.getEnd(), replacementText: text };
8073af6ab5fSopenharmony_ci    }
8083af6ab5fSopenharmony_ci
8093af6ab5fSopenharmony_ci    return {
8103af6ab5fSopenharmony_ci      start: ident.getStart(),
8113af6ab5fSopenharmony_ci      end: ident.getEnd(),
8123af6ab5fSopenharmony_ci      replacementText: ident.text.slice(1, ident.text.length)
8133af6ab5fSopenharmony_ci    };
8143af6ab5fSopenharmony_ci  }
8153af6ab5fSopenharmony_ci
8163af6ab5fSopenharmony_ci  private static replacePrivateIdentInDeclarationName(
8173af6ab5fSopenharmony_ci    mods: ts.Modifier[],
8183af6ab5fSopenharmony_ci    name: string,
8193af6ab5fSopenharmony_ci    oldDecl: ts.PropertyDeclaration | ts.MethodDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration
8203af6ab5fSopenharmony_ci  ): ts.Declaration {
8213af6ab5fSopenharmony_ci    if (ts.isPropertyDeclaration(oldDecl)) {
8223af6ab5fSopenharmony_ci      return ts.factory.createPropertyDeclaration(
8233af6ab5fSopenharmony_ci        mods,
8243af6ab5fSopenharmony_ci        ts.factory.createIdentifier(name),
8253af6ab5fSopenharmony_ci        oldDecl.questionToken ?? oldDecl.exclamationToken,
8263af6ab5fSopenharmony_ci        oldDecl.type,
8273af6ab5fSopenharmony_ci        oldDecl.initializer
8283af6ab5fSopenharmony_ci      );
8293af6ab5fSopenharmony_ci    } else if (ts.isMethodDeclaration(oldDecl)) {
8303af6ab5fSopenharmony_ci      return ts.factory.createMethodDeclaration(
8313af6ab5fSopenharmony_ci        mods,
8323af6ab5fSopenharmony_ci        oldDecl.asteriskToken,
8333af6ab5fSopenharmony_ci        ts.factory.createIdentifier(name),
8343af6ab5fSopenharmony_ci        oldDecl.questionToken,
8353af6ab5fSopenharmony_ci        oldDecl.typeParameters,
8363af6ab5fSopenharmony_ci        oldDecl.parameters,
8373af6ab5fSopenharmony_ci        oldDecl.type,
8383af6ab5fSopenharmony_ci        oldDecl.body
8393af6ab5fSopenharmony_ci      );
8403af6ab5fSopenharmony_ci    } else if (ts.isGetAccessorDeclaration(oldDecl)) {
8413af6ab5fSopenharmony_ci      return ts.factory.createGetAccessorDeclaration(
8423af6ab5fSopenharmony_ci        mods,
8433af6ab5fSopenharmony_ci        ts.factory.createIdentifier(name),
8443af6ab5fSopenharmony_ci        oldDecl.parameters,
8453af6ab5fSopenharmony_ci        oldDecl.type,
8463af6ab5fSopenharmony_ci        oldDecl.body
8473af6ab5fSopenharmony_ci      );
8483af6ab5fSopenharmony_ci    }
8493af6ab5fSopenharmony_ci    return ts.factory.createSetAccessorDeclaration(
8503af6ab5fSopenharmony_ci      mods,
8513af6ab5fSopenharmony_ci      ts.factory.createIdentifier(name),
8523af6ab5fSopenharmony_ci      oldDecl.parameters,
8533af6ab5fSopenharmony_ci      oldDecl.body
8543af6ab5fSopenharmony_ci    );
8553af6ab5fSopenharmony_ci  }
8563af6ab5fSopenharmony_ci
8573af6ab5fSopenharmony_ci  fixRecordObjectLiteral(objectLiteralExpr: ts.ObjectLiteralExpression): Autofix[] | undefined {
8583af6ab5fSopenharmony_ci    const autofix: Autofix[] = [];
8593af6ab5fSopenharmony_ci
8603af6ab5fSopenharmony_ci    for (const prop of objectLiteralExpr.properties) {
8613af6ab5fSopenharmony_ci      if (!prop.name) {
8623af6ab5fSopenharmony_ci        return undefined;
8633af6ab5fSopenharmony_ci      }
8643af6ab5fSopenharmony_ci      if (this.utils.isValidRecordObjectLiteralKey(prop.name)) {
8653af6ab5fSopenharmony_ci        // Skip property with a valid property key.
8663af6ab5fSopenharmony_ci        continue;
8673af6ab5fSopenharmony_ci      }
8683af6ab5fSopenharmony_ci      if (!ts.isIdentifier(prop.name)) {
8693af6ab5fSopenharmony_ci        // Can only fix identifier name.
8703af6ab5fSopenharmony_ci        return undefined;
8713af6ab5fSopenharmony_ci      }
8723af6ab5fSopenharmony_ci
8733af6ab5fSopenharmony_ci      const stringLiteralName = ts.factory.createStringLiteralFromNode(prop.name, true);
8743af6ab5fSopenharmony_ci      const text = this.printer.printNode(ts.EmitHint.Unspecified, stringLiteralName, prop.name.getSourceFile());
8753af6ab5fSopenharmony_ci      autofix.push({ start: prop.name.getStart(), end: prop.name.getEnd(), replacementText: text });
8763af6ab5fSopenharmony_ci    }
8773af6ab5fSopenharmony_ci
8783af6ab5fSopenharmony_ci    return autofix;
8793af6ab5fSopenharmony_ci  }
8803af6ab5fSopenharmony_ci
8813af6ab5fSopenharmony_ci  fixUntypedObjectLiteral(
8823af6ab5fSopenharmony_ci    objectLiteralExpr: ts.ObjectLiteralExpression,
8833af6ab5fSopenharmony_ci    objectLiteralType: ts.Type | undefined
8843af6ab5fSopenharmony_ci  ): Autofix[] | undefined {
8853af6ab5fSopenharmony_ci    if (objectLiteralType) {
8863af6ab5fSopenharmony_ci
8873af6ab5fSopenharmony_ci      /*
8883af6ab5fSopenharmony_ci       * Special case for object literal of Record type: fix object's property names
8893af6ab5fSopenharmony_ci       * by replacing identifiers with string literals.
8903af6ab5fSopenharmony_ci       */
8913af6ab5fSopenharmony_ci      if (this.utils.isStdRecordType(this.utils.getNonNullableType(objectLiteralType))) {
8923af6ab5fSopenharmony_ci        return this.fixRecordObjectLiteral(objectLiteralExpr);
8933af6ab5fSopenharmony_ci      }
8943af6ab5fSopenharmony_ci
8953af6ab5fSopenharmony_ci      // Can't fix when object literal has a contextual type.
8963af6ab5fSopenharmony_ci      return undefined;
8973af6ab5fSopenharmony_ci    }
8983af6ab5fSopenharmony_ci
8993af6ab5fSopenharmony_ci    const enclosingStmt = TsUtils.getEnclosingTopLevelStatement(objectLiteralExpr);
9003af6ab5fSopenharmony_ci    if (!enclosingStmt) {
9013af6ab5fSopenharmony_ci      return undefined;
9023af6ab5fSopenharmony_ci    }
9033af6ab5fSopenharmony_ci
9043af6ab5fSopenharmony_ci    const newInterfaceProps = this.getInterfacePropertiesFromObjectLiteral(objectLiteralExpr, enclosingStmt);
9053af6ab5fSopenharmony_ci    if (!newInterfaceProps) {
9063af6ab5fSopenharmony_ci      return undefined;
9073af6ab5fSopenharmony_ci    }
9083af6ab5fSopenharmony_ci
9093af6ab5fSopenharmony_ci    const srcFile = objectLiteralExpr.getSourceFile();
9103af6ab5fSopenharmony_ci    const newInterfaceName = TsUtils.generateUniqueName(this.objectLiteralInterfaceNameGenerator, srcFile);
9113af6ab5fSopenharmony_ci    if (!newInterfaceName) {
9123af6ab5fSopenharmony_ci      return undefined;
9133af6ab5fSopenharmony_ci    }
9143af6ab5fSopenharmony_ci
9153af6ab5fSopenharmony_ci    return [
9163af6ab5fSopenharmony_ci      this.createNewInterface(srcFile, newInterfaceName, newInterfaceProps, enclosingStmt.getStart()),
9173af6ab5fSopenharmony_ci      this.fixObjectLiteralExpression(srcFile, newInterfaceName, objectLiteralExpr)
9183af6ab5fSopenharmony_ci    ];
9193af6ab5fSopenharmony_ci  }
9203af6ab5fSopenharmony_ci
9213af6ab5fSopenharmony_ci  private getInterfacePropertiesFromObjectLiteral(
9223af6ab5fSopenharmony_ci    objectLiteralExpr: ts.ObjectLiteralExpression,
9233af6ab5fSopenharmony_ci    enclosingStmt: ts.Node
9243af6ab5fSopenharmony_ci  ): ts.PropertySignature[] | undefined {
9253af6ab5fSopenharmony_ci    const interfaceProps: ts.PropertySignature[] = [];
9263af6ab5fSopenharmony_ci    for (const prop of objectLiteralExpr.properties) {
9273af6ab5fSopenharmony_ci      const interfaceProp = this.getInterfacePropertyFromObjectLiteralElement(prop, enclosingStmt);
9283af6ab5fSopenharmony_ci      if (!interfaceProp) {
9293af6ab5fSopenharmony_ci        return undefined;
9303af6ab5fSopenharmony_ci      }
9313af6ab5fSopenharmony_ci      interfaceProps.push(interfaceProp);
9323af6ab5fSopenharmony_ci    }
9333af6ab5fSopenharmony_ci    return interfaceProps;
9343af6ab5fSopenharmony_ci  }
9353af6ab5fSopenharmony_ci
9363af6ab5fSopenharmony_ci  private getInterfacePropertyFromObjectLiteralElement(
9373af6ab5fSopenharmony_ci    prop: ts.ObjectLiteralElementLike,
9383af6ab5fSopenharmony_ci    enclosingStmt: ts.Node
9393af6ab5fSopenharmony_ci  ): ts.PropertySignature | undefined {
9403af6ab5fSopenharmony_ci    // Can't fix if property is not a key-value pair, or the property name is a computed value.
9413af6ab5fSopenharmony_ci    if (!ts.isPropertyAssignment(prop) || ts.isComputedPropertyName(prop.name)) {
9423af6ab5fSopenharmony_ci      return undefined;
9433af6ab5fSopenharmony_ci    }
9443af6ab5fSopenharmony_ci
9453af6ab5fSopenharmony_ci    const propType = this.typeChecker.getTypeAtLocation(prop);
9463af6ab5fSopenharmony_ci
9473af6ab5fSopenharmony_ci    // Can't capture generic type parameters of enclosing declarations.
9483af6ab5fSopenharmony_ci    if (this.utils.hasGenericTypeParameter(propType)) {
9493af6ab5fSopenharmony_ci      return undefined;
9503af6ab5fSopenharmony_ci    }
9513af6ab5fSopenharmony_ci
9523af6ab5fSopenharmony_ci    if (Autofixer.propertyTypeIsCapturedFromEnclosingLocalScope(propType, enclosingStmt)) {
9533af6ab5fSopenharmony_ci      return undefined;
9543af6ab5fSopenharmony_ci    }
9553af6ab5fSopenharmony_ci
9563af6ab5fSopenharmony_ci    const propTypeNode = this.typeChecker.typeToTypeNode(propType, undefined, ts.NodeBuilderFlags.None);
9573af6ab5fSopenharmony_ci    if (!propTypeNode || !this.utils.isSupportedType(propTypeNode)) {
9583af6ab5fSopenharmony_ci      return undefined;
9593af6ab5fSopenharmony_ci    }
9603af6ab5fSopenharmony_ci
9613af6ab5fSopenharmony_ci    const newProp: ts.PropertySignature = ts.factory.createPropertySignature(
9623af6ab5fSopenharmony_ci      undefined,
9633af6ab5fSopenharmony_ci      prop.name,
9643af6ab5fSopenharmony_ci      undefined,
9653af6ab5fSopenharmony_ci      propTypeNode
9663af6ab5fSopenharmony_ci    );
9673af6ab5fSopenharmony_ci    return newProp;
9683af6ab5fSopenharmony_ci  }
9693af6ab5fSopenharmony_ci
9703af6ab5fSopenharmony_ci  private static propertyTypeIsCapturedFromEnclosingLocalScope(type: ts.Type, enclosingStmt: ts.Node): boolean {
9713af6ab5fSopenharmony_ci    const sym = type.getSymbol();
9723af6ab5fSopenharmony_ci    let symNode: ts.Node | undefined = TsUtils.getDeclaration(sym);
9733af6ab5fSopenharmony_ci
9743af6ab5fSopenharmony_ci    while (symNode) {
9753af6ab5fSopenharmony_ci      if (symNode === enclosingStmt) {
9763af6ab5fSopenharmony_ci        return true;
9773af6ab5fSopenharmony_ci      }
9783af6ab5fSopenharmony_ci      symNode = symNode.parent;
9793af6ab5fSopenharmony_ci    }
9803af6ab5fSopenharmony_ci
9813af6ab5fSopenharmony_ci    return false;
9823af6ab5fSopenharmony_ci  }
9833af6ab5fSopenharmony_ci
9843af6ab5fSopenharmony_ci  private createNewInterface(
9853af6ab5fSopenharmony_ci    srcFile: ts.SourceFile,
9863af6ab5fSopenharmony_ci    interfaceName: string,
9873af6ab5fSopenharmony_ci    members: ts.TypeElement[],
9883af6ab5fSopenharmony_ci    pos: number
9893af6ab5fSopenharmony_ci  ): Autofix {
9903af6ab5fSopenharmony_ci    const newInterfaceDecl = ts.factory.createInterfaceDeclaration(
9913af6ab5fSopenharmony_ci      undefined,
9923af6ab5fSopenharmony_ci      interfaceName,
9933af6ab5fSopenharmony_ci      undefined,
9943af6ab5fSopenharmony_ci      undefined,
9953af6ab5fSopenharmony_ci      members
9963af6ab5fSopenharmony_ci    );
9973af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, newInterfaceDecl, srcFile) + '\n';
9983af6ab5fSopenharmony_ci    return { start: pos, end: pos, replacementText: text };
9993af6ab5fSopenharmony_ci  }
10003af6ab5fSopenharmony_ci
10013af6ab5fSopenharmony_ci  private fixObjectLiteralExpression(
10023af6ab5fSopenharmony_ci    srcFile: ts.SourceFile,
10033af6ab5fSopenharmony_ci    newInterfaceName: string,
10043af6ab5fSopenharmony_ci    objectLiteralExpr: ts.ObjectLiteralExpression
10053af6ab5fSopenharmony_ci  ): Autofix {
10063af6ab5fSopenharmony_ci
10073af6ab5fSopenharmony_ci    /*
10083af6ab5fSopenharmony_ci     * If object literal is initializing a variable or property,
10093af6ab5fSopenharmony_ci     * then simply add new 'contextual' type to the declaration.
10103af6ab5fSopenharmony_ci     * Otherwise, cast object literal to newly created interface type.
10113af6ab5fSopenharmony_ci     */
10123af6ab5fSopenharmony_ci    if (
10133af6ab5fSopenharmony_ci      (ts.isVariableDeclaration(objectLiteralExpr.parent) ||
10143af6ab5fSopenharmony_ci        ts.isPropertyDeclaration(objectLiteralExpr.parent) ||
10153af6ab5fSopenharmony_ci        ts.isParameter(objectLiteralExpr.parent)) &&
10163af6ab5fSopenharmony_ci      !objectLiteralExpr.parent.type
10173af6ab5fSopenharmony_ci    ) {
10183af6ab5fSopenharmony_ci      const text = ': ' + newInterfaceName;
10193af6ab5fSopenharmony_ci      const pos = Autofixer.getDeclarationTypePositionForObjectLiteral(objectLiteralExpr.parent);
10203af6ab5fSopenharmony_ci      return { start: pos, end: pos, replacementText: text };
10213af6ab5fSopenharmony_ci    }
10223af6ab5fSopenharmony_ci
10233af6ab5fSopenharmony_ci    const newTypeRef = ts.factory.createTypeReferenceNode(newInterfaceName);
10243af6ab5fSopenharmony_ci    let newExpr: ts.Expression = ts.factory.createAsExpression(
10253af6ab5fSopenharmony_ci      ts.factory.createObjectLiteralExpression(objectLiteralExpr.properties),
10263af6ab5fSopenharmony_ci      newTypeRef
10273af6ab5fSopenharmony_ci    );
10283af6ab5fSopenharmony_ci    if (!ts.isParenthesizedExpression(objectLiteralExpr.parent)) {
10293af6ab5fSopenharmony_ci      newExpr = ts.factory.createParenthesizedExpression(newExpr);
10303af6ab5fSopenharmony_ci    }
10313af6ab5fSopenharmony_ci    const text = this.printer.printNode(ts.EmitHint.Unspecified, newExpr, srcFile);
10323af6ab5fSopenharmony_ci    return { start: objectLiteralExpr.getStart(), end: objectLiteralExpr.getEnd(), replacementText: text };
10333af6ab5fSopenharmony_ci  }
10343af6ab5fSopenharmony_ci
10353af6ab5fSopenharmony_ci  private static getDeclarationTypePositionForObjectLiteral(
10363af6ab5fSopenharmony_ci    decl: ts.VariableDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration
10373af6ab5fSopenharmony_ci  ): number {
10383af6ab5fSopenharmony_ci    if (ts.isPropertyDeclaration(decl)) {
10393af6ab5fSopenharmony_ci      return (decl.questionToken || decl.exclamationToken || decl.name).getEnd();
10403af6ab5fSopenharmony_ci    } else if (ts.isParameter(decl)) {
10413af6ab5fSopenharmony_ci      return (decl.questionToken || decl.name).getEnd();
10423af6ab5fSopenharmony_ci    }
10433af6ab5fSopenharmony_ci    return (decl.exclamationToken || decl.name).getEnd();
10443af6ab5fSopenharmony_ci  }
10453af6ab5fSopenharmony_ci
10463af6ab5fSopenharmony_ci  private readonly objectLiteralInterfaceNameGenerator = new NameGenerator(
10473af6ab5fSopenharmony_ci    GENERATED_OBJECT_LITERAL_INTERFACE_NAME,
10483af6ab5fSopenharmony_ci    GENERATED_OBJECT_LITERAL_INTERFACE_TRESHOLD
10493af6ab5fSopenharmony_ci  );
10503af6ab5fSopenharmony_ci
10513af6ab5fSopenharmony_ci  /*
10523af6ab5fSopenharmony_ci   * In case of type alias initialized with type literal, replace
10533af6ab5fSopenharmony_ci   * entire type alias with identical interface declaration.
10543af6ab5fSopenharmony_ci   */
10553af6ab5fSopenharmony_ci  private proceedTypeAliasDeclaration(typeLiteral: ts.TypeLiteralNode): Autofix[] | undefined {
10563af6ab5fSopenharmony_ci    if (ts.isTypeAliasDeclaration(typeLiteral.parent)) {
10573af6ab5fSopenharmony_ci      const typeAlias = typeLiteral.parent;
10583af6ab5fSopenharmony_ci      const newInterfaceDecl = ts.factory.createInterfaceDeclaration(
10593af6ab5fSopenharmony_ci        typeAlias.modifiers,
10603af6ab5fSopenharmony_ci        typeAlias.name,
10613af6ab5fSopenharmony_ci        typeAlias.typeParameters,
10623af6ab5fSopenharmony_ci        undefined,
10633af6ab5fSopenharmony_ci        typeLiteral.members
10643af6ab5fSopenharmony_ci      );
10653af6ab5fSopenharmony_ci      const text = this.printer.printNode(ts.EmitHint.Unspecified, newInterfaceDecl, typeLiteral.getSourceFile());
10663af6ab5fSopenharmony_ci      return [{ start: typeAlias.getStart(), end: typeAlias.getEnd(), replacementText: text }];
10673af6ab5fSopenharmony_ci    }
10683af6ab5fSopenharmony_ci    return undefined;
10693af6ab5fSopenharmony_ci  }
10703af6ab5fSopenharmony_ci
10713af6ab5fSopenharmony_ci  fixTypeliteral(typeLiteral: ts.TypeLiteralNode): Autofix[] | undefined {
10723af6ab5fSopenharmony_ci    const typeAliasAutofix = this.proceedTypeAliasDeclaration(typeLiteral);
10733af6ab5fSopenharmony_ci    if (typeAliasAutofix) {
10743af6ab5fSopenharmony_ci      return typeAliasAutofix;
10753af6ab5fSopenharmony_ci    }
10763af6ab5fSopenharmony_ci
10773af6ab5fSopenharmony_ci    /*
10783af6ab5fSopenharmony_ci     * Create new interface declaration with members of type literal
10793af6ab5fSopenharmony_ci     * and put the interface name in place of the type literal.
10803af6ab5fSopenharmony_ci     */
10813af6ab5fSopenharmony_ci    const srcFile = typeLiteral.getSourceFile();
10823af6ab5fSopenharmony_ci    const enclosingStmt = TsUtils.getEnclosingTopLevelStatement(typeLiteral);
10833af6ab5fSopenharmony_ci    if (!enclosingStmt) {
10843af6ab5fSopenharmony_ci      return undefined;
10853af6ab5fSopenharmony_ci    }
10863af6ab5fSopenharmony_ci
10873af6ab5fSopenharmony_ci    if (this.typeLiteralCapturesTypeFromEnclosingLocalScope(typeLiteral, enclosingStmt)) {
10883af6ab5fSopenharmony_ci      return undefined;
10893af6ab5fSopenharmony_ci    }
10903af6ab5fSopenharmony_ci
10913af6ab5fSopenharmony_ci    const newInterfaceName = TsUtils.generateUniqueName(this.typeLiteralInterfaceNameGenerator, srcFile);
10923af6ab5fSopenharmony_ci    if (!newInterfaceName) {
10933af6ab5fSopenharmony_ci      return undefined;
10943af6ab5fSopenharmony_ci    }
10953af6ab5fSopenharmony_ci    const newInterfacePos = enclosingStmt.getStart();
10963af6ab5fSopenharmony_ci    const newInterfaceDecl = ts.factory.createInterfaceDeclaration(
10973af6ab5fSopenharmony_ci      undefined,
10983af6ab5fSopenharmony_ci      newInterfaceName,
10993af6ab5fSopenharmony_ci      undefined,
11003af6ab5fSopenharmony_ci      undefined,
11013af6ab5fSopenharmony_ci      typeLiteral.members
11023af6ab5fSopenharmony_ci    );
11033af6ab5fSopenharmony_ci    const interfaceText = this.printer.printNode(ts.EmitHint.Unspecified, newInterfaceDecl, srcFile) + '\n';
11043af6ab5fSopenharmony_ci
11053af6ab5fSopenharmony_ci    return [
11063af6ab5fSopenharmony_ci      { start: newInterfacePos, end: newInterfacePos, replacementText: interfaceText },
11073af6ab5fSopenharmony_ci      { start: typeLiteral.getStart(), end: typeLiteral.getEnd(), replacementText: newInterfaceName }
11083af6ab5fSopenharmony_ci    ];
11093af6ab5fSopenharmony_ci  }
11103af6ab5fSopenharmony_ci
11113af6ab5fSopenharmony_ci  typeLiteralCapturesTypeFromEnclosingLocalScope(typeLiteral: ts.TypeLiteralNode, enclosingStmt: ts.Node): boolean {
11123af6ab5fSopenharmony_ci    let found = false;
11133af6ab5fSopenharmony_ci
11143af6ab5fSopenharmony_ci    const callback = (node: ts.Node): void => {
11153af6ab5fSopenharmony_ci      if (!ts.isIdentifier(node)) {
11163af6ab5fSopenharmony_ci        return;
11173af6ab5fSopenharmony_ci      }
11183af6ab5fSopenharmony_ci      const sym = this.typeChecker.getSymbolAtLocation(node);
11193af6ab5fSopenharmony_ci      let symNode: ts.Node | undefined = TsUtils.getDeclaration(sym);
11203af6ab5fSopenharmony_ci      while (symNode) {
11213af6ab5fSopenharmony_ci        if (symNode === typeLiteral) {
11223af6ab5fSopenharmony_ci          return;
11233af6ab5fSopenharmony_ci        }
11243af6ab5fSopenharmony_ci        if (symNode === enclosingStmt) {
11253af6ab5fSopenharmony_ci          found = true;
11263af6ab5fSopenharmony_ci          return;
11273af6ab5fSopenharmony_ci        }
11283af6ab5fSopenharmony_ci        symNode = symNode.parent;
11293af6ab5fSopenharmony_ci      }
11303af6ab5fSopenharmony_ci    };
11313af6ab5fSopenharmony_ci
11323af6ab5fSopenharmony_ci    const stopCondition = (node: ts.Node): boolean => {
11333af6ab5fSopenharmony_ci      void node;
11343af6ab5fSopenharmony_ci      return found;
11353af6ab5fSopenharmony_ci    };
11363af6ab5fSopenharmony_ci
11373af6ab5fSopenharmony_ci    forEachNodeInSubtree(typeLiteral, callback, stopCondition);
11383af6ab5fSopenharmony_ci    return found;
11393af6ab5fSopenharmony_ci  }
11403af6ab5fSopenharmony_ci
11413af6ab5fSopenharmony_ci  // eslint-disable-next-line class-methods-use-this
11423af6ab5fSopenharmony_ci  removeDecorator(decorator: ts.Decorator): Autofix[] {
11433af6ab5fSopenharmony_ci    return [{ start: decorator.getStart(), end: decorator.getEnd(), replacementText: '' }];
11443af6ab5fSopenharmony_ci  }
11453af6ab5fSopenharmony_ci
11463af6ab5fSopenharmony_ci  private readonly typeLiteralInterfaceNameGenerator = new NameGenerator(
11473af6ab5fSopenharmony_ci    GENERATED_TYPE_LITERAL_INTERFACE_NAME,
11483af6ab5fSopenharmony_ci    GENERATED_TYPE_LITERAL_INTERFACE_TRESHOLD
11493af6ab5fSopenharmony_ci  );
11503af6ab5fSopenharmony_ci
11513af6ab5fSopenharmony_ci  private readonly symbolCache: SymbolCache;
11523af6ab5fSopenharmony_ci}
1153