• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15import * as ts from "../_namespaces/ts";
16import {
17    ArrayLiteralExpression, ArrowFunction, AsExpression, BinaryExpression, BindingName, CallExpression, CatchClause,
18    ClassDeclaration, ClassStaticBlockDeclaration, CommentRange, ComputedPropertyName, ConciseBody, Declaration,
19    Decorator, Diagnostic, DiagnosticMessageChain, ElementAccessExpression, EnumDeclaration, EnumMember,
20    ExportAssignment, ExpressionWithTypeArguments, forEachChild, ForInStatement, ForOfStatement, ForStatement,
21    FunctionDeclaration, FunctionExpression, FunctionLikeDeclaration, GetAccessorDeclaration, getCombinedNodeFlags,
22    getDecorators, getLeadingCommentRanges, getModifiers, getTrailingCommentRanges, HeritageClause, Identifier,
23    ImportClause, ImportDeclaration, ImportSpecifier, InterfaceDeclaration, isAccessor, isArrayBindingPattern,
24    isArrayLiteralExpression, isArrayTypeNode, isArrowFunction, isBinaryExpression, isBlock, isCallExpression,
25    isCallLikeExpression, isCatchClause, isClassDeclaration, isClassExpression, isClassLike,
26    isClassStaticBlockDeclaration, isConstructorDeclaration, isElementAccessExpression, isEnumDeclaration,
27    isExportAssignment, isExportSpecifier, isExpressionWithTypeArguments, isFunctionDeclaration, isFunctionExpression,
28    isFunctionTypeNode, isIdentifier, isImportClause, isImportDeclaration, isImportEqualsDeclaration, isImportSpecifier,
29    isInterfaceDeclaration, isMetaProperty, isMethodDeclaration, isModuleBlock, isModuleDeclaration, isNamedImports,
30    isNamespaceImport, isNewExpression, isObjectBindingPattern, isObjectLiteralExpression, isOmittedExpression,
31    isParameter, isPrivateIdentifier, isPropertyAccessExpression, isPropertyAssignment, isPropertyDeclaration,
32    isQualifiedName, isReturnStatement, isShorthandPropertyAssignment, isSourceFile, isSpreadElement, isStringLiteral,
33    isStructDeclaration, isTypeNode, isTypeOfExpression, isVariableDeclaration, Map, MetaProperty, MethodDeclaration,
34    MethodSignature, ModuleDeclaration, NamespaceImport, NewExpression, Node, NodeArray, NodeBuilderFlags, NodeFlags,
35    normalizePath, NumericLiteral, ObjectFlags, ObjectLiteralExpression, ObjectType, ParameterDeclaration,
36    PrefixUnaryExpression, Program, PropertyAccessExpression, PropertyAssignment, PropertyDeclaration,
37    PropertySignature, Set, SetAccessorDeclaration, Signature, SourceFile, Symbol, SymbolFlags, SyntaxKind,
38    ThrowStatement, Type, TypeAliasDeclaration, TypeAssertion, TypeChecker, TypeFlags, TypeNode, TypeReference,
39    TypeReferenceNode, VariableDeclaration, perfLogger as Logger
40} from "../_namespaces/ts";
41
42//import Utils = Utils;
43import {
44  ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE,
45  TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE,
46  NO_OVERLOAD_MATCHES_THIS_CALL_ERROR_CODE,
47  LibraryTypeCallDiagnosticChecker, autofixInfo, cookBookTag, cookBookMsg, DiagnosticChecker, FaultID, faultsAttrs, LinterConfig, fixLiteralAsPropertyName,
48  shouldAutofix, fixFunctionExpression, fixReturnType, fixPropertyAccessByIndex, Autofix, getStartPos, getEndPos, ProblemSeverity,
49  symbolHasDuplicateName, trueSymbolAtLocation, isLibrarySymbol, isAnyType, isPrototypeSymbol, isTypeSymbol, isFunctionSymbol, isDestructuringAssignmentLHS,
50  isStructObjectInitializer, isDynamicLiteralInitializer, isExpressionAssignableToType, hasModifier, isDerivedFrom, CheckType, isSymbolAPI,
51  ALLOWED_STD_SYMBOL_API, symbolHasEsObjectType, isStdRecordType, NON_INITIALIZABLE_PROPERTY_DECORATORS, PROPERTY_HAS_NO_INITIALIZER_ERROR_CODE,
52  NON_INITIALIZABLE_PROPERTY_ClASS_DECORATORS, hasPredecessor, isLibraryType, isUnsupportedType, isCallToFunctionWithOmittedReturnType, unwrapParenthesized,
53  isIntegerConstantValue, isAssignmentOperator, isMethodAssignment, isEnumMemberType, isNumberType, isStringLikeType, isPrimitiveType,
54  needToDeduceStructuralIdentity, getVariableDeclarationTypeNode, isEsObjectType, isInsideBlock, isValueAssignableToESObject, isDefaultImport,
55  NON_RETURN_FUNCTION_DECORATORS, FUNCTION_HAS_NO_RETURN_ERROR_CODE, hasLibraryType, isStruct, isGenericArrayType, isThisOrSuperExpr, isTypedArray,
56  isObjectLiteralType, hasEsObjectType, isValidEnumMemberInit, isInterfaceType, LIMITED_STD_GLOBAL_FUNC, LIMITED_STD_OBJECT_API, LIMITED_STD_REFLECT_API,
57  LIMITED_STD_PROXYHANDLER_API, getParentSymbolName, isBooleanType, isEsObjectPossiblyAllowed, entityNameToString, LIMITED_STANDARD_UTILITY_TYPES,
58  isEsObjectSymbol, isSymbolIterator, isUnknownType, ARKUI_DECORATORS
59} from "../_namespaces/ts.ArkTSLinter_1_0";
60import * as ArkTSLinter_1_0 from "../_namespaces/ts.ArkTSLinter_1_0";
61//import cookBookMsg = cookBookMsg;
62//import cookBookTag = ts.cookBookTag;
63
64//import LinterConfig = ts.LinterConfig;
65//import Autofixer = ts.Autofixer;
66
67//const logger = Logger.getLogger();
68
69export interface ProblemInfo {
70  line: number;
71  column: number;
72  start: number;
73  end: number;
74  type: string;
75  severity: number;
76  problem: string;
77  suggest: string;
78  rule: string;
79  ruleTag: number;
80  autofixable: boolean;
81  autofix?: Autofix[];
82}
83
84export class TypeScriptLinter {
85  static ideMode: boolean;
86  static strictMode: boolean;
87  static logTscErrors: boolean;
88  static warningsAsErrors: boolean;
89  static lintEtsOnly: boolean;
90  static totalVisitedNodes: number;
91  static nodeCounters: number[];
92  static lineCounters: number[];
93
94  static totalErrorLines: number;
95  static errorLineNumbersString: string;
96  static totalWarningLines: number;
97  static warningLineNumbersString: string;
98  static reportDiagnostics = true;
99
100  // The SyntaxKind enum defines additional elements at the end of the enum
101  // that serve as markers (FirstX/LastX). Those elements are initialized
102  // with indices of the previously defined elements. As result, the enum
103  // may return incorrect name for a certain kind index (e.g. 'FirstStatement'
104  // instead of 'VariableStatement').
105  // The following code creates a map with correct syntax kind names.
106  // It can be used when need to print name of syntax kind of certain
107  // AST node in diagnostic messages.
108  //private static tsSyntaxKindNames: string[];
109
110  static problemsInfos: ProblemInfo[] = [];
111
112  static filteredDiagnosticMessages: DiagnosticMessageChain[] = [];
113
114  public static initGlobals(): void {
115    TypeScriptLinter.filteredDiagnosticMessages = []
116  }
117
118  public static initStatic(): void {
119    TypeScriptLinter.strictMode = true;
120    TypeScriptLinter.logTscErrors = false;
121    TypeScriptLinter.warningsAsErrors = false;
122    TypeScriptLinter.lintEtsOnly = true;
123    TypeScriptLinter.totalVisitedNodes = 0;
124    TypeScriptLinter.nodeCounters = [];
125    TypeScriptLinter.lineCounters = [];
126
127    TypeScriptLinter.totalErrorLines = 0;
128    TypeScriptLinter.totalWarningLines = 0;
129    TypeScriptLinter.errorLineNumbersString = "";
130    TypeScriptLinter.warningLineNumbersString = "";
131
132    autofixInfo.length = 0;
133
134    //TypeScriptLinter.tsSyntaxKindNames = [];
135    //const keys = Object.keys(ts.SyntaxKind);
136    //const keys: string[] = [];
137    //const values = Object.values(ts.SyntaxKind);
138    //const values: string[] = [];
139
140    /*
141    for (let i = 0; i < values.length; i++) {
142      const val = values[i];
143      const kindNum = typeof val === "string" ? parseInt(val) : val;
144      if (kindNum && !TypeScriptLinter.tsSyntaxKindNames[kindNum])
145        TypeScriptLinter.tsSyntaxKindNames[kindNum] = keys[i];
146    }
147    */
148
149    for (let i = 0; i < FaultID.LAST_ID; i++) {
150      TypeScriptLinter.nodeCounters[i] = 0;
151      TypeScriptLinter.lineCounters[i] = 0;
152    }
153
154    TypeScriptLinter.problemsInfos = [];
155  }
156
157  public static tsTypeChecker: TypeChecker;
158
159  currentErrorLine: number;
160  currentWarningLine: number;
161  staticBlocks: Set<string>;
162  libraryTypeCallDiagnosticChecker: LibraryTypeCallDiagnosticChecker;
163  skipArkTSStaticBlocksCheck: boolean;
164
165  constructor(private sourceFile: SourceFile,
166            /* private */ tsProgram: Program,
167            private tscStrictDiagnostics?: Map<Diagnostic[]>) {
168    TypeScriptLinter.tsTypeChecker = tsProgram.getLinterTypeChecker();
169    this.currentErrorLine = 0;
170    this.currentWarningLine = 0;
171    this.staticBlocks = new Set<string>();
172    this.libraryTypeCallDiagnosticChecker = new LibraryTypeCallDiagnosticChecker(TypeScriptLinter.filteredDiagnosticMessages);
173
174    const options = tsProgram.getCompilerOptions();
175    this.skipArkTSStaticBlocksCheck = false;
176    if (options.skipArkTSStaticBlocksCheck) {
177      this.skipArkTSStaticBlocksCheck = options.skipArkTSStaticBlocksCheck as boolean;
178    }
179  }
180
181  public static clearTsTypeChecker(): void {
182    TypeScriptLinter.tsTypeChecker = {} as TypeChecker;
183  }
184
185  public static clearQualifiedNameCache(): void {
186    if (TypeScriptLinter.tsTypeChecker) {
187      TypeScriptLinter.tsTypeChecker.clearQualifiedNameCache && TypeScriptLinter.tsTypeChecker.clearQualifiedNameCache();
188    }
189  }
190
191  readonly handlersMap: ts.ESMap<SyntaxKind, (node: Node) => void> = new Map([
192    [SyntaxKind.ObjectLiteralExpression, this.handleObjectLiteralExpression],
193    [SyntaxKind.ArrayLiteralExpression, this.handleArrayLiteralExpression],
194    [SyntaxKind.Parameter, this.handleParameter],
195    [SyntaxKind.EnumDeclaration, this.handleEnumDeclaration],
196    [SyntaxKind.InterfaceDeclaration, this.handleInterfaceDeclaration],
197    [SyntaxKind.ThrowStatement, this.handleThrowStatement], [SyntaxKind.ImportClause, this.handleImportClause],
198    [SyntaxKind.ForStatement, this.handleForStatement],
199    [SyntaxKind.ForInStatement, this.handleForInStatement],
200    [SyntaxKind.ForOfStatement, this.handleForOfStatement],
201    [SyntaxKind.ImportDeclaration, this.handleImportDeclaration],
202    [SyntaxKind.PropertyAccessExpression, this.handlePropertyAccessExpression],
203    [SyntaxKind.PropertyDeclaration, this.handlePropertyAssignmentOrDeclaration],
204    [SyntaxKind.PropertyAssignment, this.handlePropertyAssignmentOrDeclaration],
205    [SyntaxKind.FunctionExpression, this.handleFunctionExpression],
206    [SyntaxKind.ArrowFunction, this.handleArrowFunction],
207    [SyntaxKind.ClassExpression, this.handleClassExpression], [SyntaxKind.CatchClause, this.handleCatchClause],
208    [SyntaxKind.FunctionDeclaration, this.handleFunctionDeclaration],
209    [SyntaxKind.PrefixUnaryExpression, this.handlePrefixUnaryExpression],
210    [SyntaxKind.BinaryExpression, this.handleBinaryExpression],
211    [SyntaxKind.VariableDeclarationList, this.handleVariableDeclarationList],
212    [SyntaxKind.VariableDeclaration, this.handleVariableDeclaration],
213    [SyntaxKind.ClassDeclaration, this.handleClassDeclaration],
214    [SyntaxKind.ModuleDeclaration, this.handleModuleDeclaration],
215    [SyntaxKind.TypeAliasDeclaration, this.handleTypeAliasDeclaration],
216    [SyntaxKind.ImportSpecifier, this.handleImportSpecifier],
217    [SyntaxKind.NamespaceImport, this.handleNamespaceImport],
218    [SyntaxKind.TypeAssertionExpression, this.handleTypeAssertionExpression],
219    [SyntaxKind.MethodDeclaration, this.handleMethodDeclaration],
220    [SyntaxKind.Identifier, this.handleIdentifier],
221    [SyntaxKind.ElementAccessExpression, this.handleElementAccessExpression],
222    [SyntaxKind.EnumMember, this.handleEnumMember], [SyntaxKind.TypeReference, this.handleTypeReference],
223    [SyntaxKind.ExportAssignment, this.handleExportAssignment],
224    [SyntaxKind.CallExpression, this.handleCallExpression], [SyntaxKind.MetaProperty, this.handleMetaProperty],
225    [SyntaxKind.NewExpression, this.handleNewExpression], [SyntaxKind.AsExpression, this.handleAsExpression],
226    [SyntaxKind.SpreadElement, this.handleSpreadOp], [SyntaxKind.SpreadAssignment, this.handleSpreadOp],
227    [SyntaxKind.GetAccessor, this.handleGetAccessor], [SyntaxKind.SetAccessor, this.handleSetAccessor],
228    [SyntaxKind.ConstructSignature, this.handleConstructSignature],
229    [SyntaxKind.ExpressionWithTypeArguments, this.handleExpressionWithTypeArguments],
230    [SyntaxKind.ComputedPropertyName, this.handleComputedPropertyName],
231    [SyntaxKind.ClassStaticBlockDeclaration, this.handleClassStaticBlockDeclaration],
232  ]);
233
234  public incrementCounters(node: Node | CommentRange, faultId: number, autofixable = false, autofix?: Autofix[]): void {
235    if (!TypeScriptLinter.strictMode && faultsAttrs[faultId].migratable) { return; } // In relax mode skip migratable
236
237    const startPos = getStartPos(node);
238    const endPos = getEndPos(node);
239
240    TypeScriptLinter.nodeCounters[faultId]++;
241    // TSC counts lines and columns from zero
242    let { line, character } = this.sourceFile.getLineAndCharacterOfPosition(startPos);
243    ++line;
244    ++character;
245
246    const faultDescr = LinterConfig.nodeDesc[faultId];
247    const faultType = "unknown"; //TypeScriptLinter.tsSyntaxKindNames[node.kind];
248
249    const cookBookMsgNum = faultsAttrs[faultId] ? Number(faultsAttrs[faultId].cookBookRef) : 0;
250    const cookBookTg = cookBookTag[cookBookMsgNum];
251    let severity = ProblemSeverity.ERROR;
252    if (faultsAttrs[faultId] && faultsAttrs[faultId].warning) {
253      severity = ProblemSeverity.WARNING;
254    }
255    const badNodeInfo: ProblemInfo = {
256      line: line,
257      column: character,
258      start: startPos,
259      end: endPos,
260      type: faultType,
261      severity: severity,
262      problem: FaultID[faultId],
263      suggest: cookBookMsgNum > 0 ? cookBookMsg[cookBookMsgNum] : "",
264      rule: cookBookMsgNum > 0 && cookBookTg !== "" ? cookBookTg : faultDescr ? faultDescr : faultType,
265      ruleTag: cookBookMsgNum,
266      autofixable: autofixable,
267      autofix: autofix
268    };
269
270    TypeScriptLinter.problemsInfos.push(badNodeInfo);
271
272    if (!TypeScriptLinter.reportDiagnostics) {
273      //logger.info(
274      Logger.logEvent(
275        `Warning: ${this.sourceFile.fileName} (${line}, ${character}): ${faultDescr ? faultDescr : faultType}`
276      );
277    }
278
279    TypeScriptLinter.lineCounters[faultId]++;
280
281    if (faultsAttrs[faultId].warning) {
282      if (line !== this.currentWarningLine) {
283        this.currentWarningLine = line;
284        ++TypeScriptLinter.totalWarningLines;
285        TypeScriptLinter.warningLineNumbersString += line + ", " ;
286      }
287    }
288    else if (line !== this.currentErrorLine) {
289      this.currentErrorLine = line;
290      ++TypeScriptLinter.totalErrorLines;
291      TypeScriptLinter.errorLineNumbersString += line + ", ";
292    }
293  }
294
295  public visitTSNode(node: Node): void {
296    const self = this;
297    visitTSNodeImpl(node);
298    function visitTSNodeImpl(node: Node): void {
299      if (node === null || node.kind === null) {
300        return;
301      }
302      TypeScriptLinter.totalVisitedNodes++;
303
304      //if (TypeScriptLinter.tsSyntaxKindNames[node.kind] === "StructDeclaration") {
305      // if (node.kind === SyntaxKind.StructDeclaration) {
306      //if ( SyntaxKind[node.kind] === 'StructDeclaration') {
307      if(isStructDeclaration(node)) {
308        self.handleStructDeclaration(node);
309        return;
310      }
311
312      self.handleComments(node);
313
314      if (LinterConfig.terminalTokens.has(node.kind)) return;
315
316      const incrementedType = LinterConfig.incrementOnlyTokens.get(node.kind);
317      if (incrementedType !== undefined) {
318        self.incrementCounters(node, incrementedType);
319      }
320      else {
321        const handler = self.handlersMap.get(node.kind);
322        if (handler !== undefined) {
323          handler.call(self, node);
324        }
325      }
326
327      forEachChild(node, visitTSNodeImpl);
328    }
329  }
330
331  private countInterfaceExtendsDifferentPropertyTypes(
332    node: Node,
333    prop2type: Map<string /*, string*/>,
334    propName: string,
335    type: TypeNode | undefined
336  ): void {
337    if (type) {
338      const methodType = type.getText();
339      const propType = prop2type.get(propName);
340      if (!propType) {
341        prop2type.set(propName, methodType);
342      }
343      else if (propType !== methodType) {
344        this.incrementCounters(node, FaultID.IntefaceExtendDifProps);
345      }
346    }
347  }
348
349  private countDeclarationsWithDuplicateName(
350    tsNode: Node, tsDeclNode: Node, tsDeclKind?: SyntaxKind
351  ): void {
352    const symbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsNode);
353
354    // If specific declaration kind is provided, check against it.
355    // Otherwise, use syntax kind of corresponding declaration node.
356    if (!!symbol && symbolHasDuplicateName(symbol, tsDeclKind ?? tsDeclNode.kind)) {
357      this.incrementCounters(tsDeclNode, FaultID.DeclWithDuplicateName);
358    }
359  }
360
361  private countClassMembersWithDuplicateName(tsClassDecl: ClassDeclaration): void {
362    for (const tsCurrentMember of tsClassDecl.members) {
363      if (
364        !tsCurrentMember.name ||
365        !(isIdentifier(tsCurrentMember.name) || isPrivateIdentifier(tsCurrentMember.name))
366      ) {
367        continue;
368      }
369      for (const tsClassMember of tsClassDecl.members) {
370        if (tsCurrentMember === tsClassMember) continue;
371
372        if (
373          !tsClassMember.name ||
374          !(isIdentifier(tsClassMember.name) || isPrivateIdentifier(tsClassMember.name))
375        ) {
376          continue;
377        }
378        if (
379          isIdentifier(tsCurrentMember.name) &&
380          isPrivateIdentifier(tsClassMember.name) &&
381          tsCurrentMember.name.text === tsClassMember.name.text.substring(1)
382        ) {
383          this.incrementCounters(tsCurrentMember, FaultID.DeclWithDuplicateName);
384          break;
385        }
386
387        if (
388          isPrivateIdentifier(tsCurrentMember.name) &&
389          isIdentifier(tsClassMember.name) &&
390          tsCurrentMember.name.text.substring(1) === tsClassMember.name.text
391        ) {
392          this.incrementCounters(tsCurrentMember, FaultID.DeclWithDuplicateName);
393          break;
394        }
395      }
396    }
397  }
398
399  private functionContainsThis(tsNode: Node): boolean {
400    let found = false;
401
402    function visitNode(tsNode: Node): void {
403      // Stop visiting child nodes if finished searching.
404      if (found) return;
405
406      if (tsNode.kind === SyntaxKind.ThisKeyword) {
407        found = true;
408        return;
409      }
410
411      // Visit children nodes. Skip any local declaration that defines
412      // its own scope as it needs to be checked separately.
413      if (
414        !isClassDeclaration(tsNode) &&
415        !isClassExpression(tsNode) &&
416        !isModuleDeclaration(tsNode) &&
417        !isFunctionDeclaration(tsNode) &&
418        !isFunctionExpression(tsNode)
419      ) {
420        tsNode.forEachChild(visitNode);
421      }
422    }
423
424    visitNode(tsNode);
425
426    return found;
427  }
428
429  private isPrototypePropertyAccess(tsPropertyAccess: PropertyAccessExpression, propAccessSym: Symbol | undefined, baseExprSym: Symbol | undefined, baseExprType: Type): boolean {
430    if (!(isIdentifier(tsPropertyAccess.name) && tsPropertyAccess.name.text === "prototype")) {
431      return false;
432    }
433    // #13600: Relax prototype check when expression comes from interop.
434    let curPropAccess: Node = tsPropertyAccess;
435    while (curPropAccess && isPropertyAccessExpression(curPropAccess)) {
436      const baseExprSym = trueSymbolAtLocation(curPropAccess.expression);
437      if (isLibrarySymbol(baseExprSym)) {
438        return false;
439      }
440      curPropAccess = curPropAccess.expression;
441    }
442    if (isIdentifier(curPropAccess) && curPropAccess.text !== 'prototype') {
443      const type = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(curPropAccess);
444      if (isAnyType(type)) {
445        return false;
446      }
447    }
448    // Check if property symbol is "Prototype"
449    if (isPrototypeSymbol(propAccessSym)) {
450      return true;
451    }
452
453    // Check if symbol of LHS-expression is Class or Function.
454    if (isTypeSymbol(baseExprSym) || isFunctionSymbol(baseExprSym)) {
455      return true;
456    }
457    // Check if type of LHS expression Function type or Any type.
458    // The latter check is to cover cases with multiple prototype
459    // chain (as the 'Prototype' property should be 'Any' type):
460    //      X.prototype.prototype.prototype = ...
461    const baseExprTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(
462      baseExprType, undefined, NodeBuilderFlags.None
463    );
464
465    return ((baseExprTypeNode && isFunctionTypeNode(baseExprTypeNode)) || isAnyType(baseExprType));
466  }
467
468  private interfaceInheritanceLint(node: Node, heritageClauses: NodeArray<HeritageClause>): void {
469    for (const hClause of heritageClauses) {
470      if (hClause.token !== SyntaxKind.ExtendsKeyword) continue;
471
472      const prop2type = new Map<string, string>();
473      for (const tsTypeExpr of hClause.types) {
474        const tsExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeExpr.expression);
475        if (tsExprType.isClass()) {
476          this.incrementCounters(node, FaultID.InterfaceExtendsClass);
477        }
478        else if (tsExprType.isClassOrInterface()) {
479          this.lintForInterfaceExtendsDifferentPorpertyTypes(node, tsExprType, prop2type);
480        }
481      }
482    }
483  }
484
485  private lintForInterfaceExtendsDifferentPorpertyTypes(
486    node: Node, tsExprType: Type, prop2type: Map</*string,*/ string>
487  ): void {
488    const props = tsExprType.getProperties();
489    for (const p of props) {
490      if (!p.declarations) continue;
491
492      const decl: Declaration = p.declarations[0];
493      if (decl.kind === SyntaxKind.MethodSignature) {
494        this.countInterfaceExtendsDifferentPropertyTypes(
495          node, prop2type, p.name, (decl as MethodSignature).type
496        );
497      }
498      else if (decl.kind === SyntaxKind.MethodDeclaration) {
499        this.countInterfaceExtendsDifferentPropertyTypes(
500          node, prop2type, p.name, (decl as MethodDeclaration).type
501        );
502      }
503      else if (decl.kind === SyntaxKind.PropertyDeclaration) {
504        this.countInterfaceExtendsDifferentPropertyTypes(
505          node, prop2type, p.name, (decl as PropertyDeclaration).type
506        );
507      }
508      else if (decl.kind === SyntaxKind.PropertySignature) {
509        this.countInterfaceExtendsDifferentPropertyTypes(
510          node, prop2type, p.name, (decl as PropertySignature).type
511        );
512      }
513    }
514  }
515
516  private handleObjectLiteralExpression(node: Node): void {
517    const objectLiteralExpr = node as ObjectLiteralExpression;
518
519    // If object literal is a part of destructuring assignment, then don't process it further.
520    if (isDestructuringAssignmentLHS(objectLiteralExpr)) {
521      return;
522    }
523    const objectLiteralType = TypeScriptLinter.tsTypeChecker.getContextualType(objectLiteralExpr);
524    if (!isStructObjectInitializer(objectLiteralExpr) &&
525        !isDynamicLiteralInitializer(objectLiteralExpr) &&
526        !isExpressionAssignableToType(objectLiteralType, objectLiteralExpr)
527      //  !Utils.validateObjectLiteralType(objectLiteralType) || Utils.hasMemberFunction(objectLiteralExpr) ||
528      //  !Utils.validateFields(objectLiteralType, objectLiteralExpr)
529    ) {
530      this.incrementCounters(node, FaultID.ObjectLiteralNoContextType);
531    }
532  }
533
534  private handleArrayLiteralExpression(node: Node): void {
535    // If array literal is a part of destructuring assignment, then
536    // don't process it further.
537    if (isDestructuringAssignmentLHS(node as ArrayLiteralExpression)) {
538      return;
539    }
540
541    const arrayLitNode = node as ArrayLiteralExpression;
542    let noContextTypeForArrayLiteral = false;
543
544    // check that array literal consists of inferrable types
545    // e.g. there is no element which is untyped object literals
546    const arrayLitElements = arrayLitNode.elements;
547    for(const element of arrayLitElements) {
548      if(element.kind === SyntaxKind.ObjectLiteralExpression) {
549        const objectLiteralType = TypeScriptLinter.tsTypeChecker.getContextualType(element);
550        if (!isDynamicLiteralInitializer(arrayLitNode) &&
551            !isExpressionAssignableToType(objectLiteralType, element)) {
552          noContextTypeForArrayLiteral = true;
553          break;
554        }
555      }
556    }
557
558    if (noContextTypeForArrayLiteral) {
559      this.incrementCounters(node, FaultID.ArrayLiteralNoContextType);
560    }
561  }
562
563  private handleParameter(node: Node): void {
564    const tsParam = node as ParameterDeclaration;
565    if (isArrayBindingPattern(tsParam.name) || isObjectBindingPattern(tsParam.name)) {
566      this.incrementCounters(node, FaultID.DestructuringParameter);
567    }
568    const tsParamMods = getModifiers(tsParam); //tsParam.modifiers;
569    if (
570      tsParamMods &&
571      (hasModifier(tsParamMods, SyntaxKind.PublicKeyword) ||
572        hasModifier(tsParamMods, SyntaxKind.ProtectedKeyword) ||
573        hasModifier(tsParamMods, SyntaxKind.ReadonlyKeyword) ||
574        hasModifier(tsParamMods, SyntaxKind.PrivateKeyword))
575    ) {
576      this.incrementCounters(node, FaultID.ParameterProperties);
577    }
578    this.handleDecorators(getDecorators(tsParam));
579
580    this.handleDeclarationInferredType(tsParam);
581  }
582
583  private handleEnumDeclaration(node: Node): void {
584    const enumNode = node as EnumDeclaration;
585    this.countDeclarationsWithDuplicateName(enumNode.name, enumNode);
586
587    const enumSymbol = trueSymbolAtLocation(enumNode.name);
588    if (!enumSymbol) return;
589
590    const enumDecls = enumSymbol.getDeclarations();
591    if (!enumDecls) return;
592
593    // Since type checker merges all declarations with the same name
594    // into one symbol, we need to check that there's more than one
595    // enum declaration related to that specific symbol.
596    // See 'countDeclarationsWithDuplicateName' method for details.
597    let enumDeclCount = 0;
598    for (const decl of enumDecls) {
599      if (decl.kind === SyntaxKind.EnumDeclaration) enumDeclCount++;
600    }
601
602    if (enumDeclCount > 1) this.incrementCounters(node, FaultID.EnumMerging);
603  }
604
605  private handleInterfaceDeclaration(node: Node): void {
606    const interfaceNode = node as InterfaceDeclaration;
607    const iSymbol = trueSymbolAtLocation(interfaceNode.name);
608    const iDecls = iSymbol ? iSymbol.getDeclarations() : null;
609    if (iDecls) {
610      // Since type checker merges all declarations with the same name
611      // into one symbol, we need to check that there's more than one
612      // interface declaration related to that specific symbol.
613      // See 'countDeclarationsWithDuplicateName' method for details.
614      let iDeclCount = 0;
615      for (const decl of iDecls) {
616        if (decl.kind === SyntaxKind.InterfaceDeclaration) iDeclCount++;
617      }
618
619      if (iDeclCount > 1) this.incrementCounters(node, FaultID.InterfaceMerging);
620    }
621
622    if (interfaceNode.heritageClauses) this.interfaceInheritanceLint(node, interfaceNode.heritageClauses);
623
624    this.countDeclarationsWithDuplicateName(interfaceNode.name, interfaceNode);
625  }
626
627  private handleThrowStatement(node: Node): void {
628    const throwStmt = node as ThrowStatement;
629    const throwExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(throwStmt.expression);
630    if (!throwExprType.isClassOrInterface() || !isDerivedFrom(throwExprType, CheckType.Error)) {
631      this.incrementCounters(node, FaultID.ThrowStatement);
632    }
633  }
634
635  private handleForStatement(node: Node): void {
636  const tsForStmt = node as ForStatement;
637  const tsForInit = tsForStmt.initializer;
638    if (tsForInit && (isArrayLiteralExpression(tsForInit) || isObjectLiteralExpression(tsForInit))) {
639      this.incrementCounters(tsForInit, FaultID.DestructuringAssignment);
640    }
641  }
642
643  private handleForInStatement(node: Node): void {
644    const tsForInStmt = node as ForInStatement;
645    const tsForInInit = tsForInStmt.initializer;
646    if (isArrayLiteralExpression(tsForInInit) || isObjectLiteralExpression(tsForInInit)) {
647      this.incrementCounters(tsForInInit, FaultID.DestructuringAssignment);
648    }
649    this.incrementCounters(node, FaultID.ForInStatement);
650  }
651
652  private handleForOfStatement(node: Node): void {
653    const tsForOfStmt = node as ForOfStatement;
654    const tsForOfInit = tsForOfStmt.initializer;
655    if (isArrayLiteralExpression(tsForOfInit) || isObjectLiteralExpression(tsForOfInit)) {
656      this.incrementCounters(tsForOfInit, FaultID.DestructuringAssignment);
657    }
658  }
659
660  private handleImportDeclaration(node: Node): void {
661    const importDeclNode = node as ImportDeclaration;
662    for (const stmt of importDeclNode.parent.statements) {
663      if (stmt === importDeclNode) {
664        break;
665      }
666      if (!isImportDeclaration(stmt)) {
667        this.incrementCounters(node, FaultID.ImportAfterStatement);
668        break;
669      }
670    }
671    const expr1 = importDeclNode.moduleSpecifier;
672    if (expr1.kind === SyntaxKind.StringLiteral) {
673      if (!importDeclNode.importClause) this.incrementCounters(node, FaultID.ImportFromPath);
674    }
675  }
676
677  private handlePropertyAccessExpression(node: Node): void {
678    if (isCallExpression(node.parent) && node === node.parent.expression) {
679      return;
680    }
681
682    const propertyAccessNode = node as PropertyAccessExpression;
683    const exprSym = trueSymbolAtLocation(propertyAccessNode);
684    const baseExprSym = trueSymbolAtLocation(propertyAccessNode.expression);
685    const baseExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(propertyAccessNode.expression);
686    if (this.isPrototypePropertyAccess(propertyAccessNode, exprSym, baseExprSym, baseExprType)) {
687      this.incrementCounters(propertyAccessNode.name, FaultID.Prototype);
688    }
689    if (!!exprSym && isSymbolAPI(exprSym) && !ALLOWED_STD_SYMBOL_API.includes(exprSym.getName())) {
690      this.incrementCounters(propertyAccessNode, FaultID.SymbolType);
691    }
692    if (!!baseExprSym && symbolHasEsObjectType(baseExprSym)) {
693      this.incrementCounters(propertyAccessNode, FaultID.EsObjectType);
694    }
695  }
696
697  private handlePropertyAssignmentOrDeclaration(node: Node) {
698    const propName = (node as PropertyAssignment | PropertyDeclaration).name;
699
700    if (propName && (propName.kind === SyntaxKind.NumericLiteral || propName.kind === SyntaxKind.StringLiteral)) {
701      // We can use literals as property names only when creating Record or any interop instances.
702      let isRecordObjectInitializer = false;
703      let isLibraryType = false;
704      let isDynamic = false;
705      if (isPropertyAssignment(node)) {
706        let objectLiteralType = TypeScriptLinter.tsTypeChecker.getContextualType(node.parent);
707        if (objectLiteralType) {
708          isRecordObjectInitializer = isStdRecordType(objectLiteralType);
709          isLibraryType = ArkTSLinter_1_0.isLibraryType(objectLiteralType);
710        }
711        isDynamic = isLibraryType || isDynamicLiteralInitializer(node.parent);
712      }
713
714      if (!isRecordObjectInitializer && !isDynamic) {
715        let autofix: Autofix[] | undefined = fixLiteralAsPropertyName(node);
716        const autofixable = autofix !== undefined;
717        if (!shouldAutofix(node, FaultID.LiteralAsPropertyName)) {
718          autofix = undefined;
719        }
720        this.incrementCounters(node, FaultID.LiteralAsPropertyName, autofixable, autofix);
721      }
722    }
723
724    if (isPropertyDeclaration(node)) {
725      const decorators = getDecorators(node);
726      this.handleDecorators(decorators);
727      this.filterOutDecoratorsDiagnostics(
728          decorators,
729          NON_INITIALIZABLE_PROPERTY_DECORATORS,
730          { begin: propName.getStart(), end: propName.getStart() },
731          PROPERTY_HAS_NO_INITIALIZER_ERROR_CODE
732        );
733      const classDecorators = getDecorators(node.parent);
734      const propType = (node as PropertyDeclaration).type?.getText();
735      this.filterOutDecoratorsDiagnostics(classDecorators, NON_INITIALIZABLE_PROPERTY_ClASS_DECORATORS,
736        {begin: propName.getStart(), end: propName.getStart()}, PROPERTY_HAS_NO_INITIALIZER_ERROR_CODE, propType);
737      this.handleDeclarationInferredType(node);
738      this.handleDefiniteAssignmentAssertion(node);
739    }
740  }
741
742  private filterOutDecoratorsDiagnostics(decorators: readonly Decorator[] | undefined,
743    expectedDecorators: readonly string[],
744    range: { begin: number, end: number},
745    code: number,
746    prop_type?: string) {
747    // Filter out non-initializable property decorators from strict diagnostics.
748    if (this.tscStrictDiagnostics && this.sourceFile) {
749      if (decorators?.some(x => {
750        let decoratorName = "";
751        if (isIdentifier(x.expression)) {
752          decoratorName = x.expression.text;
753        }
754        else if (isCallExpression(x.expression) && isIdentifier(x.expression.expression)) {
755          decoratorName = x.expression.expression.text;
756        }
757        // special case for property of type CustomDialogController of the @CustomDialog-decorated class
758        if (expectedDecorators.includes(NON_INITIALIZABLE_PROPERTY_ClASS_DECORATORS[0])) {
759          return expectedDecorators.includes(decoratorName) && prop_type === "CustomDialogController"
760        }
761        //return Utils.NON_INITIALIZABLE_PROPERTY_DECORATORS.includes(decoratorName);
762        return expectedDecorators.includes(decoratorName);
763      })) {
764        const file = normalizePath(this.sourceFile.fileName);
765        const tscDiagnostics = this.tscStrictDiagnostics.get(file);
766        if (tscDiagnostics) {
767          const filteredDiagnostics = tscDiagnostics.filter(
768            (val /*, idx, array */) => {
769              if (val.code !== code) return true;
770              if (val.start === undefined) return true;
771              if (val.start < range.begin) return true;
772              if (val.start > range.end) return true;
773              return false;
774            }
775          );
776          this.tscStrictDiagnostics.set(file, filteredDiagnostics);
777        }
778      }
779    }
780  }
781
782  private checkInRange(rangesToFilter: { begin: number, end: number }[], pos: number): boolean {
783    for (let i = 0; i < rangesToFilter.length; i++) {
784      if (pos >= rangesToFilter[i].begin && pos < rangesToFilter[i].end) {
785        return false;
786      }
787    }
788    return true;
789  }
790
791  private filterStrictDiagnostics(filters: { [code: number]: (pos: number) => boolean },
792    diagnosticChecker: DiagnosticChecker): boolean {
793    if (!this.tscStrictDiagnostics || !this.sourceFile) {
794      return false;
795    }
796    const file = normalizePath(this.sourceFile.fileName);
797    const tscDiagnostics = this.tscStrictDiagnostics.get(file);
798    if (!tscDiagnostics) {
799      return false;
800    }
801
802    const checkDiagnostic = (val: Diagnostic) => {
803      const checkInRange = filters[val.code];
804      if (!checkInRange) {
805        return true;
806      }
807      if (val.start === undefined || checkInRange(val.start)) {
808        return true;
809      }
810      return diagnosticChecker.checkDiagnosticMessage(val.messageText);
811    };
812
813    if (tscDiagnostics.every(checkDiagnostic)) {
814      return false;
815    }
816    this.tscStrictDiagnostics.set(file, tscDiagnostics.filter(checkDiagnostic));
817    return true;
818  }
819
820  private handleFunctionExpression(node: Node): void {
821    const funcExpr = node as FunctionExpression;
822    const isGenerator = funcExpr.asteriskToken !== undefined;
823    const containsThis = this.functionContainsThis(funcExpr.body);
824    const hasValidContext = hasPredecessor(funcExpr, isClassLike) ||
825                            hasPredecessor(funcExpr, isInterfaceDeclaration);
826    const isGeneric = funcExpr.typeParameters !== undefined && funcExpr.typeParameters.length > 0;
827    const [hasUnfixableReturnType, newRetTypeNode] = this.handleMissingReturnType(funcExpr);
828    const autofixable = !isGeneric && !isGenerator && !containsThis && !hasUnfixableReturnType;
829
830    let autofix: Autofix[] | undefined;
831    if (autofixable && shouldAutofix(node, FaultID.FunctionExpression)) {
832      autofix = [fixFunctionExpression(funcExpr, funcExpr.parameters, newRetTypeNode)];
833    }
834
835    this.incrementCounters(node, FaultID.FunctionExpression, autofixable, autofix);
836    if (isGeneric) {
837      this.incrementCounters(funcExpr, FaultID.LambdaWithTypeParameters);
838    }
839    if (isGenerator) {
840      this.incrementCounters(funcExpr, FaultID.GeneratorFunction);
841    }
842    if (containsThis && !hasValidContext) {
843      this.incrementCounters(funcExpr, FaultID.FunctionContainsThis);
844    }
845    if (hasUnfixableReturnType) {
846      this.incrementCounters(funcExpr, FaultID.LimitedReturnTypeInference);
847    }
848  }
849
850  private handleArrowFunction(node: Node): void {
851    const arrowFunc = node as ArrowFunction;
852    const containsThis = this.functionContainsThis(arrowFunc.body);
853    const hasValidContext = hasPredecessor(arrowFunc, isClassLike) ||
854                            hasPredecessor(arrowFunc, isInterfaceDeclaration);
855    if (containsThis && !hasValidContext) {
856      this.incrementCounters(arrowFunc, FaultID.FunctionContainsThis);
857    }
858
859    const contextType = TypeScriptLinter.tsTypeChecker.getContextualType(arrowFunc);
860    if (!(contextType && isLibraryType(contextType))) {
861      if (!arrowFunc.type) {
862        this.handleMissingReturnType(arrowFunc);
863      }
864
865      if (arrowFunc.typeParameters && arrowFunc.typeParameters.length > 0) {
866        this.incrementCounters(node, FaultID.LambdaWithTypeParameters);
867      }
868    }
869  }
870
871  private handleClassExpression(node: Node): void {
872    //let tsClassExpr = node as ClassExpression;
873    this.incrementCounters(node, FaultID.ClassExpression);
874    //this.handleDecorators(tsClassExpr.decorators);
875  }
876
877  private handleFunctionDeclaration(node: Node) {
878    const tsFunctionDeclaration = node as FunctionDeclaration;
879    if (!tsFunctionDeclaration.type) this.handleMissingReturnType(tsFunctionDeclaration);
880    if (tsFunctionDeclaration.name) {
881      this.countDeclarationsWithDuplicateName(tsFunctionDeclaration.name, tsFunctionDeclaration);
882    }
883    if (tsFunctionDeclaration.body && this.functionContainsThis(tsFunctionDeclaration.body)) {
884      this.incrementCounters(node, FaultID.FunctionContainsThis);
885    }
886    if (!isSourceFile(tsFunctionDeclaration.parent) && !isModuleBlock(tsFunctionDeclaration.parent)) {
887      this.incrementCounters(tsFunctionDeclaration, FaultID.LocalFunction);
888    }
889    if (tsFunctionDeclaration.asteriskToken) this.incrementCounters(node, FaultID.GeneratorFunction);
890  }
891
892  private handleMissingReturnType(funcLikeDecl: FunctionLikeDeclaration): [boolean, TypeNode | undefined] {
893    // if (funcLikeDecl.type) return [false, funcLikeDecl.type];
894
895    // Note: Return type can't be inferred for function without body.
896    if (!funcLikeDecl.body) return [false, undefined];
897
898    let autofixable = false;
899    let autofix: Autofix[] | undefined;
900    let newRetTypeNode: TypeNode | undefined;
901    const isFuncExpr = isFunctionExpression(funcLikeDecl);
902
903    // Currently, ArkTS can't infer return type of function, when expression
904    // in the return statement is a call to a function or method whose return
905    // value type is omitted. In that case, we attempt to prepare an autofix.
906    let hasLimitedRetTypeInference = this.hasLimitedTypeInferenceFromReturnExpr(funcLikeDecl.body);
907
908    const tsSignature = TypeScriptLinter.tsTypeChecker.getSignatureFromDeclaration(funcLikeDecl);
909    if (tsSignature) {
910      const tsRetType = TypeScriptLinter.tsTypeChecker.getReturnTypeOfSignature(tsSignature);
911
912      if (!tsRetType || isUnsupportedType(tsRetType)) {
913        hasLimitedRetTypeInference = true;
914      }
915      else if (hasLimitedRetTypeInference) {
916        newRetTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(tsRetType, funcLikeDecl, NodeBuilderFlags.None);
917        autofixable = !!newRetTypeNode;
918
919        if (!isFuncExpr && newRetTypeNode && shouldAutofix(funcLikeDecl, FaultID.LimitedReturnTypeInference)) {
920          autofix = [fixReturnType(funcLikeDecl, newRetTypeNode)];
921        }
922      }
923    }
924
925    // Don't report here if in function expression context.
926    // See handleFunctionExpression for details.
927    if (hasLimitedRetTypeInference && !isFuncExpr) {
928      this.incrementCounters(funcLikeDecl, FaultID.LimitedReturnTypeInference, autofixable, autofix);
929    }
930    return [hasLimitedRetTypeInference && !newRetTypeNode, newRetTypeNode];
931  }
932
933  private hasLimitedTypeInferenceFromReturnExpr(funBody: ConciseBody): boolean {
934    let hasLimitedTypeInference = false;
935    function visitNode(tsNode: Node): void {
936      if (hasLimitedTypeInference) {
937        return;
938      }
939
940      if (
941        isReturnStatement(tsNode) && tsNode.expression &&
942        isCallToFunctionWithOmittedReturnType(unwrapParenthesized(tsNode.expression))
943      ) {
944        hasLimitedTypeInference = true;
945        return;
946      }
947
948      // Visit children nodes. Don't traverse other nested function-like declarations.
949      if (
950        !isFunctionDeclaration(tsNode) &&
951        !isFunctionExpression(tsNode) &&
952        !isMethodDeclaration(tsNode) &&
953        !isAccessor(tsNode) &&
954        !isArrowFunction(tsNode)
955      ) {
956        tsNode.forEachChild(visitNode);
957      }
958    }
959
960    if (isBlock(funBody)) {
961      visitNode(funBody);
962    }
963    else {
964      const tsExpr = unwrapParenthesized(funBody);
965      hasLimitedTypeInference = isCallToFunctionWithOmittedReturnType(tsExpr);
966    }
967
968    return hasLimitedTypeInference;
969  }
970
971  private handlePrefixUnaryExpression(node: Node) {
972    const tsUnaryArithm = node as PrefixUnaryExpression;
973    const tsUnaryOp = tsUnaryArithm.operator;
974    if (
975      tsUnaryOp === SyntaxKind.PlusToken ||
976      tsUnaryOp === SyntaxKind.MinusToken ||
977      tsUnaryOp === SyntaxKind.TildeToken
978    ) {
979      const tsOperatndType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsUnaryArithm.operand);
980      if (!(tsOperatndType.getFlags() & (TypeFlags.NumberLike | TypeFlags.BigIntLiteral)) ||
981            (tsUnaryOp === SyntaxKind.TildeToken && tsUnaryArithm.operand.kind === SyntaxKind.NumericLiteral &&
982              !isIntegerConstantValue(tsUnaryArithm.operand as NumericLiteral))
983          ) {
984        this.incrementCounters(node, FaultID.UnaryArithmNotNumber);
985      }
986    }
987  }
988
989  private handleBinaryExpression(node: Node): void {
990    const tsBinaryExpr = node as BinaryExpression;
991    const tsLhsExpr = tsBinaryExpr.left;
992    const tsRhsExpr = tsBinaryExpr.right;
993
994    if (isAssignmentOperator(tsBinaryExpr.operatorToken)) {
995      if (isObjectLiteralExpression(tsLhsExpr) || isArrayLiteralExpression(tsLhsExpr)) {
996        this.incrementCounters(node, FaultID.DestructuringAssignment);
997      }
998      if (isPropertyAccessExpression(tsLhsExpr)) {
999        const tsLhsSymbol = trueSymbolAtLocation(tsLhsExpr);
1000        const tsLhsBaseSymbol = trueSymbolAtLocation(tsLhsExpr.expression);
1001        if (tsLhsSymbol && (tsLhsSymbol.flags & SymbolFlags.Method)) {
1002          this.incrementCounters(tsLhsExpr, FaultID.NoUndefinedPropAccess);
1003        }
1004        if (
1005          isMethodAssignment(tsLhsSymbol) && tsLhsBaseSymbol &&
1006          (tsLhsBaseSymbol.flags & SymbolFlags.Function) !== 0
1007        ) {
1008          this.incrementCounters(tsLhsExpr, FaultID.PropertyDeclOnFunction);
1009        }
1010      }
1011    }
1012
1013    const leftOperandType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsLhsExpr);
1014    const rightOperandType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsRhsExpr);
1015
1016    if (tsBinaryExpr.operatorToken.kind === SyntaxKind.PlusToken) {
1017      if (isEnumMemberType(leftOperandType) && isEnumMemberType(rightOperandType)) {
1018        if (
1019            ((leftOperandType.flags & (TypeFlags.NumberLike)) && (rightOperandType.getFlags() & (TypeFlags.NumberLike))) ||
1020            ((leftOperandType.flags & (TypeFlags.StringLike)) && (rightOperandType.getFlags() & (TypeFlags.StringLike)))
1021          ) {
1022          return;
1023        }
1024      }
1025      else if (isNumberType(leftOperandType) && isNumberType(rightOperandType)) {
1026        return;
1027      }
1028      else if (isStringLikeType(leftOperandType) || isStringLikeType(rightOperandType)) {
1029        return;
1030      }
1031    }
1032    else if (
1033      tsBinaryExpr.operatorToken.kind === SyntaxKind.AmpersandToken ||
1034      tsBinaryExpr.operatorToken.kind === SyntaxKind.BarToken ||
1035      tsBinaryExpr.operatorToken.kind === SyntaxKind.CaretToken ||
1036      tsBinaryExpr.operatorToken.kind === SyntaxKind.LessThanLessThanToken ||
1037      tsBinaryExpr.operatorToken.kind === SyntaxKind.GreaterThanGreaterThanToken ||
1038      tsBinaryExpr.operatorToken.kind === SyntaxKind.GreaterThanGreaterThanGreaterThanToken
1039    ) {
1040      if (!(isNumberType(leftOperandType) && isNumberType(rightOperandType)) ||
1041            (tsLhsExpr.kind === SyntaxKind.NumericLiteral && !isIntegerConstantValue(tsLhsExpr as NumericLiteral)) ||
1042            (tsRhsExpr.kind === SyntaxKind.NumericLiteral && !isIntegerConstantValue(tsRhsExpr as NumericLiteral))
1043          ) {
1044        return; //this.incrementCounters(node, FaultID.BitOpWithWrongType);
1045      }
1046    }
1047    else if (tsBinaryExpr.operatorToken.kind === SyntaxKind.CommaToken) {
1048      // CommaOpertor is allowed in 'for' statement initalizer and incrementor
1049      let tsExprNode: Node = tsBinaryExpr;
1050      let tsParentNode = tsExprNode.parent;
1051      while (tsParentNode && tsParentNode.kind === SyntaxKind.BinaryExpression) {
1052        tsExprNode = tsParentNode;
1053        tsParentNode = tsExprNode.parent;
1054      }
1055
1056      if (tsParentNode && tsParentNode.kind === SyntaxKind.ForStatement) {
1057        const tsForNode = tsParentNode as ForStatement;
1058        if (tsExprNode === tsForNode.initializer || tsExprNode === tsForNode.incrementor) return;
1059      }
1060      this.incrementCounters(node, FaultID.CommaOperator);
1061    }
1062    else if (tsBinaryExpr.operatorToken.kind === SyntaxKind.InstanceOfKeyword) {
1063      const leftExpr = unwrapParenthesized(tsBinaryExpr.left);
1064      const leftSymbol = trueSymbolAtLocation(leftExpr);
1065      // In STS, the left-hand side expression may be of any reference type, otherwise
1066      // a compile-time error occurs. In addition, the left operand in STS cannot be a type.
1067      if (tsLhsExpr.kind === SyntaxKind.ThisKeyword) {
1068        return;
1069      }
1070      if (isPrimitiveType(leftOperandType) || isTypeNode(leftExpr) || isTypeSymbol(leftSymbol)) {
1071        this.incrementCounters(node, FaultID.InstanceofUnsupported);
1072      }
1073    }
1074    else if (tsBinaryExpr.operatorToken.kind === SyntaxKind.EqualsToken) {
1075      if (needToDeduceStructuralIdentity(rightOperandType, leftOperandType)) {
1076        this.incrementCounters(tsBinaryExpr, FaultID.StructuralIdentity);
1077      }
1078      const typeNode = getVariableDeclarationTypeNode(tsLhsExpr);
1079      this.handleEsObjectAssignment(tsBinaryExpr, typeNode, tsRhsExpr);
1080    }
1081  }
1082
1083  private handleVariableDeclarationList(node: Node): void {
1084    const varDeclFlags = getCombinedNodeFlags(node);
1085    if (!(varDeclFlags & (NodeFlags.Let | NodeFlags.Const))) {
1086      this.incrementCounters(node, FaultID.VarDeclaration);
1087    }
1088  }
1089
1090  private handleVariableDeclaration(node: Node): void {
1091    const tsVarDecl = node as VariableDeclaration;
1092    if (isArrayBindingPattern(tsVarDecl.name) || isObjectBindingPattern(tsVarDecl.name)) {
1093      this.incrementCounters(node, FaultID.DestructuringDeclaration);
1094    }
1095    {
1096      // Check variable declaration for duplicate name.
1097      const visitBindingPatternNames = (tsBindingName: BindingName): void => {
1098        if (isIdentifier(tsBindingName)) {
1099          // The syntax kind of the declaration is defined here by the parent of 'BindingName' node.
1100          this.countDeclarationsWithDuplicateName(tsBindingName, tsBindingName, tsBindingName.parent.kind);
1101        }
1102        else {
1103          for (const tsBindingElem of tsBindingName.elements) {
1104            if (isOmittedExpression(tsBindingElem)) continue;
1105
1106            visitBindingPatternNames(tsBindingElem.name);
1107          }
1108        }
1109      };
1110
1111      visitBindingPatternNames(tsVarDecl.name);
1112    }
1113
1114    if (tsVarDecl.type && tsVarDecl.initializer) {
1115      const tsVarInit = tsVarDecl.initializer;
1116      const tsVarType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsVarDecl.type);
1117      const tsInitType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsVarInit);
1118      if (needToDeduceStructuralIdentity(tsInitType, tsVarType)) {
1119        this.incrementCounters(tsVarDecl, FaultID.StructuralIdentity);
1120      }
1121    }
1122
1123    this.handleEsObjectDelaration(tsVarDecl);
1124    this.handleDeclarationInferredType(tsVarDecl);
1125    this.handleDefiniteAssignmentAssertion(tsVarDecl);
1126  }
1127
1128  private handleEsObjectDelaration(node: VariableDeclaration) {
1129    const isDeclaredESObject = !!node.type && isEsObjectType(node.type);
1130    const initalizerTypeNode = node.initializer && getVariableDeclarationTypeNode(node.initializer);
1131    const isInitializedWithESObject = !!initalizerTypeNode && isEsObjectType(initalizerTypeNode);
1132    const isLocal = isInsideBlock(node);
1133    if ((isDeclaredESObject || isInitializedWithESObject) && !isLocal) {
1134      this.incrementCounters(node, FaultID.EsObjectType);
1135      return;
1136    }
1137
1138    if (node.initializer) {
1139      this.handleEsObjectAssignment(node, node.type, node.initializer);
1140      return;
1141    }
1142  }
1143
1144  private handleEsObjectAssignment(node: Node, nodeDeclType: TypeNode | undefined, initializer: Node) {
1145    const isTypeAnnotated = !!nodeDeclType;
1146    const isDeclaredESObject = !!nodeDeclType && isEsObjectType(nodeDeclType);
1147    const initalizerTypeNode = getVariableDeclarationTypeNode(initializer);
1148    const isInitializedWithESObject = !!initalizerTypeNode && isEsObjectType(initalizerTypeNode);
1149    if (isTypeAnnotated && !isDeclaredESObject && isInitializedWithESObject) {
1150      this.incrementCounters(node, FaultID.EsObjectType);
1151      return;
1152    }
1153
1154    if (isDeclaredESObject && !isValueAssignableToESObject(initializer)) {
1155      this.incrementCounters(node, FaultID.EsObjectType);
1156    }
1157  }
1158
1159
1160  private handleCatchClause(node: Node): void {
1161    const tsCatch = node as CatchClause;
1162    // In TS catch clause doesn't permit specification of the exception varible type except 'any' or 'unknown'.
1163    // It is not compatible with STS 'catch' where the exception varilab has to be of type
1164    // 'Exception' or derived from it.
1165    // So each 'catch' which has explicite type for the exception object goes to problems in strict mode.
1166    if (tsCatch.variableDeclaration && tsCatch.variableDeclaration.type) {
1167      this.incrementCounters(node, FaultID.CatchWithUnsupportedType);
1168    }
1169  }
1170
1171  private handleClassDeclaration(node: Node): void {
1172    const tsClassDecl = node as ClassDeclaration;
1173    this.staticBlocks.clear();
1174
1175    if (tsClassDecl.name) {
1176      this.countDeclarationsWithDuplicateName(tsClassDecl.name, tsClassDecl);
1177    }
1178    this.countClassMembersWithDuplicateName(tsClassDecl);
1179
1180    const visitHClause = (hClause: HeritageClause) => {
1181      for (const tsTypeExpr of hClause.types) {
1182        const tsExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeExpr.expression);
1183        if (tsExprType.isClass() && hClause.token === SyntaxKind.ImplementsKeyword) {
1184          this.incrementCounters(tsTypeExpr, FaultID.ImplementsClass);
1185        }
1186      }
1187    };
1188
1189    if (tsClassDecl.heritageClauses) {
1190      for (const hClause of tsClassDecl.heritageClauses) {
1191        if (!hClause) {
1192          continue;
1193        }
1194        visitHClause(hClause);
1195      }
1196    }
1197
1198    this.handleDecorators(getDecorators(tsClassDecl));
1199
1200    if (!this.skipArkTSStaticBlocksCheck) {
1201      let hasStaticBlock = false;
1202      for (const element of tsClassDecl.members) {
1203        if (isClassStaticBlockDeclaration(element)) {
1204          if (hasStaticBlock) {
1205            this.incrementCounters(element, FaultID.MultipleStaticBlocks);
1206          } else {
1207            hasStaticBlock = true;
1208          }
1209        }
1210      }
1211    }
1212  }
1213
1214  private handleModuleDeclaration(node: Node): void {
1215    const tsModuleDecl = node as ModuleDeclaration;
1216    this.countDeclarationsWithDuplicateName(tsModuleDecl.name, tsModuleDecl);
1217
1218    const tsModuleBody = tsModuleDecl.body;
1219    const tsModifiers = tsModuleDecl.modifiers; // TSC 4.2 doesn't have 'getModifiers()' method
1220    if (tsModuleBody) {
1221      if (isModuleBlock(tsModuleBody)) {
1222        for (const tsModuleStmt of tsModuleBody.statements) {
1223          switch (tsModuleStmt.kind) {
1224            case SyntaxKind.VariableStatement:
1225            case SyntaxKind.FunctionDeclaration:
1226            case SyntaxKind.ClassDeclaration:
1227            case SyntaxKind.InterfaceDeclaration:
1228            case SyntaxKind.TypeAliasDeclaration:
1229            case SyntaxKind.EnumDeclaration:
1230            case SyntaxKind.ExportDeclaration:
1231              break;
1232            // Nested namespace declarations are prohibited
1233            // but there is no cookbook recipe for it!
1234            case SyntaxKind.ModuleDeclaration:
1235              break;
1236            default:
1237              this.incrementCounters(tsModuleStmt, FaultID.NonDeclarationInNamespace);
1238              break;
1239          }
1240        }
1241      }
1242    }
1243
1244    if (!(tsModuleDecl.flags & NodeFlags.Namespace) &&
1245        hasModifier(tsModifiers, SyntaxKind.DeclareKeyword)) {
1246      this.incrementCounters(tsModuleDecl, FaultID.ShorthandAmbientModuleDecl);
1247    }
1248
1249    if (isStringLiteral(tsModuleDecl.name) && tsModuleDecl.name.text.includes("*")) {
1250      this.incrementCounters(tsModuleDecl, FaultID.WildcardsInModuleName);
1251    }
1252  }
1253
1254  private handleTypeAliasDeclaration(node: Node): void {
1255    const tsTypeAlias = node as TypeAliasDeclaration;
1256    this.countDeclarationsWithDuplicateName(tsTypeAlias.name, tsTypeAlias);
1257  }
1258
1259  private handleImportClause(node: Node): void {
1260    const tsImportClause = node as ImportClause;
1261    if (tsImportClause.name) {
1262      this.countDeclarationsWithDuplicateName(tsImportClause.name, tsImportClause);
1263    }
1264
1265    if (tsImportClause.namedBindings && isNamedImports(tsImportClause.namedBindings)) {
1266      const nonDefaultSpecs: ImportSpecifier[] = [];
1267      let defaultSpec: ImportSpecifier | undefined;
1268      for (const importSpec of tsImportClause.namedBindings.elements) {
1269        if (isDefaultImport(importSpec)) {
1270          defaultSpec = importSpec;
1271        }
1272        else nonDefaultSpecs.push(importSpec);
1273      }
1274      if (defaultSpec) {
1275        let autofix: Autofix[] | undefined;
1276        // if (Autofixer.shouldAutofix(defaultSpec, FaultID.DefaultImport))
1277        //  autofix = [ Autofixer.fixDefaultImport(tsImportClause, defaultSpec, nonDefaultSpecs) ];
1278        this.incrementCounters(defaultSpec, FaultID.DefaultImport, true, autofix);
1279      }
1280    }
1281  }
1282
1283  private handleImportSpecifier(node: Node): void {
1284    const tsImportSpecifier = node as ImportSpecifier;
1285    this.countDeclarationsWithDuplicateName(tsImportSpecifier.name, tsImportSpecifier);
1286  }
1287
1288  private handleNamespaceImport(node: Node): void {
1289    const tsNamespaceImport = node as NamespaceImport;
1290    this.countDeclarationsWithDuplicateName(tsNamespaceImport.name, tsNamespaceImport);
1291  }
1292
1293  private handleTypeAssertionExpression(node: Node): void {
1294    const tsTypeAssertion = node as TypeAssertion;
1295    if (tsTypeAssertion.type.getText() === "const") {
1296      this.incrementCounters(tsTypeAssertion, FaultID.ConstAssertion);
1297    }
1298    else {
1299      this.incrementCounters(node, FaultID.TypeAssertion);
1300    }
1301  }
1302
1303  private handleMethodDeclaration(node: Node): void {
1304    const tsMethodDecl = node as MethodDeclaration;
1305    const hasThis = this.functionContainsThis(tsMethodDecl);
1306    let isStatic = false;
1307    if (tsMethodDecl.modifiers) {
1308      for (const mod of tsMethodDecl.modifiers) {
1309        if (mod.kind === SyntaxKind.StaticKeyword) {
1310          isStatic = true;
1311          break;
1312        }
1313      }
1314    }
1315
1316    if (isStatic && hasThis) {
1317      this.incrementCounters(node, FaultID.FunctionContainsThis);
1318    }
1319    if (!tsMethodDecl.type) {
1320      this.handleMissingReturnType(tsMethodDecl);
1321    }
1322    if (tsMethodDecl.asteriskToken) {
1323      this.incrementCounters(node, FaultID.GeneratorFunction);
1324    }
1325    this.handleDecorators(getDecorators(tsMethodDecl));
1326    this.filterOutDecoratorsDiagnostics(getDecorators(tsMethodDecl), NON_RETURN_FUNCTION_DECORATORS,
1327      { begin: tsMethodDecl.parameters.end, end: tsMethodDecl.body?.getStart() ?? tsMethodDecl.parameters.end },
1328      FUNCTION_HAS_NO_RETURN_ERROR_CODE);
1329  }
1330
1331  private handleIdentifier(node: Node): void {
1332    const tsIdentifier = node as Identifier;
1333    const tsIdentSym = trueSymbolAtLocation(tsIdentifier);
1334
1335    if (!tsIdentSym) {
1336      return;
1337    }
1338
1339    if (
1340      (tsIdentSym.flags & SymbolFlags.Module) !== 0 &&
1341      (tsIdentSym.flags & SymbolFlags.Transient) !== 0 &&
1342      tsIdentifier.text === "globalThis"
1343    ) {
1344      this.incrementCounters(node, FaultID.GlobalThis);
1345    } else {
1346      this.handleRestrictedValues(tsIdentifier, tsIdentSym);
1347    }
1348  }
1349
1350  private isAllowedClassValueContext(tsIdentifier: Identifier /* Param not used ! ??, tsIdentSym: Symbol */ /* Param not used ! ??, tsIdentSym: Symbol */): boolean {
1351    let ctx: Node = tsIdentifier;
1352    while (isPropertyAccessExpression(ctx.parent) || isQualifiedName(ctx.parent)) {
1353      ctx = ctx.parent;
1354    }
1355    if (isPropertyAssignment(ctx.parent) && isObjectLiteralExpression(ctx.parent.parent)) {
1356      ctx = ctx.parent.parent;
1357    }
1358    if (isArrowFunction(ctx.parent) && ctx.parent.body === ctx) {
1359      ctx = ctx.parent;
1360    }
1361
1362    if (isCallExpression(ctx.parent) || isNewExpression(ctx.parent)) {
1363      const callee = ctx.parent.expression;
1364      const isAny = isAnyType(TypeScriptLinter.tsTypeChecker.getTypeAtLocation(callee));
1365      const isDynamic = isAny || hasLibraryType(callee);
1366      if (callee !== ctx && isDynamic) {
1367        return true;
1368      }
1369    }
1370    return false;
1371  }
1372
1373  private handleRestrictedValues(tsIdentifier: Identifier, tsIdentSym: Symbol) {
1374    const illegalValues = SymbolFlags.ConstEnum | SymbolFlags.RegularEnum | SymbolFlags.ValueModule | SymbolFlags.Class;
1375    // If module name is duplicated by another declaration, this increases the possibility
1376    // of finding a lot of false positives. Thus, do not check further in that case.
1377    if ((tsIdentSym.flags & SymbolFlags.ValueModule) !== 0) {
1378      if (!!tsIdentSym && symbolHasDuplicateName(tsIdentSym, SyntaxKind.ModuleDeclaration)) {
1379        return;
1380      }
1381    }
1382    if ((tsIdentSym.flags & illegalValues) === 0 || isStruct(tsIdentSym) ||
1383        !this.identiferUseInValueContext(tsIdentifier, tsIdentSym)) {
1384          return;
1385    }
1386    if ((tsIdentSym.flags & SymbolFlags.Class) !== 0) {
1387      if (this.isAllowedClassValueContext(tsIdentifier /* param not used!?? , tsIdentSym */)) {
1388        return;
1389      }
1390    }
1391
1392    if (tsIdentSym.flags & SymbolFlags.ValueModule) {
1393      this.incrementCounters(tsIdentifier, FaultID.NamespaceAsObject);
1394    }
1395    else {
1396      // missing EnumAsObject
1397      this.incrementCounters(tsIdentifier, FaultID.ClassAsObject);
1398    }
1399  }
1400
1401  private identiferUseInValueContext(
1402    ident: Identifier,
1403    tsSym: Symbol
1404    ) {
1405    // If identifier is the right-most name of Property Access chain or Qualified name,
1406    // or it's a separate identifier expression, then identifier is being referenced as an value.
1407    let qualifiedStart: Node = ident;
1408    while (isPropertyAccessExpression(qualifiedStart.parent) || isQualifiedName(qualifiedStart.parent)) {
1409      qualifiedStart = qualifiedStart.parent;
1410    }
1411    const parent = qualifiedStart.parent;
1412    return !(
1413      // treat TypeQuery as valid because it's already forbidden (FaultID.TypeQuery)
1414      (isTypeNode(parent) && !isTypeOfExpression(parent)) ||
1415      // ElementAccess is allowed for enum types
1416      this.isEnumPropAccess(ident, tsSym, parent) ||
1417      isExpressionWithTypeArguments(parent) ||
1418      isExportAssignment(parent) ||
1419      isExportSpecifier(parent) ||
1420      isMetaProperty(parent) ||
1421      isImportClause(parent) ||
1422      isClassLike(parent) ||
1423      isInterfaceDeclaration(parent) ||
1424      isModuleDeclaration(parent) ||
1425      isEnumDeclaration(parent) ||
1426      isNamespaceImport(parent) ||
1427      isImportSpecifier(parent) ||
1428      isImportEqualsDeclaration(parent) ||
1429      (isQualifiedName(qualifiedStart) && ident !== qualifiedStart.right) ||
1430      (isPropertyAccessExpression(qualifiedStart) &&
1431        ident !== qualifiedStart.name) ||
1432      (isNewExpression(qualifiedStart.parent) &&
1433        qualifiedStart === qualifiedStart.parent.expression) ||
1434      (isBinaryExpression(qualifiedStart.parent) &&
1435        qualifiedStart.parent.operatorToken.kind ===
1436        SyntaxKind.InstanceOfKeyword)
1437    );
1438  }
1439
1440  private isEnumPropAccess(ident: Identifier, tsSym: Symbol, context: Node): boolean {
1441    return isElementAccessExpression(context) && !!(tsSym.flags & SymbolFlags.Enum) &&
1442      (context.expression == ident ||
1443        (isPropertyAccessExpression(context.expression) && context.expression.name === ident));
1444  }
1445
1446  private handleElementAccessExpression(node: Node): void {
1447    const tsElementAccessExpr = node as ElementAccessExpression;
1448    const tsElemAccessBaseExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsElementAccessExpr.expression);
1449    const tsElemAccessBaseExprTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(tsElemAccessBaseExprType, undefined, NodeBuilderFlags.None);
1450    const isDerivedFromArray = isDerivedFrom(tsElemAccessBaseExprType, CheckType.Array);
1451    const checkClassOrInterface = tsElemAccessBaseExprType.isClassOrInterface() &&
1452                                  !isGenericArrayType(tsElemAccessBaseExprType) &&
1453                                  !isDerivedFromArray;
1454    const checkThisOrSuper = isThisOrSuperExpr(tsElementAccessExpr.expression) && !isDerivedFromArray;
1455
1456    // if (this.tsUtils.isEnumType(tsElemAccessBaseExprType)) {
1457    //   implement argument expression type check
1458    //   let argType = this.tsTypeChecker.getTypeAtLocation(tsElementAccessExpr.argumentExpression);
1459    //   if (argType.aliasSymbol == this.tsUtils.trueSymbolAtLocation(tsElementAccessExpr.expression)) {
1460    //     return;
1461    //   }
1462    //   check if constant EnumMember inferred ...
1463    //   this.incrementCounters(node, FaultID.PropertyAccessByIndex, autofixable, autofix);
1464    // }
1465    if (
1466        !isLibraryType(tsElemAccessBaseExprType) && !isTypedArray(tsElemAccessBaseExprTypeNode) &&
1467          (checkClassOrInterface ||
1468            isObjectLiteralType(tsElemAccessBaseExprType) || checkThisOrSuper)
1469        ) {
1470      let autofix = fixPropertyAccessByIndex(node);
1471      const autofixable = autofix !== undefined;
1472      if (!shouldAutofix(node, FaultID.PropertyAccessByIndex)) {
1473        autofix = undefined;
1474      }
1475      this.incrementCounters(node, FaultID.PropertyAccessByIndex, autofixable, autofix);
1476    }
1477    if (hasEsObjectType(tsElementAccessExpr.expression)) {
1478      this.incrementCounters(node, FaultID.EsObjectType);
1479    }
1480  }
1481
1482  private handleEnumMember(node: Node): void {
1483    const tsEnumMember = node as EnumMember;
1484    const tsEnumMemberType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsEnumMember);
1485    const constVal = TypeScriptLinter.tsTypeChecker.getConstantValue(tsEnumMember);
1486
1487    if (tsEnumMember.initializer && !isValidEnumMemberInit(tsEnumMember.initializer)) {
1488      this.incrementCounters(node, FaultID.EnumMemberNonConstInit);
1489    }
1490    // check for type - all members should be of same type
1491    const enumDecl = tsEnumMember.parent;
1492    const firstEnumMember = enumDecl.members[0];
1493    const firstEnumMemberType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(firstEnumMember);
1494    const firstElewmVal = TypeScriptLinter.tsTypeChecker.getConstantValue(firstEnumMember);
1495    // each string enum member has its own type
1496    // so check that value type is string
1497    if(constVal !==undefined && typeof constVal === "string" &&
1498        firstElewmVal !==undefined && typeof firstElewmVal === "string") {
1499      return;
1500    }
1501    if (constVal !==undefined && typeof constVal === "number" &&
1502        firstElewmVal !==undefined && typeof firstElewmVal === "number") {
1503      return;
1504    }
1505    if(firstEnumMemberType !== tsEnumMemberType) {
1506      this.incrementCounters(node, FaultID.EnumMemberNonConstInit);
1507    }
1508  }
1509
1510  private handleExportAssignment(node: Node): void {
1511    // (nsizov): check exportEquals and determine if it's an actual `export assignment`
1512    //   or a `default export namespace` when this two cases will be determined in cookbook
1513    const exportAssignment = node as ExportAssignment;
1514    if (exportAssignment.isExportEquals) {
1515      this.incrementCounters(node, FaultID.ExportAssignment);
1516    }
1517  }
1518
1519  private handleCallExpression(node: Node): void {
1520    const tsCallExpr = node as CallExpression;
1521
1522    const calleeSym = trueSymbolAtLocation(tsCallExpr.expression);
1523    const calleeType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsCallExpr.expression);
1524    const callSignature = TypeScriptLinter.tsTypeChecker.getResolvedSignature(tsCallExpr);
1525
1526    this.handleImportCall(tsCallExpr);
1527    this.handleRequireCall(tsCallExpr);
1528    // NOTE: Keep handleFunctionApplyBindPropCall above handleGenericCallWithNoTypeArgs here!!!
1529    if (calleeSym !== undefined) {
1530      this.handleStdlibAPICall(tsCallExpr, calleeSym);
1531      this.handleFunctionApplyBindPropCall(tsCallExpr, calleeSym);
1532      if (symbolHasEsObjectType(calleeSym)) {
1533        this.incrementCounters(tsCallExpr, FaultID.EsObjectType);
1534      }
1535    }
1536    if (callSignature !== undefined) {
1537      if (!isLibrarySymbol(calleeSym)) {
1538        this.handleGenericCallWithNoTypeArgs(tsCallExpr, callSignature);
1539      }
1540      this.handleStructIdentAndUndefinedInArgs(tsCallExpr, callSignature);
1541    }
1542    this.handleLibraryTypeCall(tsCallExpr, calleeType);
1543
1544    if (isPropertyAccessExpression(tsCallExpr.expression) && hasEsObjectType(tsCallExpr.expression.expression)) {
1545      this.incrementCounters(node, FaultID.EsObjectType);
1546    }
1547  }
1548
1549  private handleImportCall(tsCallExpr: CallExpression): void {
1550    if (tsCallExpr.expression.kind === SyntaxKind.ImportKeyword) {
1551      // relax rule#133 "arkts-no-runtime-import"
1552      // this.incrementCounters(tsCallExpr, FaultID.DynamicImport);
1553      const tsArgs = tsCallExpr.arguments;
1554      if (tsArgs.length > 1 && isObjectLiteralExpression(tsArgs[1])) {
1555        const objLitExpr = tsArgs[1] as ObjectLiteralExpression;
1556        for (const tsProp of objLitExpr.properties) {
1557          if (isPropertyAssignment(tsProp) || isShorthandPropertyAssignment(tsProp)) {
1558            if (tsProp.name.getText() === "assert") {
1559              this.incrementCounters(tsProp, FaultID.ImportAssertion);
1560              break;
1561            }
1562          }
1563        }
1564      }
1565    }
1566  }
1567
1568  private handleRequireCall(tsCallExpr: CallExpression): void {
1569    if (
1570      isIdentifier(tsCallExpr.expression) &&
1571      tsCallExpr.expression.text === "require" &&
1572      isVariableDeclaration(tsCallExpr.parent)
1573    ) {
1574      const tsType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsCallExpr.expression);
1575      if (isInterfaceType(tsType) && tsType.symbol.name === "NodeRequire") {
1576        this.incrementCounters(tsCallExpr.parent, FaultID.ImportAssignment);
1577      }
1578    }
1579  }
1580
1581  private handleGenericCallWithNoTypeArgs(callLikeExpr: CallExpression | NewExpression, callSignature: Signature) {
1582
1583    const tsSyntaxKind = isNewExpression(callLikeExpr) ? SyntaxKind.Constructor : SyntaxKind.FunctionDeclaration;
1584    const signDecl = TypeScriptLinter.tsTypeChecker.signatureToSignatureDeclaration(callSignature, tsSyntaxKind,
1585        undefined, NodeBuilderFlags.WriteTypeArgumentsOfSignature | NodeBuilderFlags.IgnoreErrors);
1586
1587    if (signDecl?.typeArguments) {
1588      const resolvedTypeArgs = signDecl.typeArguments;
1589
1590      const startTypeArg = callLikeExpr.typeArguments?.length ?? 0;
1591      for (let i = startTypeArg; i < resolvedTypeArgs.length; ++i) {
1592        const typeNode = resolvedTypeArgs[i];
1593        // if compiler infers 'unknown' type there are 2 possible cases:
1594        //   1. Compiler unable to infer type from arguments and use 'unknown'
1595        //   2. Compiler infer 'unknown' from arguments
1596        // We report error in both cases. It is ok because we cannot use 'unknown'
1597        // in ArkTS and already have separate check for it.
1598        if (typeNode.kind === SyntaxKind.UnknownKeyword) {
1599          this.incrementCounters(callLikeExpr, FaultID.GenericCallNoTypeArgs);
1600          break;
1601        }
1602      }
1603    }
1604  }
1605
1606  private static listApplyBindCallApis = [
1607    "Function.apply",
1608    "Function.call",
1609    "Function.bind",
1610    "CallableFunction.apply",
1611    "CallableFunction.call",
1612    "CallableFunction.bind"
1613  ];
1614  private handleFunctionApplyBindPropCall(tsCallExpr: CallExpression, calleeSym: Symbol) {
1615    const exprName = TypeScriptLinter.tsTypeChecker.getFullyQualifiedName(calleeSym);
1616    if (TypeScriptLinter.listApplyBindCallApis.includes(exprName)) {
1617      this.incrementCounters(tsCallExpr, FaultID.FunctionApplyBindCall);
1618    }
1619  }
1620
1621  private handleStructIdentAndUndefinedInArgs(tsCallOrNewExpr: CallExpression | NewExpression, callSignature: Signature) {
1622    if (!tsCallOrNewExpr.arguments) {
1623      return;
1624    }
1625
1626    for (let argIndex = 0; argIndex < tsCallOrNewExpr.arguments.length; ++argIndex) {
1627      const tsArg = tsCallOrNewExpr.arguments[argIndex];
1628      const tsArgType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsArg);
1629      if (!tsArgType) continue;
1630
1631      let paramIndex = argIndex < callSignature.parameters.length ? argIndex : callSignature.parameters.length-1;
1632      let tsParamSym = callSignature.parameters[paramIndex];
1633      if (!tsParamSym) continue;
1634
1635      const tsParamDecl = tsParamSym.valueDeclaration;
1636      if (tsParamDecl && isParameter(tsParamDecl)) {
1637        let tsParamType = TypeScriptLinter.tsTypeChecker.getTypeOfSymbolAtLocation(tsParamSym, tsParamDecl);
1638        if (tsParamDecl.dotDotDotToken && isGenericArrayType(tsParamType) && tsParamType.typeArguments) {
1639          tsParamType = tsParamType.typeArguments[0];
1640        }
1641        if (!tsParamType) continue;
1642
1643        if (needToDeduceStructuralIdentity(tsArgType, tsParamType)) {
1644          this.incrementCounters(tsArg, FaultID.StructuralIdentity);
1645        }
1646      }
1647    }
1648  }
1649
1650  // let re = new RegExp("^(" + arr.reduce((acc, v) => ((acc ? (acc + "|") : "") + v)) +")$")
1651  private static LimitedApis = new Map<string, {arr: Array<string> | null, fault: FaultID}> ([
1652    ["global", {arr: LIMITED_STD_GLOBAL_FUNC, fault: FaultID.LimitedStdLibApi}],
1653    ["Object", {arr: LIMITED_STD_OBJECT_API, fault: FaultID.LimitedStdLibApi}],
1654    ["ObjectConstructor", {arr: LIMITED_STD_OBJECT_API, fault: FaultID.LimitedStdLibApi}],
1655    ["Reflect", {arr: LIMITED_STD_REFLECT_API, fault: FaultID.LimitedStdLibApi}],
1656    ["ProxyHandler", {arr: LIMITED_STD_PROXYHANDLER_API, fault: FaultID.LimitedStdLibApi}],
1657    ["Symbol", {arr: null, fault: FaultID.SymbolType}],
1658    ["SymbolConstructor", {arr: null, fault: FaultID.SymbolType}],
1659  ])
1660
1661  private handleStdlibAPICall(callExpr: CallExpression, calleeSym: Symbol) {
1662    const name = calleeSym.getName();
1663    const parName = getParentSymbolName(calleeSym);
1664    if (parName === undefined) {
1665      if (LIMITED_STD_GLOBAL_FUNC.includes(name)) {
1666        this.incrementCounters(callExpr, FaultID.LimitedStdLibApi);
1667        return;
1668      }
1669      let escapedName = calleeSym.escapedName;
1670      if (escapedName === 'Symbol' || escapedName === 'SymbolConstructor') {
1671        this.incrementCounters(callExpr, FaultID.SymbolType);
1672      }
1673      return;
1674    }
1675    let lookup = TypeScriptLinter.LimitedApis.get(parName);
1676    if (lookup !== undefined && (lookup.arr === null || lookup.arr.includes(name))) {
1677      this.incrementCounters(callExpr, lookup.fault);
1678    };
1679  }
1680
1681  private findNonFilteringRangesFunctionCalls(callExpr: CallExpression): { begin: number, end: number }[] {
1682    let args = callExpr.arguments;
1683    let result: { begin: number, end: number }[] = [];
1684    for (const arg of args) {
1685      if (isArrowFunction(arg)) {
1686        let arrowFuncExpr = arg as ArrowFunction;
1687        result.push({begin: arrowFuncExpr.body.pos, end: arrowFuncExpr.body.end});
1688      } else if (isCallExpression(arg)) {
1689        result.push({begin: arg.arguments.pos, end: arg.arguments.end});
1690      }
1691      // there may be other cases
1692    }
1693    return result;
1694  }
1695
1696  private handleLibraryTypeCall(callExpr: CallExpression, calleeType: Type) {
1697    let inLibCall = isLibraryType(calleeType);
1698    const diagnosticMessages: Array<DiagnosticMessageChain> = [];
1699    this.libraryTypeCallDiagnosticChecker.configure(inLibCall, diagnosticMessages);
1700
1701    let nonFilteringRanges = this.findNonFilteringRangesFunctionCalls(callExpr);
1702    let rangesToFilter: { begin: number, end: number }[] = [];
1703    if (nonFilteringRanges.length !== 0) {
1704      let rangesSize = nonFilteringRanges.length;
1705      rangesToFilter.push({ begin: callExpr.arguments.pos, end: nonFilteringRanges[0].begin })
1706      rangesToFilter.push({ begin: nonFilteringRanges[rangesSize - 1].end, end: callExpr.arguments.end })
1707      for (let i = 0; i < rangesSize - 1; i++) {
1708        rangesToFilter.push({ begin: nonFilteringRanges[i].end, end: nonFilteringRanges[i + 1].begin })
1709      }
1710    } else {
1711      rangesToFilter.push({ begin: callExpr.arguments.pos, end: callExpr.arguments.end })
1712    }
1713
1714    this.filterStrictDiagnostics({
1715        [ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE]: (pos: number) => {
1716          return this.checkInRange([{begin: callExpr.pos, end: callExpr.end}], pos);
1717        },
1718        [NO_OVERLOAD_MATCHES_THIS_CALL_ERROR_CODE]: (pos: number) => {
1719          return this.checkInRange([{begin: callExpr.pos, end: callExpr.end}], pos);
1720        },
1721        [TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE]: (pos: number) => {
1722          return this.checkInRange(rangesToFilter, pos);
1723        }
1724      },
1725      this.libraryTypeCallDiagnosticChecker
1726    );
1727
1728    for (const msgChain of diagnosticMessages) {
1729      TypeScriptLinter.filteredDiagnosticMessages.push(msgChain);
1730    }
1731  }
1732
1733  private handleNewExpression(node: Node): void {
1734    const tsNewExpr = node as NewExpression;
1735    let callSignature = TypeScriptLinter.tsTypeChecker.getResolvedSignature(tsNewExpr);
1736    if (callSignature !== undefined) {
1737      this.handleStructIdentAndUndefinedInArgs(tsNewExpr, callSignature);
1738      this.handleGenericCallWithNoTypeArgs(tsNewExpr, callSignature);
1739    }
1740  }
1741
1742  private handleAsExpression(node: Node): void {
1743    const tsAsExpr = node as AsExpression;
1744    if (tsAsExpr.type.getText() === "const") this.incrementCounters(node, FaultID.ConstAssertion);
1745
1746    const targetType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsAsExpr.type).getNonNullableType();
1747    const exprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsAsExpr.expression).getNonNullableType();
1748    if (needToDeduceStructuralIdentity(exprType, targetType, true)) {
1749      this.incrementCounters(tsAsExpr, FaultID.StructuralIdentity);
1750    }
1751    // check for rule#65:   "number as Number" and "boolean as Boolean" are disabled
1752    if(
1753        (isNumberType(exprType) && targetType.getSymbol()?.getName() === "Number") ||
1754        (isBooleanType(exprType) && targetType.getSymbol()?.getName() === "Boolean")
1755    ) {
1756      this.incrementCounters(node, FaultID.TypeAssertion);
1757    }
1758  }
1759
1760  private handleTypeReference(node: Node): void {
1761    const typeRef = node as TypeReferenceNode;
1762
1763    const isESObject = isEsObjectType(typeRef);
1764    const isPossiblyValidContext = isEsObjectPossiblyAllowed(typeRef);
1765    if (isESObject && !isPossiblyValidContext) {
1766      this.incrementCounters(node, FaultID.EsObjectType);
1767      return;
1768    }
1769    const typeName = entityNameToString(typeRef.typeName);
1770    const isStdUtilityType = LIMITED_STANDARD_UTILITY_TYPES.includes(typeName);
1771    if (isStdUtilityType) {
1772      this.incrementCounters(node, FaultID.UtilityType);
1773      return;
1774    }
1775
1776    // Using Partial<T> type is allowed only when its argument type is either Class or Interface.
1777    const isStdPartial = entityNameToString(typeRef.typeName) === 'Partial';
1778    const hasSingleTypeArgument = !!typeRef.typeArguments && typeRef.typeArguments.length === 1;
1779    const firstTypeArg = !!typeRef.typeArguments && hasSingleTypeArgument && typeRef.typeArguments[0];
1780    const argType = firstTypeArg && TypeScriptLinter.tsTypeChecker.getTypeFromTypeNode(firstTypeArg);
1781    if (isStdPartial && argType && !argType.isClassOrInterface()) {
1782      this.incrementCounters(node, FaultID.UtilityType);
1783      return;
1784    }
1785  }
1786
1787  private handleMetaProperty(node: Node): void {
1788    const tsMetaProperty = node as MetaProperty;
1789    if (tsMetaProperty.name.text === "target") {
1790      this.incrementCounters(node, FaultID.NewTarget);
1791    }
1792  }
1793
1794  private handleStructDeclaration(node: Node): void {
1795    node.forEachChild(child => {
1796      // Skip synthetic constructor in Struct declaration.
1797      if (!isConstructorDeclaration(child)) this.visitTSNode(child);
1798    });
1799  }
1800
1801  private handleSpreadOp(node: Node) {
1802    // spread assignment is disabled
1803    // spread element is allowed only for arrays as rest parameter
1804    if (isSpreadElement(node)) {
1805      const spreadElemNode = node;
1806      const spreadExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(spreadElemNode.expression);
1807      if (spreadExprType) {
1808        const spreadExprTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(spreadExprType, undefined, NodeBuilderFlags.None);
1809        if (spreadExprTypeNode !== undefined &&
1810              (isCallLikeExpression(node.parent) || isArrayLiteralExpression(node.parent))) {
1811          if (isArrayTypeNode(spreadExprTypeNode) ||
1812              isTypedArray(spreadExprTypeNode) ||
1813              isDerivedFrom(spreadExprType, CheckType.Array)) {
1814            return;
1815          }
1816        }
1817      }
1818    }
1819    this.incrementCounters(node, FaultID.SpreadOperator);
1820  }
1821
1822  private handleConstructSignature(node: Node) {
1823    switch (node.parent.kind) {
1824      case SyntaxKind.TypeLiteral:
1825        this.incrementCounters(node, FaultID.ConstructorType);
1826        break;
1827      case SyntaxKind.InterfaceDeclaration:
1828        this.incrementCounters(node, FaultID.ConstructorIface);
1829        break;
1830      default:
1831        return;
1832    }
1833  }
1834
1835  private handleComments(node: Node) {
1836    // Note: Same comment may be owned by several nodes if their
1837    // start/end position matches. Thus, look for the most parental
1838    // owner of the specific comment (by the node's position).
1839    const srcText = node.getSourceFile().getFullText();
1840
1841    const parent = node.parent;
1842    if (!parent || parent.getFullStart() !== node.getFullStart()) {
1843      const leadingComments = getLeadingCommentRanges(srcText, node.getFullStart());
1844      if (leadingComments) {
1845        for (const comment of leadingComments) {
1846          this.checkErrorSuppressingAnnotation(comment, srcText);
1847        }
1848      }
1849    }
1850
1851    if (!parent || parent.getEnd() !== node.getEnd()) {
1852      const trailingComments = getTrailingCommentRanges(srcText, node.getEnd());
1853      if (trailingComments) {
1854        for (const comment of trailingComments) {
1855          this.checkErrorSuppressingAnnotation(comment, srcText);
1856        }
1857      }
1858    }
1859  }
1860
1861  private handleExpressionWithTypeArguments(node: Node) {
1862    const tsTypeExpr = node as ExpressionWithTypeArguments;
1863    const symbol = trueSymbolAtLocation(tsTypeExpr.expression);
1864    if (!!symbol && isEsObjectSymbol(symbol)) {
1865      this.incrementCounters(tsTypeExpr, FaultID.EsObjectType);
1866    }
1867  }
1868
1869  private handleComputedPropertyName(node: Node) {
1870    const computedProperty = node as ComputedPropertyName;
1871    const symbol = trueSymbolAtLocation(computedProperty.expression);
1872    if (!!symbol && isSymbolIterator(symbol)) {
1873      return;
1874    }
1875    this.incrementCounters(node, FaultID.ComputedPropertyName);
1876  }
1877
1878  private checkErrorSuppressingAnnotation(comment: CommentRange, srcText: string) {
1879    const commentContent = comment.kind === SyntaxKind.MultiLineCommentTrivia
1880      ? srcText.slice(comment.pos + 2, comment.end - 2)
1881      : srcText.slice(comment.pos + 2, comment.end);
1882    // if comment is multiline end closing '*/' is not at the same line as '@ts-xxx' - do nothing (#13851)
1883    if (commentContent.endsWith('\n')) {
1884      return
1885    }
1886    const trimmedContent = commentContent.trim();
1887    if (trimmedContent.startsWith("@ts-ignore") ||
1888        trimmedContent.startsWith("@ts-nocheck") ||
1889        trimmedContent.startsWith("@ts-expect-error")) {
1890      this.incrementCounters(comment, FaultID.ErrorSuppression);
1891    }
1892  }
1893
1894  private handleDecorators(decorators: readonly Decorator[] | undefined): void {
1895    if (!decorators) return;
1896
1897    for (const decorator of decorators) {
1898      let decoratorName = "";
1899      if (isIdentifier(decorator.expression)) {
1900        decoratorName = decorator.expression.text;
1901      }
1902      else if (isCallExpression(decorator.expression) && isIdentifier(decorator.expression.expression)) {
1903        decoratorName = decorator.expression.expression.text;
1904      }
1905      if (!ARKUI_DECORATORS.includes(decoratorName)) {
1906        this.incrementCounters(decorator, FaultID.UnsupportedDecorators);
1907      }
1908    }
1909  }
1910
1911  private handleGetAccessor(node: Node) {
1912    this.handleDecorators(getDecorators(node as GetAccessorDeclaration));
1913  }
1914
1915  private handleSetAccessor(node: Node) {
1916    this.handleDecorators(getDecorators(node as SetAccessorDeclaration));
1917  }
1918
1919  private handleDeclarationInferredType(
1920    decl: VariableDeclaration | PropertyDeclaration | ParameterDeclaration
1921    ) {
1922    // The type is explicitly specified, no need to check inferred type.
1923    if (decl.type) return;
1924
1925    // issue 13161:
1926    // In TypeScript, the catch clause variable must be 'any' or 'unknown' type. Since
1927    // ArkTS doesn't support these types, the type for such variable is simply omitted,
1928    // and we don't report it as an error.
1929    if (isCatchClause(decl.parent)) return;
1930
1931    //Destructuring declarations are not supported, do not process them.
1932    if (isArrayBindingPattern(decl.name) || isObjectBindingPattern(decl.name)) return;
1933
1934    const type = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(decl);
1935    if (type) this.validateDeclInferredType(type, decl);
1936  }
1937
1938  private handleDefiniteAssignmentAssertion(decl: VariableDeclaration | PropertyDeclaration) {
1939    if (decl.exclamationToken !== undefined) {
1940      this.incrementCounters(decl, FaultID.DefiniteAssignment);
1941    }
1942  }
1943
1944  private validatedTypesSet = new Set<Type>();
1945
1946private checkAnyOrUnknownChildNode(node: Node): boolean {
1947  if (node.kind === SyntaxKind.AnyKeyword ||
1948      node.kind === SyntaxKind.UnknownKeyword) {
1949    return true;
1950  }
1951  const isAnyOrUnknown = forEachChild(node, (child) => {
1952    if (this.checkAnyOrUnknownChildNode(child)) {
1953      return true;
1954    }
1955    return undefined;
1956  });
1957  return !!isAnyOrUnknown;
1958}
1959
1960  private handleInferredObjectreference(
1961    type: Type,
1962    decl: VariableDeclaration | PropertyDeclaration | ParameterDeclaration
1963    ) {
1964    const typeArgs = TypeScriptLinter.tsTypeChecker.getTypeArguments(type as TypeReference);
1965    if (typeArgs) {
1966      const haveAnyOrUnknownNodes = this.checkAnyOrUnknownChildNode(decl);
1967      if (!haveAnyOrUnknownNodes) {
1968        for (const typeArg of typeArgs) {
1969          this.validateDeclInferredType(typeArg, decl);
1970        }
1971      }
1972    }
1973  }
1974
1975  private validateDeclInferredType(
1976    type: Type,
1977    decl: VariableDeclaration | PropertyDeclaration | ParameterDeclaration
1978    ): void {
1979    if (type.aliasSymbol !== undefined) {
1980      return;
1981    }
1982    const isObject = type.flags & TypeFlags.Object;
1983    const isReference = (type as ObjectType).objectFlags & ObjectFlags.Reference;
1984    if (isObject && isReference) {
1985      this.handleInferredObjectreference(type, decl);
1986      return;
1987    }
1988    if (this.validatedTypesSet.has(type)) {
1989      return;
1990    }
1991    if (type.isUnion()) {
1992      this.validatedTypesSet.add(type);
1993      for (let unionElem of type.types) {
1994        this.validateDeclInferredType(unionElem, decl);
1995      }
1996    }
1997
1998    if (isAnyType(type)) {
1999      this.incrementCounters(decl, FaultID.AnyType);
2000    }
2001    else if (isUnknownType(type)) {
2002      this.incrementCounters(decl, FaultID.UnknownType);
2003    }
2004  }
2005
2006  private handleClassStaticBlockDeclaration(node: Node): void {
2007    if (this.skipArkTSStaticBlocksCheck) {
2008      return;
2009    }
2010    const classStaticBlockDecl = node as ClassStaticBlockDeclaration;
2011    if (!isClassDeclaration(classStaticBlockDecl.parent)) {
2012      return;
2013    }
2014    if (this.functionContainsThis(node)) {
2015      this.incrementCounters(node, FaultID.FunctionContainsThis);
2016    }
2017  }
2018
2019  public lint(): void {
2020    this.visitTSNode(this.sourceFile);
2021  }
2022
2023}