• 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 {
16    ArrayLiteralExpression, AsExpression, BinaryExpression, BinaryOperatorToken, CallExpression, canHaveModifiers,
17    CatchClause, ClassDeclaration, CommentRange, ComputedPropertyName, ConditionalExpression, ConstructorDeclaration,
18    Declaration, Decorator, Diagnostic, ElementAccessExpression, EntityName, EnumMember, ESMap, Expression,
19    ExpressionWithTypeArguments, Extension, flattenDiagnosticMessageText, ForInStatement, FunctionDeclaration,
20    FunctionExpression, getAllDecorators, getAnyExtensionFromPath, getBaseFileName, getCombinedNodeFlags, getDecorators,
21    getLineAndCharacterOfPosition, getModifiers, getPathComponents, HasDecorators, hasIndexSignature, HasModifiers,
22    Identifier, idText, IfStatement, ImportSpecifier, IndexSignatureDeclaration, isArrayLiteralExpression,
23    isArrayTypeNode, isArrowFunction, isAsExpression, isBinaryExpression, isBlock, isCallExpression,
24    isCallLikeExpression, isClassDeclaration, isComputedPropertyName, isConstructorDeclaration, isEnumDeclaration,
25    isExportAssignment, isExportDeclaration, isExpressionStatement, isForInStatement, isForOfStatement, isForStatement,
26    isFunctionDeclaration, isFunctionExpression, isFunctionTypeNode, isGetAccessorDeclaration, isIdentifier,
27    isImportDeclaration, isInterfaceDeclaration, isIntersectionTypeNode, isLiteralTypeNode, isMemberName,
28    isMethodDeclaration, isModuleBlock, isNamedExports, isNamedTupleMember, isNumericLiteral, isObjectLiteralExpression,
29    isParenthesizedExpression, isParenthesizedTypeNode, isPropertyAccessExpression, isPropertyAssignment,
30    isPropertyDeclaration, isPropertySignature, isSetAccessorDeclaration, isSourceFile, isStringLiteral, isStringLiteralLike, isTupleTypeNode,
31    isTypeAliasDeclaration, isTypeLiteralNode, isTypeNode, isTypeQueryNode, isTypeReferenceNode, isUnionTypeNode,
32    isVariableDeclaration, isVariableDeclarationList, isVariableStatement, Map, MethodDeclaration, Modifier,
33    NamedDeclaration, Node, NodeArray, NodeBuilderFlags, NodeFlags, normalizePath, NumericLiteral, ObjectFlags, ObjectLiteralExpression, ObjectType,
34    PrefixUnaryExpression, PrefixUnaryOperator, PropertyAccessExpression, PropertyAssignment, PropertyDeclaration,
35    ResolvedModuleFull, ScriptKind, Set, SourceFile, Statement, Symbol, SymbolFlags, symbolName, SyntaxKind, Type,
36    TypeAliasDeclaration, TypeAssertion, TypeChecker, TypeFlags, TypeNode, TypeReference, UnionType,
37    WithStatement,
38} from "../_namespaces/ts";
39import { AutofixInfo, FaultID, ProblemInfo } from "../_namespaces/ts.ArkTSLinter_1_1";
40
41//import * as path from 'node:path';
42//import * as ts from 'typescript';
43//import ProblemInfo = ts.ProblemInfo;
44//import TypeScriptLinter = TypeScriptLinter;
45
46export const PROPERTY_HAS_NO_INITIALIZER_ERROR_CODE = 2564;
47
48export const NON_INITIALIZABLE_PROPERTY_DECORATORS = ['Link', 'Consume', 'ObjectLink', 'Prop', 'BuilderParam', 'Param', 'Event', 'Require'];
49
50export const NON_INITIALIZABLE_PROPERTY_CLASS_DECORATORS = ['CustomDialog']
51
52export const LIMITED_STANDARD_UTILITY_TYPES = [
53  "Awaited", "Pick", "Omit", "Exclude", "Extract", "NonNullable", "Parameters",
54  "ConstructorParameters", "ReturnType", "InstanceType", "ThisParameterType", "OmitThisParameter",
55  "ThisType", "Uppercase", "Lowercase", "Capitalize", "Uncapitalize",
56];
57
58export const ALLOWED_STD_SYMBOL_API = ["iterator"]
59
60export const ARKTS_IGNORE_DIRS = ['node_modules', 'oh_modules', 'build', '.preview'];
61export const ARKTS_IGNORE_FILES = ['hvigorfile.ts'];
62
63export const ARKTS_IGNORE_DIRS_OH_MODULES = 'oh_modules';
64
65export const SENDABLE_DECORATOR = 'Sendable';
66
67export const SENDABLE_INTERFACE = 'ISendable';
68
69export const PROMISE = 'Promise';
70
71export const SENDABLE_DECORATOR_NODES = [
72  SyntaxKind.ClassDeclaration,
73  SyntaxKind.FunctionDeclaration,
74  SyntaxKind.TypeAliasDeclaration
75];
76
77export const SENDABLE_CLOSURE_DECLS = [
78  SyntaxKind.ClassDeclaration,
79  SyntaxKind.FunctionDeclaration
80];
81
82export const ARKTS_COLLECTIONS_D_ETS = '@arkts.collections.d.ets';
83
84export const COLLECTIONS_NAMESPACE = 'collections';
85
86export const ARKTS_LANG_D_ETS = '@arkts.lang.d.ets';
87
88export const LANG_NAMESPACE = 'lang';
89
90export const ISENDABLE_TYPE = 'ISendable';
91
92export const USE_SHARED = 'use shared';
93
94export const D_TS = '.d.ts';
95
96export const TASKPOOL = 'taskpool';
97
98export const TASKGROUP = 'TaskGroup';
99
100export const TASKPOOL_API = ['Task', 'LongTask', 'GenericsTask', 'execute', 'addTask'];
101
102export const TASK_LIST = ['Task', 'LongTask', 'GenericsTask', 'TaskGroup'];
103
104export const CONCURRENT_DECORATOR = 'Concurrent';
105
106export const USE_CONCURRENT = 'use concurrent'
107
108
109let typeChecker: TypeChecker;
110export function setTypeChecker(tsTypeChecker: TypeChecker): void {
111  typeChecker = tsTypeChecker;
112}
113
114export function clearTypeChecker(): void {
115  typeChecker = {} as TypeChecker;
116}
117
118let testMode = false;
119export function setTestMode(tsTestMode: boolean): void {
120  testMode = tsTestMode;
121}
122
123let mixCompile = false;
124export function setMixCompile(isMixCompile: boolean): void {
125  mixCompile = isMixCompile;
126}
127
128export function getStartPos(nodeOrComment: Node | CommentRange): number {
129  return (nodeOrComment.kind === SyntaxKind.SingleLineCommentTrivia || nodeOrComment.kind === SyntaxKind.MultiLineCommentTrivia)
130    ? (nodeOrComment as CommentRange).pos
131    : (nodeOrComment as Node).getStart();
132}
133
134export function getEndPos(nodeOrComment: Node | CommentRange): number {
135  return (nodeOrComment.kind === SyntaxKind.SingleLineCommentTrivia || nodeOrComment.kind === SyntaxKind.MultiLineCommentTrivia)
136    ? (nodeOrComment as CommentRange).end
137    : (nodeOrComment as Node).getEnd();
138}
139
140export function getHighlightRange(nodeOrComment: Node | CommentRange, faultId: number): [number, number] {
141  return (
142    highlightRangeHandlers.get(faultId)?.call(undefined, nodeOrComment) ?? [
143      getStartPos(nodeOrComment),
144      getEndPos(nodeOrComment)
145    ]
146  );
147}
148
149const highlightRangeHandlers = new Map([
150  [FaultID.VarDeclaration, getVarDeclarationHighlightRange],
151  [FaultID.CatchWithUnsupportedType, getCatchWithUnsupportedTypeHighlightRange],
152  [FaultID.ForInStatement, getForInStatementHighlightRange],
153  [FaultID.WithStatement, getWithStatementHighlightRange],
154  [FaultID.DeleteOperator, getDeleteOperatorHighlightRange],
155  [FaultID.TypeQuery, getTypeQueryHighlightRange],
156  [FaultID.InstanceofUnsupported, getInstanceofUnsupportedHighlightRange],
157  [FaultID.ConstAssertion, getConstAssertionHighlightRange],
158  [FaultID.LimitedReturnTypeInference, getLimitedReturnTypeInferenceHighlightRange],
159  [FaultID.LocalFunction, getLocalFunctionHighlightRange],
160  [FaultID.FunctionBind, getFunctionApplyCallHighlightRange],
161  [FaultID.FunctionApplyCall, getFunctionApplyCallHighlightRange],
162  [FaultID.DeclWithDuplicateName, getDeclWithDuplicateNameHighlightRange],
163  [FaultID.ObjectLiteralNoContextType, getObjectLiteralNoContextTypeHighlightRange],
164  [FaultID.ClassExpression, getClassExpressionHighlightRange],
165  [FaultID.MultipleStaticBlocks, getMultipleStaticBlocksHighlightRange],
166  [FaultID.SendableDefiniteAssignment, getSendableDefiniteAssignmentHighlightRange]
167]);
168
169export function getVarDeclarationHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
170  return getKeywordHighlightRange(nodeOrComment, 'var');
171}
172
173export function getCatchWithUnsupportedTypeHighlightRange(
174  nodeOrComment: Node | CommentRange
175): [number, number] | undefined {
176  const catchClauseNode = (nodeOrComment as CatchClause).variableDeclaration;
177  if (catchClauseNode !== undefined) {
178    return [catchClauseNode.getStart(), catchClauseNode.getEnd()];
179  }
180
181  return undefined;
182}
183
184export function getForInStatementHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
185  return [
186    getEndPos((nodeOrComment as ForInStatement).initializer) + 1,
187    getStartPos((nodeOrComment as ForInStatement).expression) - 1
188  ];
189}
190
191export function getWithStatementHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
192  return [getStartPos(nodeOrComment), (nodeOrComment as WithStatement).statement.getStart() - 1];
193}
194
195export function getDeleteOperatorHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
196  return getKeywordHighlightRange(nodeOrComment, 'delete');
197}
198
199export function getTypeQueryHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
200  return getKeywordHighlightRange(nodeOrComment, 'typeof');
201}
202
203export function getInstanceofUnsupportedHighlightRange(
204  nodeOrComment: Node | CommentRange
205): [number, number] | undefined {
206  return getKeywordHighlightRange((nodeOrComment as BinaryExpression).operatorToken, 'instanceof');
207}
208
209export function getConstAssertionHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
210  if (nodeOrComment.kind === SyntaxKind.AsExpression) {
211    return [
212      (nodeOrComment as AsExpression).expression.getEnd() + 1,
213      (nodeOrComment as AsExpression).type.getStart() - 1
214    ];
215  }
216  return [
217    (nodeOrComment as TypeAssertion).expression.getEnd() + 1,
218    (nodeOrComment as TypeAssertion).type.getEnd() + 1
219  ];
220}
221
222export function getLimitedReturnTypeInferenceHighlightRange(
223  nodeOrComment: Node | CommentRange
224): [number, number] | undefined {
225  let node: Node | undefined;
226  if (nodeOrComment.kind === SyntaxKind.FunctionExpression) {
227    // we got error about return type so it should be present
228    node = (nodeOrComment as FunctionExpression).type;
229  } else if (nodeOrComment.kind === SyntaxKind.FunctionDeclaration) {
230    node = (nodeOrComment as FunctionDeclaration).name;
231  } else if (nodeOrComment.kind === SyntaxKind.MethodDeclaration) {
232    node = (nodeOrComment as MethodDeclaration).name;
233  }
234  if (node !== undefined) {
235    return [node.getStart(), node.getEnd()];
236  }
237
238  return undefined;
239}
240
241export function getLocalFunctionHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
242  return getKeywordHighlightRange(nodeOrComment, 'function');
243}
244
245export function getFunctionApplyCallHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
246  const pointPos = (nodeOrComment as Node).getText().lastIndexOf('.');
247  return [getStartPos(nodeOrComment) + pointPos + 1, getEndPos(nodeOrComment)];
248}
249
250export function getDeclWithDuplicateNameHighlightRange(
251  nodeOrComment: Node | CommentRange
252): [number, number] | undefined {
253  // in case of private identifier no range update is needed
254  const nameNode: Node | undefined = (nodeOrComment as NamedDeclaration).name;
255  if (nameNode !== undefined) {
256  return [nameNode.getStart(), nameNode.getEnd()];
257  }
258
259  return undefined;
260}
261
262export function getObjectLiteralNoContextTypeHighlightRange(
263  nodeOrComment: Node | CommentRange
264): [number, number] | undefined {
265  return getKeywordHighlightRange(nodeOrComment, '{');
266}
267
268export function getClassExpressionHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
269  return getKeywordHighlightRange(nodeOrComment, 'class');
270}
271
272export function getMultipleStaticBlocksHighlightRange(nodeOrComment: Node | CommentRange): [number, number] | undefined {
273  return getKeywordHighlightRange(nodeOrComment, 'static');
274}
275
276// highlight ranges for Sendable rules
277export function getSendableDefiniteAssignmentHighlightRange(
278  nodeOrComment: Node | CommentRange
279): [number, number] | undefined {
280  const name = (nodeOrComment as PropertyDeclaration).name;
281  const exclamationToken = (nodeOrComment as PropertyDeclaration).exclamationToken;
282  return [name.getStart(), exclamationToken ? exclamationToken.getEnd() : name.getEnd()];
283}
284
285export function getKeywordHighlightRange(nodeOrComment: Node | CommentRange, keyword: string): [number, number] {
286  const start = getStartPos(nodeOrComment);
287  return [start, start + keyword.length];
288}
289
290export function isAssignmentOperator(tsBinOp: BinaryOperatorToken): boolean {
291  return tsBinOp.kind >= SyntaxKind.FirstAssignment && tsBinOp.kind <= SyntaxKind.LastAssignment;
292}
293
294export function isType(tsType: TypeNode | undefined, checkType: string): boolean {
295  if (tsType === undefined || !isTypeReferenceNode(tsType)) {
296    return false;
297  }
298  return entityNameToString(tsType.typeName) === checkType;
299}
300
301export function entityNameToString(name: EntityName): string {
302  if (isIdentifier(name)) {
303    return name.escapedText.toString();
304  }
305  else {
306    return entityNameToString(name.left) + entityNameToString(name.right);
307  }
308}
309
310export function isNumberLikeType(tsType: Type): boolean {
311  return (tsType.getFlags() & TypeFlags.NumberLike) !== 0;
312}
313
314export function isBooleanLikeType(tsType: Type): boolean {
315  return (tsType.getFlags() & TypeFlags.BooleanLike) !== 0;
316}
317
318export function isStringLikeType(tsType: Type): boolean {
319  if (tsType.isUnion()) {
320    for (const tsCompType of tsType.types) {
321      if ((tsCompType.flags & TypeFlags.StringLike) === 0) return false;
322    }
323    return true;
324  }
325  return (tsType.getFlags() & TypeFlags.StringLike) !== 0;
326}
327
328export function isStringType(tsType: Type): boolean {
329  if ((tsType.getFlags() & TypeFlags.String) !== 0) {
330    return true;
331  }
332
333  if (!isTypeReference(tsType)) {
334    return false;
335  }
336
337  const symbol = tsType.symbol;
338  const name = typeChecker.getFullyQualifiedName(symbol);
339  return name === 'String' && isGlobalSymbol(symbol);
340}
341
342export function isPrimitiveEnumMemberType(type: Type, primitiveType: TypeFlags): boolean {
343  const isNonPrimitive = (type.flags & TypeFlags.NonPrimitive) !== 0;
344  if (!isEnumMemberType(type) || isNonPrimitive) {
345    return false;
346  }
347  return (type.flags & primitiveType) !== 0;
348}
349
350export function unwrapParenthesizedType(tsType: TypeNode): TypeNode {
351  while (isParenthesizedTypeNode(tsType)) {
352    tsType = tsType.type;
353  }
354  return tsType;
355}
356
357export function findParentIf(asExpr: AsExpression): IfStatement | null {
358  let node = asExpr.parent;
359  while (node) {
360    if (node.kind === SyntaxKind.IfStatement) {
361      return node as IfStatement;
362    }
363    node = node.parent;
364  }
365
366  return null;
367}
368
369export function isDestructuringAssignmentLHS(
370  tsExpr: ArrayLiteralExpression | ObjectLiteralExpression
371): boolean {
372  // Check whether given expression is the LHS part of the destructuring
373  // assignment (or is a nested element of destructuring pattern).
374  let tsParent = tsExpr.parent;
375  let tsCurrentExpr: Node = tsExpr;
376  while (tsParent) {
377    if (
378      isBinaryExpression(tsParent) && isAssignmentOperator(tsParent.operatorToken) &&
379      tsParent.left === tsCurrentExpr
380    ) {
381      return true;
382    }
383    if (
384      (isForStatement(tsParent) || isForInStatement(tsParent) || isForOfStatement(tsParent)) &&
385      tsParent.initializer && tsParent.initializer === tsCurrentExpr
386    ) {
387      return true;
388    }
389    tsCurrentExpr = tsParent;
390    tsParent = tsParent.parent;
391  }
392
393  return false;
394}
395
396export function isEnumType(tsType: Type): boolean {
397  // when type equals `typeof <Enum>`, only symbol contains information about it's type.
398  const isEnumSymbol = tsType.symbol && isEnum(tsType.symbol);
399  // otherwise, we should analyze flags of the type itself
400  const isEnumType = !!(tsType.flags & TypeFlags.Enum) || !!(tsType.flags & TypeFlags.EnumLiteral);
401  return isEnumSymbol || isEnumType;
402}
403
404export function isEnum(tsSymbol: Symbol): boolean {
405  return !!(tsSymbol.flags & SymbolFlags.Enum);
406}
407
408export function isEnumMemberType(tsType: Type): boolean {
409  // Note: For some reason, test (tsType.flags & TypeFlags.Enum) != 0 doesn't work here.
410  // Must use SymbolFlags to figure out if this is an enum type.
411  return tsType.symbol && (tsType.symbol.flags & SymbolFlags.EnumMember) !== 0;
412}
413
414export function isObjectLiteralType(tsType: Type): boolean {
415  return tsType.symbol && (tsType.symbol.flags & SymbolFlags.ObjectLiteral) !== 0;
416}
417
418export function hasModifier(tsModifiers: readonly Modifier[] | undefined, tsModifierKind: number): boolean {
419  // Sanity check.
420  if (!tsModifiers) return false;
421
422  for (const tsModifier of tsModifiers) {
423    if (tsModifier.kind === tsModifierKind) return true;
424  }
425
426  return false;
427}
428
429export function unwrapParenthesized(tsExpr: Expression): Expression {
430  let unwrappedExpr = tsExpr;
431  while (isParenthesizedExpression(unwrappedExpr)) {
432    unwrappedExpr = unwrappedExpr.expression;
433  }
434  return unwrappedExpr;
435}
436
437export function followIfAliased(sym: Symbol): Symbol {
438  if ((sym.getFlags() & SymbolFlags.Alias) !== 0) {
439    return typeChecker.getAliasedSymbol(sym);
440  }
441  return sym;
442}
443
444let trueSymbolAtLocationCache = new Map<Node, Symbol | null>();
445
446export function trueSymbolAtLocation(node: Node): Symbol | undefined {
447  let cache = trueSymbolAtLocationCache;
448  let val = cache.get(node);
449  if (val !== undefined) {
450    return val !== null ? val : undefined;
451  }
452  let sym = typeChecker.getSymbolAtLocation(node);
453  if (sym === undefined) {
454    cache.set(node, null);
455    return undefined;
456  }
457  sym = followIfAliased(sym);
458  cache.set(node, sym);
459  return sym;
460}
461
462export function clearTrueSymbolAtLocationCache(): void {
463  trueSymbolAtLocationCache.clear();
464}
465
466export function isTypeDeclSyntaxKind(kind: SyntaxKind) {
467  return isStructDeclarationKind(kind) ||
468    kind === SyntaxKind.EnumDeclaration ||
469    kind === SyntaxKind.ClassDeclaration ||
470    kind === SyntaxKind.InterfaceDeclaration ||
471    kind === SyntaxKind.TypeAliasDeclaration;
472}
473
474export function symbolHasDuplicateName(symbol: Symbol, tsDeclKind: SyntaxKind): boolean {
475  // Type Checker merges all declarations with the same name in one scope into one symbol.
476  // Thus, check whether the symbol of certain declaration has any declaration with
477  // different syntax kind.
478  const symbolDecls = symbol?.getDeclarations();
479  if (symbolDecls) {
480    for (const symDecl of symbolDecls) {
481      const declKind = symDecl.kind;
482      // we relax arkts-unique-names for namespace collision with class/interface/enum/type/struct
483      const isNamespaceTypeCollision =
484        (isTypeDeclSyntaxKind(declKind) && tsDeclKind === SyntaxKind.ModuleDeclaration) ||
485        (isTypeDeclSyntaxKind(tsDeclKind) && declKind === SyntaxKind.ModuleDeclaration);
486
487      // Don't count declarations with 'Identifier' syntax kind as those
488      // usually depict declaring an object's property through assignment.
489      if (declKind !== SyntaxKind.Identifier && declKind !== tsDeclKind && !isNamespaceTypeCollision) return true;
490    }
491  }
492
493  return false;
494}
495
496export function isReferenceType(tsType: Type): boolean {
497  const f = tsType.getFlags();
498  return (
499    (f & TypeFlags.InstantiableNonPrimitive) !== 0 || (f & TypeFlags.Object) !== 0 ||
500    (f & TypeFlags.Boolean) !== 0 || (f & TypeFlags.Enum) !== 0 || (f & TypeFlags.NonPrimitive) !== 0 ||
501    (f & TypeFlags.Number) !== 0 || (f & TypeFlags.String) !== 0
502  );
503}
504
505export function isPrimitiveType(type: Type): boolean {
506  const f = type.getFlags();
507  return (
508    (f & TypeFlags.Boolean) !== 0 || (f & TypeFlags.BooleanLiteral) !== 0 ||
509    (f & TypeFlags.Number) !== 0 || (f & TypeFlags.NumberLiteral) !== 0
510    // In ArkTS 'string' is not a primitive type. So for the common subset 'string'
511    // should be considered as a reference type. That is why next line is commented out.
512    //(f & TypeFlags.String) != 0 || (f & TypeFlags.StringLiteral) != 0
513  );
514}
515
516export function isPrimitiveLiteralType(type: Type): boolean {
517  return !!(
518    type.flags &
519    (TypeFlags.BooleanLiteral |
520      TypeFlags.NumberLiteral |
521      TypeFlags.StringLiteral |
522      TypeFlags.BigIntLiteral)
523  );
524}
525
526export function isPurePrimitiveLiteralType(type: Type): boolean {
527  return isPrimitiveLiteralType(type) && !(type.flags & TypeFlags.EnumLiteral);
528}
529
530export function isTypeSymbol(symbol: Symbol | undefined): boolean {
531  return (
532    !!symbol && !!symbol.flags &&
533    ((symbol.flags & SymbolFlags.Class) !== 0 || (symbol.flags & SymbolFlags.Interface) !== 0)
534  );
535}
536
537// Check whether type is generic 'Array<T>' type defined in TypeScript standard library.
538export function isGenericArrayType(tsType: Type): tsType is TypeReference {
539  return (
540    isTypeReference(tsType) && tsType.typeArguments?.length === 1 && tsType.target.typeParameters?.length === 1 &&
541    tsType.getSymbol()?.getName() === 'Array'
542  );
543}
544
545export function isReadonlyArrayType(tsType: Type): boolean {
546  return (
547    isTypeReference(tsType) && tsType.typeArguments?.length === 1 && tsType.target.typeParameters?.length === 1 &&
548    (tsType.getSymbol()?.getName() === 'ReadonlyArray')
549  );
550}
551
552export function isConcatArrayType(tsType: Type): boolean {
553  return (
554    isStdLibraryType(tsType) &&
555    isTypeReference(tsType) &&
556    tsType.typeArguments?.length === 1 &&
557    tsType.target.typeParameters?.length === 1 &&
558    (tsType.getSymbol()?.getName() === 'ConcatArray')
559  );
560}
561
562export function isArrayLikeType(tsType: Type): boolean {
563  return (
564    isStdLibraryType(tsType) &&
565    isTypeReference(tsType) &&
566    tsType.typeArguments?.length === 1 &&
567    tsType.target.typeParameters?.length === 1 &&
568    (tsType.getSymbol()?.getName() === 'ArrayLike')
569  );
570}
571
572export function isTypedArray(tsType: Type, allowTypeArrays: string[]): boolean {
573  const symbol = tsType.symbol;
574  if (!symbol) {
575    return false;
576  }
577  const name = typeChecker.getFullyQualifiedName(symbol);
578  if (isGlobalSymbol(symbol) && allowTypeArrays.includes(name)) {
579    return true;
580  }
581  const decl = getDeclaration(symbol);
582  return (
583    !!decl &&
584    isArkTSCollectionsClassOrInterfaceDeclaration(decl) &&
585    allowTypeArrays.includes(symbol.getName())
586  );
587}
588
589export function isArray(tsType: Type): boolean {
590    return isGenericArrayType(tsType) || isReadonlyArrayType(tsType) || isTypedArray(tsType, TYPED_ARRAYS);
591}
592
593export function isCollectionArrayType(tsType: Type): boolean {
594  return isTypedArray(tsType, TYPED_COLLECTIONS);
595}
596
597export function isIndexableArray(tsType: Type): boolean {
598  return (
599    isGenericArrayType(tsType) ||
600    isReadonlyArrayType(tsType) ||
601    isConcatArrayType(tsType) ||
602    isArrayLikeType(tsType) ||
603    isTypedArray(tsType, TYPED_ARRAYS) ||
604    isTypedArray(tsType, TYPED_COLLECTIONS)
605  );
606}
607
608export function isTuple(tsType: Type): boolean {
609  return isTypeReference(tsType) && !!(tsType.objectFlags & ObjectFlags.Tuple);
610}
611
612// does something similar to relatedByInheritanceOrIdentical function
613export function isOrDerivedFrom(tsType: Type, checkType: CheckType, checkedBaseTypes?: Set<Type>): boolean {
614  if (isTypeReference(tsType) && tsType.target !== tsType) {
615    tsType = tsType.target;
616  }
617  if (checkType(tsType)) {
618    return true;
619  }
620  if (!tsType.symbol || !tsType.symbol.declarations) {
621    return false;
622  }
623
624  // Avoid type recursion in heritage by caching checked types.
625  (checkedBaseTypes ||= new Set<Type>()).add(tsType);
626
627  for (const tsTypeDecl of tsType.symbol.declarations) {
628    const isClassOrInterfaceDecl = isClassDeclaration(tsTypeDecl) || isInterfaceDeclaration(tsTypeDecl);
629    const isDerived = isClassOrInterfaceDecl && !!tsTypeDecl.heritageClauses;
630    if (!isDerived) {
631      continue;
632    }
633    for (const heritageClause of tsTypeDecl.heritageClauses) {
634      if (processParentTypesCheck(heritageClause.types, checkType, checkedBaseTypes)) {
635        return true;
636      }
637    }
638  }
639
640  return false;
641}
642
643export function isTypeReference(tsType: Type): tsType is TypeReference {
644  return (
645    (tsType.getFlags() & TypeFlags.Object) !== 0 &&
646    ((tsType as ObjectType).objectFlags & ObjectFlags.Reference) !== 0
647  );
648}
649
650export function isNullType(tsTypeNode: TypeNode): boolean {
651  return (isLiteralTypeNode(tsTypeNode) && tsTypeNode.literal.kind === SyntaxKind.NullKeyword);
652}
653
654export function isThisOrSuperExpr(tsExpr: Expression): boolean {
655  return (tsExpr.kind === SyntaxKind.ThisKeyword || tsExpr.kind === SyntaxKind.SuperKeyword);
656}
657
658export function isPrototypeSymbol(symbol: Symbol | undefined): boolean {
659  return (!!symbol && !!symbol.flags && (symbol.flags & SymbolFlags.Prototype) !== 0);
660}
661
662export function isFunctionSymbol(symbol: Symbol | undefined): boolean {
663  return (!!symbol && !!symbol.flags && (symbol.flags & SymbolFlags.Function) !== 0);
664}
665
666export function isInterfaceType(tsType: Type | undefined): boolean {
667  return (
668    !!tsType && !!tsType.symbol && !!tsType.symbol.flags &&
669    (tsType.symbol.flags & SymbolFlags.Interface) !== 0
670  );
671}
672
673export function isAnyType(tsType: Type): tsType is TypeReference {
674  return (tsType.getFlags() & TypeFlags.Any) !== 0;
675}
676
677export function isUnknownType(tsType: Type): boolean {
678  return (tsType.getFlags() & TypeFlags.Unknown) !== 0;
679}
680
681export function isUnsupportedType(tsType: Type): boolean {
682  return (
683    !!tsType.flags && ((tsType.flags & TypeFlags.Any) !== 0 || (tsType.flags & TypeFlags.Unknown) !== 0 ||
684    (tsType.flags & TypeFlags.Intersection) !== 0)
685  );
686}
687
688export function isUnsupportedUnionType(tsType: Type): boolean {
689  if (tsType.isUnion()) {
690    return !isNullableUnionType(tsType) && !isBooleanUnionType(tsType);
691  }
692  return false;
693}
694
695function isNullableUnionType(tsUnionType: UnionType): boolean {
696  for (const t of tsUnionType.types) {
697    if (!!(t.flags & TypeFlags.Undefined) || !!(t.flags & TypeFlags.Null)) {
698      return true;
699    }
700  }
701  return false;
702}
703
704function isBooleanUnionType(tsUnionType: UnionType): boolean {
705  // For some reason, 'boolean' type is also represented as as union
706  // of 'true' and 'false' literal types. This form of 'union' type
707  // should be considered as supported.
708  const tsCompTypes = tsUnionType.types;
709  return (
710    tsUnionType.flags === (TypeFlags.Boolean | TypeFlags.Union) && tsCompTypes.length === 2 &&
711    tsCompTypes[0].flags === TypeFlags.BooleanLiteral && (tsCompTypes[1].flags === TypeFlags.BooleanLiteral)
712  );
713}
714
715export function isFunctionOrMethod(tsSymbol: Symbol | undefined): boolean {
716  return (
717    !!tsSymbol &&
718    ((tsSymbol.flags & SymbolFlags.Function) !== 0 || (tsSymbol.flags & SymbolFlags.Method) !== 0)
719  );
720}
721
722export function isMethodAssignment(tsSymbol: Symbol | undefined): boolean {
723  return (
724    !!tsSymbol &&
725    ((tsSymbol.flags & SymbolFlags.Method) !== 0 && (tsSymbol.flags & SymbolFlags.Assignment) !== 0)
726  );
727}
728
729export function getDeclaration(tsSymbol: Symbol | undefined): Declaration | undefined {
730  if (tsSymbol && tsSymbol.declarations && tsSymbol.declarations.length > 0) {
731    return tsSymbol.declarations[0];
732  }
733  return undefined;
734}
735
736function isVarDeclaration(tsDecl: Node): boolean {
737  return isVariableDeclaration(tsDecl) && isVariableDeclarationList(tsDecl.parent);
738}
739
740export function isValidEnumMemberInit(tsExpr: Expression): boolean {
741  if (isNumberConstantValue(tsExpr.parent as EnumMember)) {
742    return true;
743  }
744  if (isStringConstantValue(tsExpr.parent as EnumMember)) {
745    return true;
746  }
747  return isCompileTimeExpression(tsExpr);
748}
749
750export function isCompileTimeExpression(tsExpr: Expression): boolean {
751  if (
752    isParenthesizedExpression(tsExpr) ||
753    (isAsExpression(tsExpr) && tsExpr.type.kind === SyntaxKind.NumberKeyword)) {
754    return isCompileTimeExpression(tsExpr.expression);
755  }
756  switch (tsExpr.kind) {
757    case SyntaxKind.PrefixUnaryExpression:
758      return isPrefixUnaryExprValidEnumMemberInit(tsExpr as PrefixUnaryExpression);
759    case SyntaxKind.ParenthesizedExpression:
760    case SyntaxKind.BinaryExpression:
761      return isBinaryExprValidEnumMemberInit(tsExpr as BinaryExpression);
762    case SyntaxKind.ConditionalExpression:
763      return isConditionalExprValidEnumMemberInit(tsExpr as ConditionalExpression);
764    case SyntaxKind.Identifier:
765      return isIdentifierValidEnumMemberInit(tsExpr as Identifier);
766    case SyntaxKind.NumericLiteral:
767      return true;
768    case SyntaxKind.StringLiteral:
769        return true;
770    case SyntaxKind.PropertyAccessExpression: {
771      // if enum member is in current enum declaration try to get value
772      // if it comes from another enum consider as constant
773      const propertyAccess = tsExpr as PropertyAccessExpression;
774      if(isNumberConstantValue(propertyAccess)) {
775        return true;
776      }
777      const leftHandSymbol = typeChecker.getSymbolAtLocation(propertyAccess.expression);
778      if(!leftHandSymbol) {
779        return false;
780      }
781      const decls = leftHandSymbol.getDeclarations();
782      if (!decls || decls.length !== 1) {
783        return false;
784      }
785      return isEnumDeclaration(decls[0]);
786    }
787    default:
788      return false;
789  }
790}
791
792function isPrefixUnaryExprValidEnumMemberInit(tsExpr: PrefixUnaryExpression): boolean {
793  return (isUnaryOpAllowedForEnumMemberInit(tsExpr.operator) && isCompileTimeExpression(tsExpr.operand));
794}
795
796function isBinaryExprValidEnumMemberInit(tsExpr: BinaryExpression): boolean {
797  return (
798    isBinaryOpAllowedForEnumMemberInit(tsExpr.operatorToken) && isCompileTimeExpression(tsExpr.left) &&
799    isCompileTimeExpression(tsExpr.right)
800  );
801}
802
803function isConditionalExprValidEnumMemberInit(tsExpr: ConditionalExpression): boolean {
804  return (isCompileTimeExpression(tsExpr.whenTrue) && isCompileTimeExpression(tsExpr.whenFalse));
805}
806
807function isIdentifierValidEnumMemberInit(tsExpr: Identifier): boolean {
808  const tsSymbol = typeChecker.getSymbolAtLocation(tsExpr);
809  const tsDecl = getDeclaration(tsSymbol);
810  return (!!tsDecl &&
811    ((isVarDeclaration(tsDecl) && isConst(tsDecl.parent)) ||
812      (tsDecl.kind === SyntaxKind.EnumMember)
813    )
814  );
815}
816
817function isUnaryOpAllowedForEnumMemberInit(tsPrefixUnaryOp: PrefixUnaryOperator): boolean {
818  return (
819    tsPrefixUnaryOp === SyntaxKind.PlusToken || tsPrefixUnaryOp === SyntaxKind.MinusToken ||
820    tsPrefixUnaryOp === SyntaxKind.TildeToken
821  );
822}
823
824function isBinaryOpAllowedForEnumMemberInit(tsBinaryOp: BinaryOperatorToken): boolean {
825  return (
826    tsBinaryOp.kind === SyntaxKind.AsteriskToken || tsBinaryOp.kind === SyntaxKind.SlashToken ||
827    tsBinaryOp.kind === SyntaxKind.PercentToken || tsBinaryOp.kind === SyntaxKind.MinusToken ||
828    tsBinaryOp.kind === SyntaxKind.PlusToken || tsBinaryOp.kind === SyntaxKind.LessThanLessThanToken ||
829    tsBinaryOp.kind === SyntaxKind.GreaterThanGreaterThanToken || tsBinaryOp.kind === SyntaxKind.BarBarToken ||
830    tsBinaryOp.kind === SyntaxKind.GreaterThanGreaterThanGreaterThanToken ||
831    tsBinaryOp.kind === SyntaxKind.AmpersandToken || tsBinaryOp.kind === SyntaxKind.CaretToken ||
832    tsBinaryOp.kind === SyntaxKind.BarToken || tsBinaryOp.kind === SyntaxKind.AmpersandAmpersandToken
833  );
834}
835
836export function isConst(tsNode: Node): boolean {
837  return !!(getCombinedNodeFlags(tsNode) & NodeFlags.Const);
838}
839
840export function isNumberConstantValue(
841  tsExpr: EnumMember | PropertyAccessExpression | ElementAccessExpression | NumericLiteral
842): boolean {
843
844  const tsConstValue = (tsExpr.kind === SyntaxKind.NumericLiteral) ?
845  Number(tsExpr.getText()) :
846  typeChecker.getConstantValue(tsExpr);
847
848  return tsConstValue !== undefined && typeof tsConstValue === 'number';
849}
850
851export function isIntegerConstantValue(
852  tsExpr: EnumMember | PropertyAccessExpression | ElementAccessExpression | NumericLiteral
853): boolean {
854
855  const tsConstValue = (tsExpr.kind === SyntaxKind.NumericLiteral) ?
856  Number(tsExpr.getText()) :
857  typeChecker.getConstantValue(tsExpr);
858  return (
859    tsConstValue !== undefined && typeof tsConstValue === 'number' &&
860    tsConstValue.toFixed(0) === tsConstValue.toString()
861  );
862}
863
864export function isStringConstantValue(
865  tsExpr: EnumMember | PropertyAccessExpression | ElementAccessExpression
866): boolean {
867  const tsConstValue = typeChecker.getConstantValue(tsExpr);
868  return (
869    tsConstValue !== undefined && typeof tsConstValue === 'string'
870  );
871}
872
873// Returns true if typeA is a subtype of typeB
874export function relatedByInheritanceOrIdentical(typeA: Type, typeB: Type): boolean {
875  if (isTypeReference(typeA) && typeA.target !== typeA) { typeA = typeA.target; }
876  if (isTypeReference(typeB) && typeB.target !== typeB) { typeB = typeB.target; }
877
878  if (typeA === typeB || isObject(typeB)) { return true; }
879  if (!typeA.symbol || !typeA.symbol.declarations) { return false; }
880
881  const isBISendable = isISendableInterface(typeB);
882  for (const typeADecl of typeA.symbol.declarations) {
883    if (isBISendable && isClassDeclaration(typeADecl) && hasSendableDecorator(typeADecl)) {
884      return true;
885    }
886    if (
887      (!isClassDeclaration(typeADecl) && !isInterfaceDeclaration(typeADecl)) ||
888      !typeADecl.heritageClauses
889    ) { continue; }
890    for (const heritageClause of typeADecl.heritageClauses) {
891      const processInterfaces = typeA.isClass() ? (heritageClause.token !== SyntaxKind.ExtendsKeyword) : true;
892      if (processParentTypes(heritageClause.types, typeB, processInterfaces)) return true;
893    }
894  }
895
896  return false;
897}
898
899export function reduceReference(t: Type): Type {
900  return isTypeReference(t) && t.target !== t ? t.target : t;
901}
902
903function needToDeduceStructuralIdentityHandleUnions(
904  lhsType: Type,
905  rhsType: Type,
906  rhsExpr: Expression,
907  isStrict: boolean
908): boolean {
909  if (rhsType.isUnion()) {
910    // Each Class/Interface of the RHS union type must be compatible with LHS type.
911    for (const compType of rhsType.types) {
912      if (needToDeduceStructuralIdentity(lhsType, compType, rhsExpr, isStrict)) {
913        return true;
914      }
915    }
916    return false;
917  }
918
919  if (lhsType.isUnion()) {
920    // RHS type needs to be compatible with at least one type of the LHS union.
921    for (const compType of lhsType.types) {
922      if (!needToDeduceStructuralIdentity(compType, rhsType, rhsExpr, isStrict)) {
923        return false;
924      }
925    }
926    return true;
927  }
928  // should be unreachable
929  return false;
930}
931
932// return true if two class types are not related by inheritance and structural identity check is needed
933export function needToDeduceStructuralIdentity(
934  lhsType: Type,
935  rhsType: Type,
936  rhsExpr: Expression,
937  isStrict: boolean = false
938): boolean {
939  lhsType = getNonNullableType(lhsType);
940  rhsType = getNonNullableType(rhsType);
941  if (isLibraryType(lhsType)) {
942    return false;
943  }
944  if (isDynamicObjectAssignedToStdType(lhsType, rhsExpr)) {
945    return false;
946  }
947  // #14569: Check for Function type.
948  if (areCompatibleFunctionals(lhsType, rhsType)) {
949    return false;
950  }
951  if (rhsType.isUnion() || lhsType.isUnion()) {
952    return needToDeduceStructuralIdentityHandleUnions(lhsType, rhsType, rhsExpr, isStrict);
953  }
954  // if isStrict, things like generics need to be checked
955  if (isStrict) {
956    if (isTypeReference(rhsType) && !!(rhsType.objectFlags & ObjectFlags.ArrayLiteral)) {
957      // The 'arkts-sendable-obj-init' rule already exists. Wait for the new 'strict type' to be modified.
958      return false;
959    }
960    lhsType = reduceReference(lhsType);
961    rhsType = reduceReference(rhsType);
962  }
963  return lhsType.isClassOrInterface() && rhsType.isClassOrInterface() &&
964  !relatedByInheritanceOrIdentical(rhsType, lhsType);
965}
966
967// Does the 'arkts-no-structure-typing' rule need to be strictly enforced to complete previously missed scenarios
968export function needStrictMatchType(lhsType: Type, rhsType: Type): boolean {
969  if (isStrictSendableMatch(lhsType, rhsType)) {
970    return true;
971  }
972  // add other requirements with strict type requirements here
973  return false;
974}
975
976// For compatibility, left must all ClassOrInterface is sendable, right must has non-sendable ClassorInterface
977function isStrictSendableMatch(lhsType: Type, rhsType: Type): boolean {
978  let isStrictLhs = false;
979  if (lhsType.isUnion()) {
980    for (let compType of lhsType.types) {
981      compType = reduceReference(compType);
982      if (!compType.isClassOrInterface()) {
983        continue;
984      }
985      if (!isSendableClassOrInterface(compType)) {
986        return false;
987      }
988      isStrictLhs = true;
989    }
990  } else {
991    isStrictLhs = isSendableClassOrInterface(lhsType);
992  }
993  return isStrictLhs && typeContainsNonSendableClassOrInterface(rhsType);
994}
995
996export function hasPredecessor(node: Node, predicate: (node: Node) => boolean): boolean {
997  let parent = node.parent;
998  while (parent !== undefined) {
999    if (predicate(parent)) {
1000      return true;
1001    }
1002    parent = parent.parent;
1003  }
1004  return false;
1005}
1006
1007export function processParentTypes(parentTypes: NodeArray<ExpressionWithTypeArguments>, typeB: Type, processInterfaces: boolean): boolean {
1008  for (const baseTypeExpr of parentTypes) {
1009    let baseType = getTypeAtLocationForLinter(baseTypeExpr);
1010    if (isTypeReference(baseType) && baseType.target !== baseType) baseType = baseType.target;
1011    if (baseType && (baseType.isClass() !== processInterfaces) && relatedByInheritanceOrIdentical(baseType, typeB)) return true;
1012  }
1013  return false;
1014}
1015
1016function processParentTypesCheck(
1017  parentTypes: NodeArray<Expression>,
1018  checkType: CheckType,
1019  checkedBaseTypes: Set<Type>
1020): boolean {
1021  for (const baseTypeExpr of parentTypes) {
1022    let baseType = getTypeAtLocationForLinter(baseTypeExpr);
1023    if (isTypeReference(baseType) && baseType.target !== baseType) {
1024      baseType = baseType.target;
1025    }
1026    if (
1027      baseType &&
1028      !checkedBaseTypes.has(baseType) &&
1029      isOrDerivedFrom(baseType, checkType, checkedBaseTypes)
1030    ) {
1031      return true;
1032    }
1033  }
1034  return false;
1035}
1036
1037
1038export function isObject(tsType: Type): boolean {
1039  if (!tsType) {
1040    return false;
1041  }
1042  if (tsType.symbol && (tsType.isClassOrInterface() && tsType.symbol.name === "Object")) {
1043    return true;
1044  }
1045  const node = typeChecker.typeToTypeNode(tsType, undefined, NodeBuilderFlags.AllowEmptyTuple);
1046  return node !== undefined && node.kind === SyntaxKind.ObjectKeyword;
1047}
1048
1049export function logTscDiagnostic(diagnostics: readonly Diagnostic[], log: (message: any, ...args: any[]) => void): void {
1050  diagnostics.forEach((diagnostic) => {
1051    let message = flattenDiagnosticMessageText(diagnostic.messageText, "\n");
1052
1053    if (diagnostic.file && diagnostic.start) {
1054      const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
1055      message = `${diagnostic.file.fileName} (${line + 1}, ${character + 1}): ${message}`;
1056    }
1057
1058    log(message);
1059  });
1060}
1061
1062export function encodeProblemInfo(problem: ProblemInfo): string {
1063  return `${problem.problem}%${problem.start}%${problem.end}`;
1064}
1065
1066export function decodeAutofixInfo(info: string): AutofixInfo {
1067  const infos = info.split("%");
1068  return { problemID: infos[0], start: Number.parseInt(infos[1]), end: Number.parseInt(infos[2]) };
1069}
1070
1071export function isCallToFunctionWithOmittedReturnType(tsExpr: Expression): boolean {
1072  if (isCallExpression(tsExpr)) {
1073    const tsCallSignature = typeChecker.getResolvedSignature(tsExpr);
1074    if (tsCallSignature) {
1075      const tsSignDecl = tsCallSignature.getDeclaration();
1076      // `tsSignDecl` is undefined when `getResolvedSignature` returns `unknownSignature`
1077      if (!tsSignDecl || !tsSignDecl.type) return true;
1078    }
1079  }
1080
1081  return false;
1082}
1083
1084function hasReadonlyFields(type: Type): boolean {
1085  if (type.symbol.members === undefined) return false; // No members -> no readonly fields
1086
1087  let result = false;
1088
1089  type.symbol.members.forEach((value /*, key*/) => {
1090    if (
1091      value.declarations !== undefined && value.declarations.length > 0 &&
1092      isPropertyDeclaration(value.declarations[0])
1093    ) {
1094      const propmMods = getModifiers(value.declarations[0] as PropertyDeclaration);//value.declarations[0].modifiers; // TSC 4.2 doesn't have 'getModifiers()' method
1095      if (hasModifier(propmMods, SyntaxKind.ReadonlyKeyword)) {
1096        result = true;
1097        return;
1098      }
1099    }
1100  });
1101
1102  return result;
1103}
1104
1105function hasDefaultCtor(type: Type): boolean {
1106  if (type.symbol.members === undefined) return true; // No members -> no explicite constructors -> there is default ctor
1107
1108  let hasCtor = false; // has any constructor
1109  let hasDefaultCtor = false; // has default constructor
1110
1111  type.symbol.members.forEach((value /*, key*/) => {
1112  if ((value.flags & SymbolFlags.Constructor) !== 0) {
1113    hasCtor = true;
1114
1115    if (value.declarations !== undefined && value.declarations.length > 0) {
1116      const declCtor = value.declarations[0] as ConstructorDeclaration;
1117      if (declCtor.parameters.length === 0) {
1118        hasDefaultCtor = true;
1119        return;
1120      }
1121    }
1122  }
1123  });
1124
1125  return !hasCtor || hasDefaultCtor; // Has no any explicite constructor -> has implicite default constructor.
1126}
1127
1128function isAbstractClass(type: Type): boolean {
1129  if (type.isClass() && type.symbol.declarations && type.symbol.declarations.length > 0) {
1130    const declClass = type.symbol.declarations[0] as ClassDeclaration;
1131    const classMods = getModifiers(declClass); //declClass.modifiers; // TSC 4.2 doesn't have 'getModifiers()' method
1132    if (hasModifier(classMods, SyntaxKind.AbstractKeyword)) {
1133      return true;
1134    }
1135  }
1136
1137  return false;
1138}
1139
1140export function validateObjectLiteralType(type: Type | undefined): boolean {
1141  if (!type) return false;
1142
1143  type = getTargetType(type);
1144  return (
1145    type !== undefined && type.isClassOrInterface() && hasDefaultCtor(type) &&
1146    !hasReadonlyFields(type) && !isAbstractClass(type)
1147  );
1148}
1149
1150export function isStructDeclarationKind(kind: SyntaxKind) {
1151  return kind === SyntaxKind.StructDeclaration;
1152}
1153
1154export function isStructDeclaration(node: Node) {
1155  return isStructDeclarationKind(node.kind);
1156}
1157export function isStructObjectInitializer(objectLiteral: ObjectLiteralExpression): boolean {
1158  if(isCallLikeExpression(objectLiteral.parent)) {
1159    const signature = typeChecker.getResolvedSignature(objectLiteral.parent);
1160    const signDecl = signature?.declaration;
1161    return !!signDecl && isConstructorDeclaration(signDecl) && isStructDeclaration(signDecl.parent);
1162  }
1163  return false;
1164}
1165
1166export function hasMethods(type: Type): boolean {
1167  const properties = typeChecker.getPropertiesOfType(type);
1168  if (properties?.length) {
1169    for (const prop of properties) {
1170      if (prop.getFlags() & SymbolFlags.Method) return true;
1171    }
1172  };
1173
1174  return false;
1175}
1176
1177function findProperty(type: Type, name: string): Symbol | undefined {
1178  const properties = typeChecker.getPropertiesOfType(type);
1179  if(properties.length) {
1180    for (const prop of properties) {
1181      if (prop.name === name) return prop;
1182    }
1183  }
1184  return undefined;
1185}
1186
1187export function checkTypeSet(typeSet: Type, predicate: CheckType): boolean {
1188  if (!typeSet.isUnionOrIntersection()) {
1189    return predicate(typeSet);
1190  }
1191  for (let elemType of typeSet.types) {
1192    if (checkTypeSet(elemType, predicate)) {
1193      return true;
1194    }
1195  }
1196  return false;
1197}
1198
1199export function getNonNullableType(t: Type): Type {
1200  if (t.isUnion()) {
1201    return t.getNonNullableType();
1202  }
1203  return t;
1204}
1205
1206export function isObjectLiteralAssignable(lhsType: Type | undefined, rhsExpr: ObjectLiteralExpression): boolean {
1207  if (lhsType === undefined) {
1208    return false;
1209  }
1210
1211  // Always check with the non-nullable variant of lhs type.
1212  lhsType = getNonNullableType(lhsType);
1213
1214  if (lhsType.isUnion()) {
1215    for (const compType of lhsType.types) {
1216      if (isObjectLiteralAssignable(compType, rhsExpr)) {
1217        return true;
1218      }
1219    }
1220  }
1221
1222  // Allow initializing with anything when the type
1223  // originates from the library.
1224  if ((isAnyType(lhsType) || isLibraryType(lhsType)) && !isStaticSourceFileForLinter(lhsType)) {
1225    return true;
1226  }
1227
1228  // issue 13412:
1229  // Allow initializing with a dynamic object when the LHS type
1230  // is primitive or defined in standard library.
1231  if (isDynamicObjectAssignedToStdType(lhsType, rhsExpr)) {
1232    return true;
1233  }
1234
1235  // For Partial<T>, Required<T>, Readonly<T> types, validate their argument type.
1236  if (isStdPartialType(lhsType) || isStdRequiredType(lhsType) || isStdReadonlyType(lhsType)) {
1237    if (lhsType.aliasTypeArguments && lhsType.aliasTypeArguments.length === 1) {
1238      lhsType = lhsType.aliasTypeArguments[0];
1239    } else {
1240      return false;
1241    }
1242  }
1243
1244  // Allow initializing Record objects with object initializer.
1245  // Record supports any type for a its value, but the key value
1246  // must be either a string or number literal.
1247  if (isStdRecordType(lhsType)) {
1248    return validateRecordObjectKeys(rhsExpr);
1249  }
1250
1251  return validateObjectLiteralType(lhsType) && !hasMethods(lhsType) && validateFields(lhsType, rhsExpr);
1252}
1253
1254function isDynamicObjectAssignedToStdType(lhsType: Type, rhsExpr: Expression): boolean {
1255  if (isStdLibraryType(lhsType) || isPrimitiveType(lhsType)) {
1256    const rhsSym = isCallExpression(rhsExpr)
1257      ? getSymbolOfCallExpression(rhsExpr)
1258      : typeChecker.getSymbolAtLocation(rhsExpr);
1259
1260    if (rhsSym && isLibrarySymbol(rhsSym)) return true;
1261  }
1262  return false;
1263}
1264
1265function getTargetType(type: Type): Type {
1266  return (type.getFlags() & TypeFlags.Object) &&
1267    (type as ObjectType).objectFlags & ObjectFlags.Reference ? (type as TypeReference).target : type;
1268}
1269
1270export function isLiteralType(type: Type): boolean {
1271  return type.isLiteral() || (type.flags & TypeFlags.BooleanLiteral) !== 0;
1272}
1273
1274export function validateFields(objectType: Type, objectLiteral: ObjectLiteralExpression): boolean {
1275  for (const prop of objectLiteral.properties) {
1276    if (isPropertyAssignment(prop)) {
1277      if (!validateField(objectType, prop)) {
1278        return false;
1279      }
1280    }
1281  };
1282
1283  return true;
1284}
1285
1286function validateField(type: Type, prop: PropertyAssignment): boolean {
1287  // Issue 15497: Use unescaped property name to find correpsponding property.
1288  const propNameSymbol = typeChecker.getSymbolAtLocation(prop.name);
1289  const propName = propNameSymbol ?
1290    symbolName(propNameSymbol) :
1291    isMemberName(prop.name) ?
1292      idText(prop.name) :
1293      prop.name.getText();
1294  const propSym = findProperty(type, propName);
1295  if (!propSym || !propSym.declarations?.length) {
1296    return false;
1297  }
1298
1299  const propType = typeChecker.getTypeOfSymbolAtLocation(propSym, propSym.declarations[0]);
1300  const initExpr = unwrapParenthesized(prop.initializer);
1301  const rhsType = getTypeAtLocationForLinter(initExpr);
1302  if (isObjectLiteralExpression(initExpr)) {
1303    if (!isObjectLiteralAssignable(propType, initExpr)) {
1304      return false;
1305    }
1306  } else {
1307    // Only check for structural sub-typing.
1308    if (needToDeduceStructuralIdentity(
1309      propType,
1310      rhsType,
1311      initExpr,
1312      needStrictMatchType(propType, rhsType)
1313    )) {
1314      return false;
1315    }
1316
1317    if (isWrongSendableFunctionAssignment(propType, rhsType)) {
1318      return false;
1319    }
1320  }
1321
1322  return true;
1323}
1324
1325function isSupportedTypeNodeKind(kind: SyntaxKind): boolean {
1326  return kind !== SyntaxKind.AnyKeyword && kind !== SyntaxKind.UnknownKeyword &&
1327    kind !== SyntaxKind.SymbolKeyword && kind !== SyntaxKind.IndexedAccessType &&
1328    kind !== SyntaxKind.ConditionalType && kind !== SyntaxKind.MappedType &&
1329    kind !== SyntaxKind.InferType;
1330}
1331
1332export function isSupportedType(typeNode: TypeNode): boolean {
1333  if (isParenthesizedTypeNode(typeNode)) return isSupportedType(typeNode.type);
1334
1335  if (isArrayTypeNode(typeNode)) return isSupportedType(typeNode.elementType);
1336
1337  if (isTypeReferenceNode(typeNode) && typeNode.typeArguments) {
1338    for (const typeArg of typeNode.typeArguments) {
1339      if (!isSupportedType(typeArg)) { return false; }
1340    }
1341    return true;
1342  }
1343
1344  if (isUnionTypeNode(typeNode)) {
1345    for (const unionTypeElem of typeNode.types) {
1346      if (!isSupportedType(unionTypeElem)) { return false; }
1347    }
1348    return true;
1349  }
1350
1351  if (isTupleTypeNode(typeNode)) {
1352    for (const elem of typeNode.elements) {
1353      if (isTypeNode(elem) && !isSupportedType(elem)) return false;
1354      if (isNamedTupleMember(elem) && !isSupportedType(elem.type)) return false;
1355    }
1356    return true;
1357  }
1358
1359  return !isTypeLiteralNode(typeNode) && !isTypeQueryNode(typeNode) &&
1360    !isIntersectionTypeNode(typeNode) && isSupportedTypeNodeKind(typeNode.kind);
1361}
1362
1363export function isStruct(symbol: Symbol) {
1364  if (!symbol.declarations) {
1365    return false;
1366  }
1367  for (const decl of symbol.declarations) {
1368    if (isStructDeclaration(decl)) {
1369      return true;
1370    }
1371  }
1372  return false;
1373}
1374
1375function validateRecordObjectKeys(objectLiteral: ObjectLiteralExpression): boolean {
1376  for (const prop of objectLiteral.properties) {
1377    if (!prop.name) {
1378      return false;
1379    }
1380    const isValidComputedProperty = isComputedPropertyName(prop.name) && isValidComputedPropertyName(prop.name, true);
1381    if (!isStringLiteral(prop.name) && !isNumericLiteral(prop.name) && !isValidComputedProperty) {
1382      return false;
1383    }
1384  }
1385  return true;
1386}
1387
1388/* Not need in Tsc 4.9
1389export function getDecorators(node: Node): readonly Decorator[] | undefined {
1390if (node.decorators) {
1391return filter(node.decorators, isDecorator);
1392}
1393}
1394*/
1395
1396export type CheckType = ((t: Type) => boolean);
1397
1398export const ES_OBJECT = "ESObject";
1399
1400export const LIMITED_STD_GLOBAL_FUNC = [
1401  "eval"
1402];
1403export const LIMITED_STD_OBJECT_API = [
1404  "__proto__", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "assign", "create",
1405  "defineProperties", "defineProperty", "freeze", "fromEntries", "getOwnPropertyDescriptor",
1406  "getOwnPropertyDescriptors", "getOwnPropertySymbols", "getPrototypeOf", "hasOwnProperty", "is",
1407  "isExtensible", "isFrozen", "isPrototypeOf", "isSealed", "preventExtensions", "propertyIsEnumerable",
1408  "seal", "setPrototypeOf"
1409];
1410export const LIMITED_STD_REFLECT_API = [
1411  "apply", "construct", "defineProperty", "deleteProperty", "getOwnPropertyDescriptor", "getPrototypeOf",
1412  "isExtensible", "preventExtensions", "setPrototypeOf"
1413];
1414export const LIMITED_STD_PROXYHANDLER_API = [
1415  "apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf",
1416  "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"
1417];
1418
1419export const FUNCTION_HAS_NO_RETURN_ERROR_CODE = 2366;
1420export const NON_RETURN_FUNCTION_DECORATORS = ["AnimatableExtend", "Builder", "Extend", "Styles" ];
1421
1422export const STANDARD_LIBRARIES = [
1423  "lib.dom.d.ts", "lib.dom.iterable.d.ts", "lib.webworker.d.ts", "lib.webworker.importscripd.ts",
1424  "lib.webworker.iterable.d.ts", "lib.scripthost.d.ts", "lib.decorators.d.ts", "lib.decorators.legacy.d.ts",
1425  "lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.collection.d.ts", "lib.es2015.generator.d.ts",
1426  "lib.es2015.iterable.d.ts", "lib.es2015.promise.d.ts", "lib.es2015.proxy.d.ts", "lib.es2015.reflect.d.ts",
1427  "lib.es2015.symbol.d.ts", "lib.es2015.symbol.wellknown.d.ts", "lib.es2016.array.include.d.ts",
1428  "lib.es2017.object.d.ts", "lib.es2017.sharedmemory.d.ts", "lib.es2017.string.d.ts", "lib.es2017.intl.d.ts",
1429  "lib.es2017.typedarrays.d.ts", "lib.es2018.asyncgenerator.d.ts", "lib.es2018.asynciterable.d.ts",
1430  "lib.es2018.intl.d.ts", "lib.es2018.promise.d.ts", "lib.es2018.regexp.d.ts", "lib.es2019.array.d.ts",
1431  "lib.es2019.object.d.ts", "lib.es2019.string.d.ts", "lib.es2019.symbol.d.ts", "lib.es2019.intl.d.ts",
1432  "lib.es2020.bigint.d.ts", "lib.es2020.date.d.ts", "lib.es2020.promise.d.ts", "lib.es2020.sharedmemory.d.ts",
1433  "lib.es2020.string.d.ts", "lib.es2020.symbol.wellknown.d.ts", "lib.es2020.intl.d.ts", "lib.es2020.number.d.ts",
1434  "lib.es2021.promise.d.ts", "lib.es2021.string.d.ts", "lib.es2021.weakref.d.ts", "lib.es2021.intl.d.ts",
1435  "lib.es2022.array.d.ts", "lib.es2022.error.d.ts", "lib.es2022.intl.d.ts", "lib.es2022.object.d.ts",
1436  "lib.es2022.sharedmemory.d.ts", "lib.es2022.string.d.ts", "lib.es2022.regexp.d.ts", "lib.es2023.array.d.ts",
1437];
1438
1439export const TYPED_ARRAYS = [
1440  'Int8Array',
1441  'Uint8Array',
1442  'Uint8ClampedArray',
1443  'Int16Array',
1444  'Uint16Array',
1445  'Int32Array',
1446  'Uint32Array',
1447  'Float32Array',
1448  'Float64Array',
1449  'BigInt64Array',
1450  'BigUint64Array',
1451  ];
1452
1453export const TYPED_COLLECTIONS = [
1454  'BitVector'
1455  ];
1456
1457let parentSymbolCache: ESMap<Symbol, string | undefined> | undefined = new Map<Symbol, string | undefined>();
1458export function getParentSymbolName(symbol: Symbol): string | undefined {
1459  parentSymbolCache = parentSymbolCache ? parentSymbolCache : new Map<Symbol, string | undefined>();
1460  const cached = parentSymbolCache.get(symbol);
1461  if (cached) {
1462    return cached;
1463  }
1464  const name = typeChecker.getFullyQualifiedName(symbol);
1465  const dotPosition = name.lastIndexOf(".");
1466  const result = (dotPosition === -1) ? undefined : name.substring(0, dotPosition);
1467  parentSymbolCache.set(symbol, result);
1468  return result;
1469}
1470
1471export function isGlobalSymbol(symbol: Symbol): boolean {
1472  const parentName = getParentSymbolName(symbol);
1473  return !parentName || parentName === "global";
1474}
1475
1476export function isSymbolAPI(symbol: Symbol): boolean {
1477  const parentName = getParentSymbolName(symbol);
1478  let name = parentName ? parentName : symbol.escapedName;
1479  return name === 'Symbol' || name === "SymbolConstructor";
1480}
1481
1482export function isStdSymbol(symbol: Symbol): boolean {
1483  const name = typeChecker.getFullyQualifiedName(symbol);
1484  return name === 'Symbol' && isGlobalSymbol(symbol);
1485}
1486
1487export function isSymbolIterator(symbol: Symbol): boolean {
1488  const name = symbol.name;
1489  const parName = getParentSymbolName(symbol);
1490  return (parName === 'Symbol' || parName === 'SymbolConstructor') && name === 'iterator';
1491}
1492
1493export function isSymbolIteratorExpression(expr: Expression): boolean {
1494  const symbol = trueSymbolAtLocation(expr);
1495  return !!symbol && isSymbolIterator(symbol);
1496}
1497
1498export function isDefaultImport(importSpec: ImportSpecifier): boolean {
1499  return importSpec?.propertyName?.text === "default";
1500}
1501export function hasAccessModifier(decl: Declaration): boolean {
1502  const modifiers = getModifiers(decl as HasModifiers); //decl.modifiers; // TSC 4.2 doesn't have 'getModifiers()' method
1503  return (
1504    !!modifiers &&
1505    (hasModifier(modifiers, SyntaxKind.PublicKeyword) ||
1506      hasModifier(modifiers, SyntaxKind.ProtectedKeyword) ||
1507      hasModifier(modifiers, SyntaxKind.PrivateKeyword))
1508  );
1509}
1510
1511export function getModifier(modifiers: readonly Modifier[] | undefined, modifierKind: SyntaxKind): Modifier | undefined {
1512  if (!modifiers) return undefined;
1513  return modifiers.find(x => x.kind === modifierKind);
1514}
1515
1516export function getAccessModifier(modifiers: readonly Modifier[] | undefined): Modifier | undefined {
1517  return getModifier(modifiers, SyntaxKind.PublicKeyword) ??
1518    getModifier(modifiers, SyntaxKind.ProtectedKeyword) ??
1519    getModifier(modifiers, SyntaxKind.PrivateKeyword);
1520}
1521
1522export function isStdRecordType(type: Type): boolean {
1523  // In TypeScript, 'Record<K, T>' is defined as type alias to a mapped type.
1524  // Thus, it should have 'aliasSymbol' and 'target' properties. The 'target'
1525  // in this case will resolve to origin 'Record' symbol.
1526  if (type.aliasSymbol) {
1527    const target = (type as TypeReference).target;
1528    if (target) {
1529      const sym = target.aliasSymbol;
1530      return !!sym && sym.getName() === "Record" && isGlobalSymbol(sym);
1531    }
1532  }
1533
1534  return false;
1535}
1536
1537export function isStdMapType(type: Type): boolean {
1538  const sym = type.symbol;
1539  return !!sym && sym.getName() === "Map" && isGlobalSymbol(sym);
1540}
1541
1542export function isStdErrorType(type: Type): boolean {
1543  const symbol = type.symbol;
1544  if (!symbol) {
1545    return false;
1546  }
1547  const name = typeChecker.getFullyQualifiedName(symbol);
1548  return name === 'Error' && isGlobalSymbol(symbol);
1549}
1550
1551export function isStdPartialType(type: Type): boolean {
1552  const sym = type.aliasSymbol;
1553  return !!sym && sym.getName() === "Partial" && isGlobalSymbol(sym);
1554}
1555
1556export function isStdRequiredType(type: Type): boolean {
1557  const sym = type.aliasSymbol;
1558  return !!sym && sym.getName() === "Required" && isGlobalSymbol(sym);
1559}
1560
1561export function isStdReadonlyType(type: Type): boolean {
1562  const sym = type.aliasSymbol;
1563  return !!sym && sym.getName() === "Readonly" && isGlobalSymbol(sym);
1564}
1565
1566export function isLibraryType(type: Type): boolean {
1567  const nonNullableType = type.getNonNullableType();
1568  if (nonNullableType.isUnion()) {
1569    for (const componentType of nonNullableType.types) {
1570      if (!isLibraryType(componentType)) {
1571        return false;
1572      }
1573    }
1574    return true;
1575  }
1576  return isLibrarySymbol(nonNullableType.aliasSymbol ?? nonNullableType.getSymbol());
1577}
1578
1579export function hasLibraryType(node: Node): boolean {
1580  return isLibraryType(getTypeAtLocationForLinter(node));
1581}
1582
1583export function isLibrarySymbol(sym: Symbol | undefined) {
1584  if (sym && sym.declarations && sym.declarations.length > 0) {
1585    const srcFile = sym.declarations[0].getSourceFile();
1586    if (!srcFile) {
1587      return false;
1588    }
1589    const fileName = srcFile.fileName;
1590
1591    // Symbols from both *.ts and *.d.ts files should obey interop rules.
1592    // We disable such behavior for *.ts files in the test mode due to lack of 'ets'
1593    // extension support.
1594    const ext = getAnyExtensionFromPath(fileName);
1595    const isThirdPartyCode =
1596      ARKTS_IGNORE_DIRS.some(ignore => srcFilePathContainsDirectory(srcFile, ignore)) ||
1597      ARKTS_IGNORE_FILES.some(ignore => getBaseFileName(fileName) === ignore);
1598    const isEts = (ext === '.ets');
1599    const isTs = (ext === '.ts' && !srcFile.isDeclarationFile);
1600    const isStatic = (isEts || (isTs && testMode)) && !isThirdPartyCode;
1601    const isStdLib = STANDARD_LIBRARIES.includes(getBaseFileName(fileName).toLowerCase());
1602    // We still need to confirm support for certain API from the
1603    // TypeScript standard library in ArkTS. Thus, for now do not
1604    // count standard library modules as dynamic.
1605    return !isStatic && !isStdLib;
1606  }
1607
1608  return false;
1609}
1610
1611const srcFilePathComponents = new Map<SourceFile, string[]>();
1612export function srcFilePathContainsDirectory(srcFile: SourceFile, dir: string): boolean {
1613    let pathComps = srcFilePathComponents.get(srcFile);
1614    if (!pathComps) {
1615        pathComps = getPathComponents(normalizePath(srcFile.fileName));
1616        srcFilePathComponents.set(srcFile, pathComps);
1617    }
1618    for (const subdir of pathComps) {
1619        if (subdir === dir) {
1620          return true;
1621        }
1622    }
1623    return false;
1624}
1625
1626export function pathContainsDirectory(targetPath: string, dir: string): boolean {
1627  for (const subdir of getPathComponents(targetPath)) {
1628    if (subdir === dir) {
1629      return true;
1630    }
1631  }
1632  return false;
1633}
1634
1635export function getScriptKind(srcFile: SourceFile): ScriptKind {
1636  const fileName = srcFile.fileName;
1637  const ext = getAnyExtensionFromPath(fileName);
1638  switch (ext.toLowerCase()) {
1639    case Extension.Js:
1640      return ScriptKind.JS;
1641    case Extension.Jsx:
1642      return ScriptKind.JSX;
1643    case Extension.Ts:
1644      return ScriptKind.TS;
1645    case Extension.Tsx:
1646      return ScriptKind.TSX;
1647    case Extension.Json:
1648      return ScriptKind.JSON;
1649    default:
1650      return ScriptKind.Unknown;
1651  }
1652}
1653
1654export function isStdLibraryType(type: Type): boolean {
1655  return isStdLibrarySymbol(type.aliasSymbol ?? type.getSymbol());
1656}
1657
1658export function isStdLibrarySymbol(sym: Symbol | undefined) {
1659  if (sym && sym.declarations && sym.declarations.length > 0) {
1660    const srcFile = sym.declarations[0].getSourceFile();
1661    return srcFile &&
1662      STANDARD_LIBRARIES.includes(getBaseFileName(srcFile.fileName).toLowerCase());
1663  }
1664
1665  return false;
1666}
1667
1668export function isIntrinsicObjectType(type: Type): boolean {
1669  return !!(type.flags & TypeFlags.NonPrimitive);
1670}
1671
1672export function isOhModulesEtsSymbol(sym: Symbol | undefined): boolean {
1673  const sourceFile = sym?.declarations?.[0]?.getSourceFile();
1674  return (
1675    !!sourceFile &&
1676    sourceFile.scriptKind === ScriptKind.ETS &&
1677    srcFilePathContainsDirectory(sourceFile, ARKTS_IGNORE_DIRS_OH_MODULES)
1678  );
1679}
1680
1681export function isDynamicType(type: Type | undefined): boolean | undefined {
1682  if (type === undefined) {
1683    return false;
1684  }
1685
1686  // Return 'true' if it is an object of library type initialization, otherwise
1687  // return 'false' if it is not an object of standard library type one.
1688  // In the case of standard library type we need to determine context.
1689
1690  // Check the non-nullable version of type to eliminate 'undefined' type
1691  // from the union type elements.
1692  type = type.getNonNullableType();
1693
1694
1695  if (type.isUnion()) {
1696    for (const compType of type.types) {
1697      const isDynamic = isDynamicType(compType);
1698      if (isDynamic || isDynamic === undefined) {
1699        return isDynamic;
1700      }
1701    }
1702    return false;
1703  }
1704
1705  if (isLibraryType(type) && !isStaticSourceFileForLinter(type)) {
1706    return true;
1707  }
1708
1709  if (!isStdLibraryType(type) && !isIntrinsicObjectType(type) && !isAnyType(type)) {
1710    return false;
1711  }
1712
1713  return undefined;
1714}
1715
1716export function isObjectType(type: Type): type is ObjectType {
1717  return !!(type.flags & TypeFlags.Object);
1718}
1719
1720export function isAnonymous(type: Type): boolean {
1721  if (isObjectType(type)) {
1722    return !!(type.objectFlags & ObjectFlags.Anonymous);
1723  }
1724  return false;
1725  }
1726
1727
1728export function isDynamicLiteralInitializer(expr: Expression): boolean {
1729  if (!isObjectLiteralExpression(expr) && !isArrayLiteralExpression(expr)) {
1730    return false;
1731  }
1732
1733  // Handle nested literals:
1734  // { f: { ... } }
1735  let curNode: Node = expr;
1736  while (isObjectLiteralExpression(curNode) || isArrayLiteralExpression(curNode)) {
1737    const exprType = typeChecker.getContextualType(curNode);
1738    if (exprType !== undefined && !isAnonymous(exprType)) {
1739      const res = isDynamicType(exprType);
1740      if (res !== undefined) {
1741        return res;
1742      }
1743    }
1744
1745    curNode = curNode.parent;
1746    if (isPropertyAssignment(curNode)) {
1747      curNode = curNode.parent;
1748    }
1749  }
1750
1751  // Handle calls with literals:
1752  // foo({ ... })
1753  if (isCallExpression(curNode)) {
1754    const callExpr = curNode;
1755    const type = getTypeAtLocationForLinter(callExpr.expression);
1756
1757    // this check is a hack to fix #13474, only for tac 4.2
1758    if (isAnyType(type)) return true;
1759
1760    let sym: Symbol | undefined = type.symbol;
1761    if (isLibrarySymbol(sym)) {
1762      return true;
1763    }
1764
1765    // #13483:
1766    // x.foo({ ... }), where 'x' is a variable exported from some library:
1767    if (isPropertyAccessExpression(callExpr.expression)) {
1768      sym = typeChecker.getSymbolAtLocation(callExpr.expression.expression);
1769      if (sym && sym.getFlags() & SymbolFlags.Alias) {
1770        sym = typeChecker.getAliasedSymbol(sym);
1771        if (isLibrarySymbol(sym)) {
1772          return true;
1773        }
1774      }
1775    }
1776  }
1777
1778  // Handle property assignments with literals:
1779  // obj.f = { ... }
1780  if (isBinaryExpression(curNode)) {
1781    const binExpr = curNode;
1782    if (isPropertyAccessExpression(binExpr.left)) {
1783      const propAccessExpr = binExpr.left;
1784      const type = getTypeAtLocationForLinter(propAccessExpr.expression);
1785      return isLibrarySymbol(type.symbol);
1786    }
1787  }
1788
1789  return false;
1790}
1791
1792export function isEsObjectType(typeNode: TypeNode | undefined): boolean {
1793  return !!typeNode && isTypeReferenceNode(typeNode) && isIdentifier(typeNode.typeName) &&
1794    typeNode.typeName.text === ES_OBJECT;
1795}
1796
1797export function isInsideBlock(node: Node): boolean {
1798  let par = node.parent
1799  while (par) {
1800    if (isBlock(par)) {
1801      return true;
1802    }
1803    par = par.parent;
1804  }
1805  return false;
1806}
1807
1808export function isValueAssignableToESObject(node: Node): boolean {
1809  if (isArrayLiteralExpression(node) || isObjectLiteralExpression(node)) {
1810    return false;
1811  }
1812  const valueType = getTypeAtLocationForLinter(node);
1813  return isUnsupportedType(valueType) || isAnonymousType(valueType)
1814}
1815
1816export function getVariableDeclarationTypeNode(node: Node): TypeNode | undefined {
1817  let sym = trueSymbolAtLocation(node);
1818  if (sym === undefined) {
1819    return undefined;
1820  }
1821  return getSymbolDeclarationTypeNode(sym);
1822}
1823
1824export function getSymbolDeclarationTypeNode(sym: Symbol): TypeNode | undefined {
1825  const decl = getDeclaration(sym);
1826  if (!!decl && isVariableDeclaration(decl)) {
1827    return decl.type;
1828  }
1829  return undefined;
1830}
1831
1832export function hasEsObjectType(node: Node): boolean {
1833  const typeNode = getVariableDeclarationTypeNode(node);
1834  return typeNode !== undefined && isEsObjectType(typeNode);
1835}
1836
1837export function symbolHasEsObjectType(sym: Symbol): boolean {
1838  const typeNode = getSymbolDeclarationTypeNode(sym);
1839  return typeNode !== undefined && isEsObjectType(typeNode);
1840}
1841
1842export function isEsObjectSymbol(sym: Symbol): boolean {
1843  const decl = getDeclaration(sym);
1844  return !!decl && isTypeAliasDeclaration(decl) && decl.name.escapedText === ES_OBJECT &&
1845    decl.type.kind === SyntaxKind.AnyKeyword;
1846}
1847
1848export function isAnonymousType(type: Type): boolean {
1849  if (type.isUnionOrIntersection()) {
1850    for (const compType of type.types) {
1851      if (isAnonymousType(compType)) {
1852        return true;
1853      }
1854    }
1855    return false;
1856  }
1857
1858  return (type.flags & TypeFlags.Object) !== 0 &&
1859    ((type as ObjectType).objectFlags & ObjectFlags.Anonymous) !== 0;
1860}
1861
1862export function getSymbolOfCallExpression(callExpr: CallExpression): Symbol | undefined {
1863  const signature = typeChecker.getResolvedSignature(callExpr);
1864  const signDecl = signature?.getDeclaration();
1865  if (signDecl && signDecl.name) {
1866    return typeChecker.getSymbolAtLocation(signDecl.name);
1867  }
1868  return undefined;
1869}
1870
1871export function typeIsRecursive(topType: Type, type: Type | undefined = undefined): boolean {
1872  if (type === undefined) {
1873    type = topType;
1874  }
1875  else if (type === topType) {
1876    return true;
1877  }
1878  else if (type.aliasSymbol) {
1879    return false;
1880  }
1881
1882  if (type.isUnion()) {
1883    for (const unionElem of type.types) {
1884      if (typeIsRecursive(topType, unionElem)) {
1885        return true;
1886      }
1887    }
1888  }
1889  if (type.flags & TypeFlags.Object && (type as ObjectType).objectFlags & ObjectFlags.Reference) {
1890    const typeArgs = typeChecker.getTypeArguments(type as TypeReference);
1891    if (typeArgs) {
1892      for (const typeArg of typeArgs) {
1893        if (typeIsRecursive(topType, typeArg)) {
1894          return true;
1895        }
1896      }
1897    }
1898  }
1899  return false;
1900}
1901
1902export function getTypeOrTypeConstraintAtLocation(expr: Expression): Type {
1903  let type = getTypeAtLocationForLinter(expr);
1904  if (type.isTypeParameter()) {
1905    let constraint = type.getConstraint();
1906    if (constraint) {
1907      return constraint;
1908    }
1909  }
1910  return type;
1911}
1912
1913function areCompatibleFunctionals(lhsType: Type, rhsType: Type): boolean {
1914  return (
1915    (isStdFunctionType(lhsType) || isFunctionalType(lhsType)) &&
1916    (isStdFunctionType(rhsType) || isFunctionalType(rhsType))
1917  );
1918}
1919
1920function isFunctionalType(type: Type): boolean {
1921  const callSigns = type.getCallSignatures();
1922  return callSigns && callSigns.length > 0;
1923}
1924
1925function isStdFunctionType(type: Type): boolean {
1926  const sym = type.getSymbol();
1927  return !!sym && sym.getName() === 'Function' && isGlobalSymbol(sym);
1928}
1929
1930export function isStdBigIntType(type: Type): boolean {
1931  const sym = type.symbol;
1932  return !!sym && sym.getName() === 'BigInt' && isGlobalSymbol(sym);
1933}
1934
1935export function isStdNumberType(type: Type): boolean {
1936  const sym = type.symbol;
1937  return !!sym && sym.getName() === 'Number' && isGlobalSymbol(sym);
1938}
1939
1940export function isStdBooleanType(type: Type): boolean {
1941  const sym = type.symbol;
1942  return !!sym && sym.getName() === 'Boolean' && isGlobalSymbol(sym);
1943}
1944
1945export function isEnumStringLiteral(expr: Expression): boolean {
1946  const symbol = trueSymbolAtLocation(expr);
1947  const isEnumMember = !!symbol && !!(symbol.flags & SymbolFlags.EnumMember);
1948  const type = getTypeAtLocationForLinter(expr);
1949  const isStringEnumLiteral = isEnumType(type) && !!(type.flags & TypeFlags.StringLiteral);
1950  return isEnumMember && isStringEnumLiteral;
1951}
1952
1953export function isValidComputedPropertyName(computedProperty: ComputedPropertyName, isRecordObjectInitializer = false): boolean {
1954  const expr = computedProperty.expression;
1955  if (!isRecordObjectInitializer) {
1956    if (isSymbolIteratorExpression(expr)) {
1957      return true;
1958    }
1959  }
1960  return isStringLiteralLike(expr) || isEnumStringLiteral(computedProperty.expression);
1961}
1962
1963export function isAllowedIndexSignature(node: IndexSignatureDeclaration): boolean {
1964
1965  /*
1966  * For now, relax index signature only for specific array-like types
1967  * with the following signature: 'collections.Array<T>.[_: number]: T'.
1968  */
1969
1970  if (node.parameters.length !== 1) {
1971    return false;
1972  }
1973
1974  const paramType = getTypeAtLocationForLinter(node.parameters[0]);
1975  if ((paramType.flags & TypeFlags.Number) === 0) {
1976    return false;
1977  }
1978
1979  return isArkTSCollectionsArrayLikeDeclaration(node.parent);
1980}
1981
1982export function isArkTSCollectionsArrayLikeType(type: Type): boolean {
1983  const symbol = type.aliasSymbol ?? type.getSymbol();
1984  if (symbol?.declarations === undefined || symbol.declarations.length < 1) {
1985    return false;
1986  }
1987
1988  return isArkTSCollectionsArrayLikeDeclaration(symbol.declarations[0]);
1989}
1990
1991function isArkTSCollectionsArrayLikeDeclaration(decl: Declaration): boolean {
1992  if (!isArkTSCollectionsClassOrInterfaceDeclaration(decl)) {
1993    return false;
1994  }
1995  if (!hasIndexSignature(getTypeAtLocationForLinter(decl))) {
1996    return false;
1997  }
1998  return true;
1999}
2000
2001export function isArkTSCollectionsClassOrInterfaceDeclaration(decl: Node): boolean {
2002  if (!isClassDeclaration(decl) && !isInterfaceDeclaration(decl) || !decl.name) {
2003    return false;
2004  }
2005  if (!isModuleBlock(decl.parent) || decl.parent.parent.name.text !== COLLECTIONS_NAMESPACE) {
2006    return false;
2007  }
2008  if (getBaseFileName(decl.getSourceFile().fileName).toLowerCase() !== ARKTS_COLLECTIONS_D_ETS) {
2009    return false;
2010  }
2011  return true;
2012}
2013
2014export function getDecoratorName(decorator: Decorator): string {
2015  let decoratorName = '';
2016  if (isIdentifier(decorator.expression)) {
2017    decoratorName = decorator.expression.text;
2018  } else if (isCallExpression(decorator.expression) && isIdentifier(decorator.expression.expression)) {
2019    decoratorName = decorator.expression.expression.text;
2020  }
2021  return decoratorName;
2022}
2023
2024export function unwrapParenthesizedTypeNode(typeNode: TypeNode): TypeNode {
2025  let unwrappedTypeNode = typeNode;
2026  while (isParenthesizedTypeNode(unwrappedTypeNode)) {
2027    unwrappedTypeNode = unwrappedTypeNode.type;
2028  }
2029  return unwrappedTypeNode;
2030}
2031
2032export function isSendableTypeNode(typeNode: TypeNode, isShared: boolean = false): boolean {
2033
2034  /*
2035  * In order to correctly identify the usage of the enum member or
2036  * const enum in type annotation, we need to handle union type and
2037  * type alias cases by processing the type node and checking the
2038  * symbol in case of type reference node.
2039  */
2040
2041  typeNode = unwrapParenthesizedTypeNode(typeNode);
2042
2043  // Only a sendable union type is supported
2044  if (isUnionTypeNode(typeNode)) {
2045    return typeNode.types.every((elemType) => {
2046      return isSendableTypeNode(elemType, isShared);
2047    });
2048  }
2049
2050  const sym = isTypeReferenceNode(typeNode) ?
2051    trueSymbolAtLocation(typeNode.typeName) :
2052    undefined;
2053
2054  if (sym && sym.getFlags() & SymbolFlags.TypeAlias) {
2055    const typeDecl = getDeclaration(sym);
2056    if (typeDecl && isTypeAliasDeclaration(typeDecl)) {
2057      return isSendableTypeNode(typeDecl.type, isShared);
2058    }
2059  }
2060
2061  // Const enum type is supported
2062  if (isConstEnum(sym)) {
2063    return true;
2064  }
2065  const type: Type = typeChecker.getTypeFromTypeNode(typeNode);
2066
2067  // In shared module, literal forms of primitive data types can be exported
2068  if (isShared && isPurePrimitiveLiteralType(type)) {
2069    return true;
2070  }
2071
2072  return isSendableType(type);
2073}
2074
2075export function isSendableType(type: Type): boolean {
2076  if ((type.flags & (TypeFlags.Boolean | TypeFlags.Number | TypeFlags.String |
2077    TypeFlags.BigInt | TypeFlags.Null | TypeFlags.Undefined |
2078    TypeFlags.TypeParameter)) !== 0) {
2079    return true;
2080  }
2081  if (isSendableTypeAlias(type)) {
2082    return true;
2083  }
2084  if (isSendableFunction(type)) {
2085    return true;
2086  }
2087
2088  return isSendableClassOrInterface(type);
2089}
2090
2091export function isShareableType(tsType: Type): boolean {
2092  const sym = tsType.getSymbol();
2093  if (isConstEnum(sym)) {
2094    return true;
2095  }
2096
2097  if (!!sym && sym.flags === SymbolFlags.EnumMember) {
2098    if (isConstEnum(sym.parent)) {
2099      return true;
2100    }
2101  }
2102
2103  if (tsType.isUnion()) {
2104    return tsType.types.every((elemType) => {
2105      return isShareableType(elemType);
2106    });
2107  }
2108
2109  if (isPurePrimitiveLiteralType(tsType)) {
2110    return true;
2111  }
2112
2113  return isSendableType(tsType);
2114}
2115
2116export function isSendableClassOrInterface(type: Type): boolean {
2117  const sym = type.getSymbol();
2118  if (!sym) {
2119    return false;
2120  }
2121
2122  const targetType = reduceReference(type);
2123
2124  // class with @Sendable decorator
2125  if (targetType.isClass()) {
2126    if (sym.declarations?.length) {
2127      const decl = sym.declarations[0];
2128      if (isClassDeclaration(decl)) {
2129        return hasSendableDecorator(decl);
2130      }
2131    }
2132  }
2133  // ISendable interface, or a class/interface that implements/extends ISendable interface
2134  return isOrDerivedFrom(type, isISendableInterface);
2135}
2136
2137export function typeContainsSendableClassOrInterface(type: Type): boolean {
2138  // Only check type contains sendable class / interface
2139  if ((type.flags & TypeFlags.Union) !== 0) {
2140    return !!(type as UnionType)?.types?.some((type) => {
2141      return typeContainsSendableClassOrInterface(type);
2142    });
2143  }
2144
2145  return isSendableClassOrInterface(type);
2146}
2147
2148export function typeContainsNonSendableClassOrInterface(type: Type): boolean {
2149  if (type.isUnion()) {
2150    return type.types.some((compType) => {
2151      return typeContainsNonSendableClassOrInterface(compType);
2152    });
2153  }
2154  type = reduceReference(type);
2155  return type.isClassOrInterface() && !isSendableClassOrInterface(type);
2156}
2157
2158export function isConstEnum(sym: Symbol | undefined): boolean {
2159  return !!sym && sym.flags === SymbolFlags.ConstEnum;
2160}
2161
2162export function isSendableUnionType(type: UnionType): boolean {
2163  const types = type?.types;
2164  if (!types) {
2165    return false;
2166  }
2167
2168  return types.every((type) => {
2169    return isSendableType(type);
2170  });
2171}
2172
2173export function hasSendableDecorator(decl: ClassDeclaration | FunctionDeclaration | TypeAliasDeclaration): boolean {
2174  const decorators = getAllDecorators(decl);
2175  return decorators !== undefined && decorators.some((x) => {
2176    return getDecoratorName(x) === SENDABLE_DECORATOR;
2177  });
2178}
2179
2180export function getNonSendableDecorators(decl: ClassDeclaration | FunctionDeclaration | TypeAliasDeclaration): Decorator[] | undefined {
2181  const decorators = getAllDecorators(decl);
2182  return decorators?.filter((x) => {
2183    return getDecoratorName(x) !== SENDABLE_DECORATOR;
2184  });
2185}
2186
2187export function getSendableDecorator(decl: ClassDeclaration | FunctionDeclaration | TypeAliasDeclaration): Decorator | undefined {
2188  const decorators = getAllDecorators(decl);
2189  return decorators?.find((x) => {
2190    return getDecoratorName(x) === SENDABLE_DECORATOR;
2191  });
2192}
2193
2194export function getDecoratorsIfInSendableClass(declaration: HasDecorators): readonly Decorator[] | undefined {
2195  const classNode = getClassNodeFromDeclaration(declaration);
2196  if (classNode === undefined || !hasSendableDecorator(classNode)) {
2197    return undefined;
2198  }
2199  return getDecorators(declaration);
2200}
2201
2202function getClassNodeFromDeclaration(declaration: HasDecorators): ClassDeclaration | undefined {
2203  if (declaration.kind === SyntaxKind.Parameter) {
2204    return isClassDeclaration(declaration.parent.parent) ? declaration.parent.parent : undefined;
2205  }
2206  return isClassDeclaration(declaration.parent) ? declaration.parent : undefined;
2207}
2208
2209export function isISendableInterface(type: Type): boolean {
2210  const symbol = type.aliasSymbol ?? type.getSymbol();
2211  if (symbol?.declarations === undefined || symbol.declarations.length < 1) {
2212    return false;
2213  }
2214
2215  return isArkTSISendableDeclaration(symbol.declarations[0]);
2216}
2217
2218function isArkTSISendableDeclaration(decl: Declaration): boolean {
2219  if (!isInterfaceDeclaration(decl) || !decl.name || decl.name.text !== ISENDABLE_TYPE) {
2220    return false;
2221  }
2222
2223  if (!isModuleBlock(decl.parent) || decl.parent.parent.name.text !== LANG_NAMESPACE) {
2224    return false;
2225  }
2226
2227  if (getBaseFileName(decl.getSourceFile().fileName).toLowerCase() !== ARKTS_LANG_D_ETS) {
2228    return false;
2229  }
2230
2231  return true;
2232}
2233
2234export function isSharedModule(sourceFile: SourceFile): boolean {
2235  const statements = sourceFile.statements;
2236  for (let statement of statements) {
2237    if (isImportDeclaration(statement)) {
2238      continue;
2239    }
2240
2241    return (
2242      isExpressionStatement(statement) &&
2243      isStringLiteral(statement.expression) &&
2244      statement.expression.text === USE_SHARED
2245    );
2246  }
2247
2248  return false;
2249}
2250
2251export function getDeclarationNode(node: Node): Declaration | undefined {
2252  const sym = trueSymbolAtLocation(node);
2253  return getDeclaration(sym);
2254}
2255
2256function isFunctionLikeDeclaration(node: Declaration): boolean {
2257  return isFunctionDeclaration(node) || isMethodDeclaration(node) ||
2258    isGetAccessorDeclaration(node) || isSetAccessorDeclaration(node) || isConstructorDeclaration(node) ||
2259    isFunctionExpression(node) || isArrowFunction(node);
2260}
2261
2262export function isShareableEntity(node: Node): boolean {
2263  const decl = getDeclarationNode(node);
2264  const typeNode = (decl as any)?.type;
2265  return (typeNode && !isFunctionLikeDeclaration(decl!)) ?
2266    isSendableTypeNode(typeNode, true) :
2267    isShareableType(getTypeAtLocationForLinter(decl ? decl : node));
2268}
2269
2270export function isSendableClassOrInterfaceEntity(node: Node): boolean {
2271  const decl = getDeclarationNode(node);
2272  if (!decl) {
2273    return false;
2274  }
2275
2276  if (isClassDeclaration(decl)) {
2277    return hasSendableDecorator(decl);
2278  }
2279
2280  if (isInterfaceDeclaration(decl)) {
2281    return isOrDerivedFrom(getTypeAtLocationForLinter(decl), isISendableInterface);
2282  }
2283  return false;
2284}
2285
2286export function isInImportWhiteList(resolvedModule: ResolvedModuleFull): boolean {
2287  if (
2288    !resolvedModule.resolvedFileName ||
2289    getBaseFileName(resolvedModule.resolvedFileName) !== ARKTS_LANG_D_ETS &&
2290    getBaseFileName(resolvedModule.resolvedFileName) !== ARKTS_COLLECTIONS_D_ETS
2291  ) {
2292  return false;
2293  }
2294  return true;
2295}
2296
2297// If it is an overloaded function, all declarations for that function are found
2298export function hasSendableDecoratorFunctionOverload(decl: FunctionDeclaration): boolean {
2299  const decorators = getFunctionOverloadDecorators(decl);
2300  return !!decorators?.some((x) => {
2301    return getDecoratorName(x) === SENDABLE_DECORATOR;
2302  });
2303}
2304
2305function getFunctionOverloadDecorators(funcDecl: FunctionDeclaration): readonly Decorator[] | undefined {
2306  const decls = funcDecl.symbol.getDeclarations();
2307  if (!decls?.length) {
2308    return undefined;
2309  }
2310  let result: Decorator[] = [];
2311  decls.forEach((decl) => {
2312    if (!isFunctionDeclaration(decl)) {
2313      return;
2314    }
2315    const decorators = getAllDecorators(decl);
2316    if (decorators) {
2317      result = result.concat(decorators);
2318    }
2319  });
2320  return result.length ? result : undefined;
2321}
2322
2323export function isSendableFunction(type: Type): boolean {
2324  const callSigns = type.getCallSignatures();
2325  if (!callSigns?.length) {
2326    return false;
2327  }
2328  const decl = callSigns[0].declaration;
2329  if (!decl || !isFunctionDeclaration(decl)) {
2330    return false;
2331  }
2332  return hasSendableDecoratorFunctionOverload(decl);
2333}
2334
2335
2336export function isSendableTypeAlias(type: Type): boolean {
2337  const decl = getTypsAliasOriginalDecl(type);
2338  return !!decl && hasSendableDecorator(decl);
2339}
2340
2341export function hasSendableTypeAlias(type: Type) :boolean {
2342  if (type.isUnion()) {
2343    return type.types.some((compType) => {
2344      return hasSendableTypeAlias(compType);
2345    });
2346  };
2347  return isSendableTypeAlias(type);
2348}
2349
2350export function isNonSendableFunctionTypeAlias(type: Type): boolean {
2351  const decl = getTypsAliasOriginalDecl(type);
2352  return !!decl && isFunctionTypeNode(decl.type) && !hasSendableDecorator(decl);
2353}
2354
2355// If the alias refers to another alias, the search continues
2356function getTypsAliasOriginalDecl(type: Type): TypeAliasDeclaration | undefined {
2357  if (!type.aliasSymbol) {
2358    return undefined;
2359  }
2360  const decl = getDeclaration(type.aliasSymbol);
2361  if (!decl || !isTypeAliasDeclaration(decl)) {
2362    return undefined;
2363  }
2364  if (isTypeReferenceNode(decl.type)) {
2365  const targetType = getTypeAtLocationForLinter(decl.type.typeName);
2366    if (targetType.aliasSymbol && (targetType.aliasSymbol.getFlags() & SymbolFlags.TypeAlias)) {
2367      return getTypsAliasOriginalDecl(targetType);
2368    }
2369  }
2370  return decl;
2371}
2372
2373// not allow 'lhsType' contains 'sendable typeAlias' && 'rhsType' contains 'non-sendable function/non-sendable function typeAlias'
2374export function isWrongSendableFunctionAssignment(
2375  lhsType: Type,
2376  rhsType: Type
2377): boolean {
2378  lhsType = getNonNullableType(lhsType);
2379  rhsType = getNonNullableType(rhsType);
2380  if (!hasSendableTypeAlias(lhsType)) {
2381  return false;
2382  }
2383
2384  if (rhsType.isUnion()) {
2385  return rhsType.types.some((compType) => {
2386    return isInvalidSendableFunctionAssignmentType(compType);
2387  });
2388  }
2389  return isInvalidSendableFunctionAssignmentType(rhsType);
2390}
2391
2392function isInvalidSendableFunctionAssignmentType(type: Type): boolean {
2393  if (type.aliasSymbol) {
2394    return isNonSendableFunctionTypeAlias(type);
2395  }
2396  if (isFunctionalType(type)) {
2397    return !isSendableFunction(type);
2398  }
2399  return false;
2400}
2401
2402// Search for and save the exported declaration in the specified file, re-exporting another module will not be included.
2403export function searchFileExportDecl(sourceFile: SourceFile, targetDecls?: SyntaxKind[]): Set<Node> {
2404  const exportDeclSet = new Set<Node>();
2405  const appendDecl = (decl: Node | undefined): void => {
2406    if (
2407      !decl ||
2408      targetDecls && !targetDecls.includes(decl.kind)
2409    ) {
2410      return;
2411    }
2412    exportDeclSet.add(decl);
2413  };
2414
2415  sourceFile.statements.forEach((statement: Statement) => {
2416    if (isExportAssignment(statement)) {
2417      // handle the case:"export default declName;"
2418      if (statement.isExportEquals) {
2419        return;
2420      }
2421      appendDecl(getDeclarationNode(statement.expression));
2422    } else if (isExportDeclaration(statement)) {
2423      // handle the case:"export { declName1, declName2 };"
2424      if (!statement.exportClause || !isNamedExports(statement.exportClause)) {
2425        return;
2426      }
2427      statement.exportClause.elements.forEach((specifier) => {
2428        appendDecl(getDeclarationNode(specifier.propertyName ?? specifier.name));
2429      });
2430    } else if (canHaveModifiers(statement)) {
2431      // handle the case:"export const/class/function... decalName;"
2432      if (!hasModifier(getModifiers(statement), SyntaxKind.ExportKeyword)) {
2433        return;
2434      }
2435      if (!isVariableStatement(statement)) {
2436        appendDecl(statement);
2437        return;
2438      }
2439      for (const exportDecl of statement.declarationList.declarations) {
2440        appendDecl(exportDecl);
2441      }
2442    }
2443  });
2444  return exportDeclSet;
2445}
2446
2447export function clearUtilsGlobalvariables(): void {
2448  parentSymbolCache?.clear();
2449  parentSymbolCache = undefined;
2450}
2451
2452
2453export function isTaskPoolApi(exprSym: Symbol | undefined, node: Node): boolean {
2454  if (!isPropertyAccessExpression(node)) {
2455    return false;
2456  }
2457  const propertyAccessNode = node as PropertyAccessExpression;
2458  const baseExprSym = trueSymbolAtLocation(propertyAccessNode.expression);
2459  if (!exprSym || !baseExprSym) {
2460    return false;
2461  }
2462  if ((baseExprSym.name === TASKPOOL || baseExprSym.name === TASKGROUP) && TASKPOOL_API.includes(exprSym.name)) {
2463    return true;
2464  }
2465  const baseExprType = typeChecker.getTypeOfSymbol(baseExprSym);
2466  if (typeChecker.typeToString(baseExprType) === TASKGROUP && TASKPOOL_API.includes(exprSym.name)) {
2467    return true;
2468  }
2469  return false;
2470}
2471
2472export function isConcurrentFunction(type: Type): boolean {
2473  const callSigns = type.getCallSignatures();
2474  if (!callSigns?.length) {
2475    return false;
2476  }
2477  const decl = callSigns[0].declaration;
2478  if (!decl || !isFunctionDeclaration(decl)) {
2479    return false;
2480  }
2481  return hasConcurrentDecoratorFunctionOverload(decl) || hasUseConcurrentDirective(decl);
2482}
2483
2484export function hasConcurrentDecoratorFunctionOverload(decl: FunctionDeclaration): boolean {
2485  const decorators = getFunctionOverloadDecorators(decl);
2486  return !!decorators?.some((x) => {
2487    return getDecoratorName(x) === CONCURRENT_DECORATOR;
2488  });
2489}
2490
2491export function hasUseConcurrentDirective(decl: FunctionDeclaration): boolean {
2492  const body = decl.body;
2493  if (!body || !isBlock(body)) {
2494    return false;
2495  }
2496
2497  const firstStatement = body.statements[0];
2498  if (!firstStatement) {
2499    return false;
2500  }
2501
2502  if (isExpressionStatement(firstStatement) && isStringLiteral(firstStatement.expression)) {
2503    return firstStatement.expression.text.trim() === USE_CONCURRENT;
2504  }
2505
2506  return false;
2507}
2508
2509export function isDeclarationSymbol(sym: Symbol | undefined): boolean {
2510  if (sym && sym.declarations && sym.declarations.length > 0) {
2511    const srcFile = sym.declarations[0].getSourceFile();
2512    if (!srcFile) {
2513      return false;
2514    }
2515    return srcFile.isDeclarationFile;
2516  }
2517  return false;
2518}
2519
2520export function checkTaskpoolFunction(arg: Expression, argType: Type, argSym: Symbol| undefined): boolean {
2521  if (isFunctionSymbol(argSym)) {
2522    return !isConcurrentFunction(argType);
2523  }
2524
2525  const symbol = trueSymbolAtLocation(arg);
2526  const decl = getDeclaration(symbol);
2527  return !!decl && (isMethodDeclaration(decl) || isClassDeclaration(decl) || isObjectConstructor(decl));
2528}
2529
2530function isObjectConstructor(decl: Declaration): boolean {
2531  if (
2532    isPropertySignature(decl) &&
2533    decl.name.getText() === 'constructor' &&
2534    isInterfaceDeclaration(decl.parent) &&
2535    decl.parent.name.getText() === 'Object'
2536  ) {
2537    const sourcefile = decl.getSourceFile();
2538    return !!sourcefile && sourcefile.fileName.endsWith('lib.es5.d.ts');
2539  }
2540  return false;
2541}
2542
2543export function getTypeAtLocationForLinter(node: Node): Type {
2544  if (isSourceFile(node) && typeChecker.createIntrinsicType) {
2545    return typeChecker.createIntrinsicType(TypeFlags.Any, 'error');
2546  }
2547  return typeChecker.getTypeAtLocation(node);
2548}
2549
2550function isStaticSourceFileForLinter(type: Type): boolean {
2551  if (mixCompile && typeChecker.isStaticSourceFile) {
2552    return typeChecker.isStaticSourceFile(type.symbol?.declarations?.[0]?.getSourceFile());
2553  }
2554  return false;
2555}