diff --git a/ets2panda/linter/rule-config.json b/ets2panda/linter/rule-config.json index 611a033828ee351a8d883852ab8fb3785bf19ed0..ee6670469241996a511ecc69e52f32650758e61f 100644 --- a/ets2panda/linter/rule-config.json +++ b/ets2panda/linter/rule-config.json @@ -23,6 +23,7 @@ "arkts-numeric-semantic", "arkts-incompatible-function-types", "arkts-limited-void-type", + "arkts-distinct-infinity-bitwise-inversion", "arkts-no-void-operator", "arkts-no-local-class", "arkts-no-ts-overload", diff --git a/ets2panda/linter/src/lib/CookBookMsg.ts b/ets2panda/linter/src/lib/CookBookMsg.ts index f0b8e41253982f18ac37463e1e3174e0224759f0..7491e84d199781a7711b740656ba9a2577c58675 100644 --- a/ets2panda/linter/src/lib/CookBookMsg.ts +++ b/ets2panda/linter/src/lib/CookBookMsg.ts @@ -88,7 +88,8 @@ cookBookTag[57] = ''; cookBookTag[58] = ''; cookBookTag[59] = '"delete" operator is not supported (arkts-no-delete)'; cookBookTag[60] = '"typeof" operator is allowed only in expression contexts (arkts-no-type-query)'; -cookBookTag[61] = ''; +cookBookTag[61] = + 'The bitwise inversion gives different result for "Infinity" (arkts-distinct-infinity-bitwise-inversion)'; cookBookTag[62] = ''; cookBookTag[63] = ''; cookBookTag[64] = ''; diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index 8ace468f161fd5f32f2aac72700714920a6452b3..58c8941a599ff3d136d6de994b83be9529c8f5f9 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -59,6 +59,7 @@ faultsAttrs[FaultID.JsxElement] = new FaultAttributes(54); faultsAttrs[FaultID.UnaryArithmNotNumber] = new FaultAttributes(55); faultsAttrs[FaultID.DeleteOperator] = new FaultAttributes(59); faultsAttrs[FaultID.TypeQuery] = new FaultAttributes(60); +faultsAttrs[FaultID.PrefixUnaryInfinity] = new FaultAttributes(61); faultsAttrs[FaultID.InstanceofUnsupported] = new FaultAttributes(65); faultsAttrs[FaultID.InOperator] = new FaultAttributes(66); faultsAttrs[FaultID.DestructuringAssignment] = new FaultAttributes(69); diff --git a/ets2panda/linter/src/lib/FaultDesc.ts b/ets2panda/linter/src/lib/FaultDesc.ts index d812eab32339364d3f430dad380008fcffea5ec2..efe074d5050bcd9699312f4039df023c57c4da77 100644 --- a/ets2panda/linter/src/lib/FaultDesc.ts +++ b/ets2panda/linter/src/lib/FaultDesc.ts @@ -82,6 +82,7 @@ faultDesc[FaultID.StructuralIdentity] = 'Use of type structural identity'; faultDesc[FaultID.ExportAssignment] = 'Export assignments (export = ..)'; faultDesc[FaultID.ImportAssignment] = 'Import assignments (import = ..)'; faultDesc[FaultID.GenericCallNoTypeArgs] = 'Generic calls without type arguments'; +faultDesc[FaultID.PrefixUnaryInfinity] = 'Prefix unary infinity'; faultDesc[FaultID.ParameterProperties] = 'Parameter properties in constructor'; faultDesc[FaultID.InstanceofUnsupported] = 'Left-hand side of "instanceof" is wrong'; faultDesc[FaultID.TemplateStringType] = 'Template string type'; diff --git a/ets2panda/linter/src/lib/Problems.ts b/ets2panda/linter/src/lib/Problems.ts index dd700b4ed503bf045a326a84be4b9149e4628771..5d1663e6bac0c3bb8920c9113f84a17d704eef69 100644 --- a/ets2panda/linter/src/lib/Problems.ts +++ b/ets2panda/linter/src/lib/Problems.ts @@ -103,6 +103,7 @@ export enum FaultID { LimitedStdLibApi, LimitedStdLibNoASON, NoNeedStdLibSendableContainer, + PrefixUnaryInfinity, ErrorSuppression, StrictDiagnostic, ImportAfterStatement, diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index fb73dd0e1c0c8d685bd4be1a9eb0ae9290b9e2f7..2cd8cb4cb115ab6346a188833b5c0b291e11797b 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -38,7 +38,8 @@ import { STRINGLITERAL_CHAR, STRINGLITERAL_LONG, STRINGLITERAL_FROM, - STRINGLITERAL_ARRAY + STRINGLITERAL_ARRAY, + STRINGLITERAL_INFINITY } from './utils/consts/StringLiteral'; import { NON_INITIALIZABLE_PROPERTY_CLASS_DECORATORS, @@ -255,6 +256,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private initEtsHandlers(): void { + /* * some syntax elements are ArkTs-specific and are only implemented inside patched * compiler, so we initialize those handlers if corresponding properties do exist @@ -443,7 +445,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { [ts.SyntaxKind.TypeOfExpression, this.handleInterOpImportJsOnTypeOfNode], [ts.SyntaxKind.AwaitExpression, this.handleAwaitExpression], [ts.SyntaxKind.PostfixUnaryExpression, this.handlePostfixUnaryExpression], - [ts.SyntaxKind.BigIntLiteral, this.handleBigIntLiteral], + [ts.SyntaxKind.BigIntLiteral, this.handleBigIntLiteral] ]); lint(): void { @@ -472,6 +474,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } else { const handler = this.handlersMap.get(node.kind); if (handler !== undefined) { + /* * possibly requested cancellation will be checked in a limited number of handlers * checked nodes are selected as construct nodes, similar to how TSC does @@ -579,7 +582,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * X.prototype.prototype.prototype = ... */ const baseExprTypeNode = this.tsTypeChecker.typeToTypeNode(baseExprType, undefined, ts.NodeBuilderFlags.None); - return (baseExprTypeNode && ts.isFunctionTypeNode(baseExprTypeNode)) || TsUtils.isAnyType(baseExprType); + return baseExprTypeNode && ts.isFunctionTypeNode(baseExprTypeNode) || TsUtils.isAnyType(baseExprType); } private interfaceInheritanceLint(node: ts.Node, heritageClauses: ts.NodeArray): void { @@ -653,8 +656,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ): boolean { return ( ts.isPropertyAssignment(prop) || - (ts.isShorthandPropertyAssignment(prop) && - (ts.isCallExpression(objLitExpr.parent) || ts.isNewExpression(objLitExpr.parent))) + ts.isShorthandPropertyAssignment(prop) && + (ts.isCallExpression(objLitExpr.parent) || ts.isNewExpression(objLitExpr.parent)) ); } @@ -716,6 +719,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private handleArrayLiteralExpression(node: ts.Node): void { + /* * If array literal is a part of destructuring assignment, then * don't process it further. @@ -912,6 +916,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const iSymbol = this.tsUtils.trueSymbolAtLocation(interfaceNode.name); const iDecls = iSymbol ? iSymbol.getDeclarations() : null; if (iDecls) { + /* * Since type checker merges all declarations with the same name * into one symbol, we need to check that there's more than one @@ -1195,7 +1200,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleImportModule(importDeclNode); if (this.options.arkts2) { const importClause = importDeclNode.importClause; - if (!importClause || (!importClause.name && !importClause.namedBindings)) { + if (!importClause || !importClause.name && !importClause.namedBindings) { const autofix = this.autofixer?.fixSideEffectImport(importDeclNode); this.incrementCounters(node, FaultID.NoSideEffectImport, autofix); } else { @@ -1273,6 +1278,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const modulePath = importDeclNode.moduleSpecifier.getText().slice(1, -1); if (modulePath.startsWith('./') || modulePath.startsWith('../')) { + /* * Reason for this method to check the oh module imports, * We do not use relative paths when importing from OhModules, @@ -1444,9 +1450,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isBinaryExpression(propertyAccessNode.parent)) { const isAssignment = propertyAccessNode.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken; - const autofix = isAssignment - ? this.autofixer?.fixInteropBinaryExpression(propertyAccessNode.parent) - : this.autofixer?.fixInteropPropertyAccessExpression(propertyAccessNode); + const autofix = isAssignment ? + this.autofixer?.fixInteropBinaryExpression(propertyAccessNode.parent) : + this.autofixer?.fixInteropPropertyAccessExpression(propertyAccessNode); this.incrementCounters( isAssignment ? propertyAccessNode.parent : propertyAccessNode, @@ -1505,9 +1511,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if ( - (baseExprSym && TsUtils.isFunctionSymbol(baseExprSym)) || + baseExprSym && TsUtils.isFunctionSymbol(baseExprSym) || this.tsUtils.isStdFunctionType(baseExprType) || - (TsUtils.isFunctionalType(baseExprType) && TsUtils.isAnonymousType(baseExprType)) + TsUtils.isFunctionalType(baseExprType) && TsUtils.isAnonymousType(baseExprType) ) { this.incrementCounters(node.expression, FaultID.PropertyDeclOnFunction); } @@ -1542,7 +1548,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return false; } if ( - (ts.isTypeAliasDeclaration(decl) && this.checkSpecialTypeNode(decl.type, true)) || + ts.isTypeAliasDeclaration(decl) && this.checkSpecialTypeNode(decl.type, true) || this.checkSpecialTypeNode(decl, true) ) { return true; @@ -1705,7 +1711,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private static extractKeyofFromString(typeString: string): boolean { - return /\bkeyof\b/.test(typeString); + return (/\bkeyof\b/).test(typeString); } checkUnionTypes(propertyAccessNode: ts.PropertyAccessExpression): void { @@ -1771,7 +1777,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private handleLiteralAsPropertyName(node: ts.PropertyDeclaration | ts.PropertySignature): void { const propName = node.name; - if (!!propName && (ts.isNumericLiteral(propName) || (this.options.arkts2 && ts.isStringLiteral(propName)))) { + if (!!propName && (ts.isNumericLiteral(propName) || this.options.arkts2 && ts.isStringLiteral(propName))) { const autofix = this.autofixer?.fixLiteralAsPropertyNamePropertyName(propName); this.incrementCounters(node.name, FaultID.LiteralAsPropertyName, autofix); } @@ -1838,7 +1844,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleQuotedHyphenPropsDeprecated(node); this.handleNoDeprecatedApi(node); const propName = node.name; - if (!propName || !(ts.isNumericLiteral(propName) || (this.options.arkts2 && ts.isStringLiteral(propName)))) { + if (!propName || !(ts.isNumericLiteral(propName) || this.options.arkts2 && ts.isStringLiteral(propName))) { return; } @@ -2190,8 +2196,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const tsRetType = this.tsTypeChecker.getReturnTypeOfSignature(tsSignature); if ( !tsRetType || - (!this.options.arkts2 && TsUtils.isUnsupportedType(tsRetType)) || - (this.options.arkts2 && this.tsUtils.isUnsupportedTypeArkts2(tsRetType)) + !this.options.arkts2 && TsUtils.isUnsupportedType(tsRetType) || + this.options.arkts2 && this.tsUtils.isUnsupportedTypeArkts2(tsRetType) ) { hasLimitedRetTypeInference = true; } else if (hasLimitedRetTypeInference) { @@ -2304,6 +2310,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (this.useStatic && this.options.arkts2) { const tsUnaryArithm = node as ts.PrefixUnaryExpression; this.handleInteropOperand(tsUnaryArithm); + this.handleInfinityIdentifier(tsUnaryArithm); } const tsUnaryOp = tsUnaryArithm.operator; const tsUnaryOperand = tsUnaryArithm.operand; @@ -2328,6 +2335,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } + private handleInfinityIdentifier(node: ts.PrefixUnaryExpression): void { + const identifier = node.operand; + if (identifier.getText() === STRINGLITERAL_INFINITY && node.operator === ts.SyntaxKind.TildeToken) { + this.incrementCounters(node, FaultID.PrefixUnaryInfinity); + } + } + private handleBinaryExpression(node: ts.Node): void { const tsBinaryExpr = node as ts.BinaryExpression; const tsLhsExpr = tsBinaryExpr.left; @@ -2372,7 +2386,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleArkTSPropertyAccess(tsBinaryExpr); this.handleObjectLiteralAssignmentToClass(tsBinaryExpr); this.handleAssignmentNotsLikeSmartType(tsBinaryExpr); - this.checkNumericSemanticsForBinaryExpression(tsBinaryExpr) + this.checkNumericSemanticsForBinaryExpression(tsBinaryExpr); } private checkInterOpImportJsDataCompare(expr: ts.BinaryExpression): void { @@ -2514,7 +2528,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } - private static isNumericInitializer(node: ts.Node): boolean { if (ts.isNumericLiteral(node)) { return true; @@ -2638,7 +2651,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleVariableDeclarationForProp(tsVarDecl); if ( !this.options.useRtLogic || - (ts.isVariableDeclarationList(tsVarDecl.parent) && ts.isVariableStatement(tsVarDecl.parent.parent)) + ts.isVariableDeclarationList(tsVarDecl.parent) && ts.isVariableStatement(tsVarDecl.parent.parent) ) { this.handleDeclarationDestructuring(tsVarDecl); } @@ -2717,8 +2730,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - if (this.tsUtils.isPossiblyImportedFromJS(node.left) || - this.tsUtils.isPossiblyImportedFromJS(node.right)) { + if (this.tsUtils.isPossiblyImportedFromJS(node.left) || this.tsUtils.isPossiblyImportedFromJS(node.right)) { return; } @@ -2734,15 +2746,19 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return true; } - if (ts.isBinaryExpression(node.parent) && + if ( + ts.isBinaryExpression(node.parent) && node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && - ts.isElementAccessExpression(node.parent.left)) { + ts.isElementAccessExpression(node.parent.left) + ) { return true; } - if (ts.isBinaryExpression(node.parent) && + if ( + ts.isBinaryExpression(node.parent) && node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && - this.tsUtils.isNumberArrayType(this.tsTypeChecker.getTypeAtLocation(node.parent.left))) { + this.tsUtils.isNumberArrayType(this.tsTypeChecker.getTypeAtLocation(node.parent.left)) + ) { return true; } @@ -2791,15 +2807,12 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isNumericLiteral(element) && !element.text.includes('.')) { const autofix = this.autofixer?.fixNumericLiteralToFloat(element); this.incrementCounters(element, FaultID.NumericSemantics, autofix); - } - else if (ts.isBinaryExpression(element) && - element.operatorToken.kind === ts.SyntaxKind.SlashToken) { + } else if (ts.isBinaryExpression(element) && element.operatorToken.kind === ts.SyntaxKind.SlashToken) { this.checkNumericSemanticsForDivisionOperation(element); } } } - private checkNumericSemanticsForVariable(node: ts.VariableDeclaration): void { if (!this.options.arkts2 || !node.initializer) { return; @@ -2810,8 +2823,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - if (ts.isBinaryExpression(node.initializer) && - node.initializer.operatorToken.kind === ts.SyntaxKind.BarBarToken) { + if (ts.isBinaryExpression(node.initializer) && node.initializer.operatorToken.kind === ts.SyntaxKind.BarBarToken) { this.checkNumericSemanticsForNullishCoalescing(node.initializer); } else if (ts.isConditionalExpression(node.initializer)) { this.checkNumericSemanticsForTernaryOperator(node.initializer); @@ -2850,9 +2862,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private handleDeclarationDestructuring(decl: ts.VariableDeclaration | ts.ParameterDeclaration): void { const faultId = ts.isVariableDeclaration(decl) ? FaultID.DestructuringDeclaration : FaultID.DestructuringParameter; if (ts.isObjectBindingPattern(decl.name)) { - const autofix = ts.isVariableDeclaration(decl) - ? this.autofixer?.fixObjectBindingPatternDeclarations(decl) - : undefined; + const autofix = ts.isVariableDeclaration(decl) ? + this.autofixer?.fixObjectBindingPatternDeclarations(decl) : + undefined; this.incrementCounters(decl, faultId, autofix); } else if (ts.isArrayBindingPattern(decl.name)) { // Array destructuring is allowed only for Arrays/Tuples and without spread operator. @@ -2869,9 +2881,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { hasNestedObjectDestructuring || TsUtils.destructuringDeclarationHasSpreadOperator(decl.name) ) { - const autofix = ts.isVariableDeclaration(decl) - ? this.autofixer?.fixArrayBindingPatternDeclarations(decl, isArrayOrTuple) - : undefined; + const autofix = ts.isVariableDeclaration(decl) ? + this.autofixer?.fixArrayBindingPatternDeclarations(decl, isArrayOrTuple) : + undefined; this.incrementCounters(decl, faultId, autofix); } } @@ -3341,6 +3353,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * Handle comment directive '@ts-nocheck' */ while ((currentNode as any).expression) { + /* * CC-OFFNXT(no_explicit_any) std lib * Handle comment directive '@ts-nocheck' @@ -3356,9 +3369,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { methodName?: string ): boolean { return heritageClause.types.some((type) => { - const parentName = ts.isPropertyAccessExpression(type.expression) - ? type.expression.name.text - : type.expression.getText(); + const parentName = ts.isPropertyAccessExpression(type.expression) ? + type.expression.name.text : + type.expression.getText(); const fullTypeName = TypeScriptLinter.findFinalExpression(type).getText(); const sdkInfos = this.interfaceMap.get(fullTypeName); if (!sdkInfos || sdkInfos.size === 0) { @@ -3543,6 +3556,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private checkClassDeclarationHeritageClause(hClause: ts.HeritageClause, isSendableClass: boolean): void { for (const tsTypeExpr of hClause.types) { + /* * Always resolve type from 'tsTypeExpr' node, not from 'tsTypeExpr.expression' node, * as for the latter, type checker will return incorrect type result for classes in @@ -3673,10 +3687,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const names = new Set(); if ( - (ts.isFunctionDeclaration(statement) && statement.name && statement.body) || - (ts.isClassDeclaration(statement) && statement.name) || - (ts.isInterfaceDeclaration(statement) && statement.name) || - (ts.isEnumDeclaration(statement) && statement.name) + ts.isFunctionDeclaration(statement) && statement.name && statement.body || + ts.isClassDeclaration(statement) && statement.name || + ts.isInterfaceDeclaration(statement) && statement.name || + ts.isEnumDeclaration(statement) && statement.name ) { names.add(statement.name.text); return names; @@ -4335,7 +4349,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ]; for (const [wrapper, primitive] of typePairs) { - if ((typeStr === wrapper && typeSet.has(primitive)) || (typeStr === primitive && typeSet.has(wrapper))) { + if (typeStr === wrapper && typeSet.has(primitive) || typeStr === primitive && typeSet.has(wrapper)) { return true; } } @@ -4686,6 +4700,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private isStdlibClassVarDecl(ident: ts.Identifier, sym: ts.Symbol): boolean { + /* * Most standard JS classes are defined in TS stdlib as ambient global * variables with interface constructor type and require special check @@ -4736,7 +4751,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if ( - ((tsIdentSym.flags & illegalValues) === 0 && !this.isStdlibClassVarDecl(tsIdentifier, tsIdentSym)) || + (tsIdentSym.flags & illegalValues) === 0 && !this.isStdlibClassVarDecl(tsIdentifier, tsIdentSym) || isStruct(tsIdentSym) || !identiferUseInValueContext(tsIdentifier, tsIdentSym) ) { @@ -4808,8 +4823,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.tsUtils.isOrDerivedFrom(type, TsUtils.isTuple) || this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStdRecordType) || this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStringType) || - (!this.options.arkts2 && - (this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStdMapType) || TsUtils.isIntrinsicObjectType(type))) || + !this.options.arkts2 && + (this.tsUtils.isOrDerivedFrom(type, this.tsUtils.isStdMapType) || TsUtils.isIntrinsicObjectType(type)) || TsUtils.isEnumType(type) || // we allow EsObject here beacuse it is reported later using FaultId.EsObjectType TsUtils.isEsValueType(typeNode) @@ -4862,8 +4877,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.tsUtils.isLibrarySymbol(tsElementAccessExprSymbol) || ts.isArrayLiteralExpression(tsElementAccessExpr.expression) || this.isElementAcessAllowed(tsElemAccessBaseExprType, tsElemAccessArgType) || - (this.options.arkts2 && isGetIndexable) || - (this.options.arkts2 && isSetIndexable) + this.options.arkts2 && isGetIndexable || + this.options.arkts2 && isSetIndexable ) { return; } @@ -5552,6 +5567,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { callLikeExpr: ts.CallExpression | ts.NewExpression | ts.ExpressionWithTypeArguments, callSignature?: ts.Signature ): void { + /* * Note: The PR!716 has led to a significant performance degradation. * Since initial problem was fixed in a more general way, this change @@ -5582,9 +5598,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isNewExpression(callLikeExpr) && this.isNonGenericClass(callLikeExpr)) { return; } - const tsSyntaxKind = ts.isNewExpression(callLikeExpr) - ? ts.SyntaxKind.Constructor - : ts.SyntaxKind.FunctionDeclaration; + const tsSyntaxKind = ts.isNewExpression(callLikeExpr) ? + ts.SyntaxKind.Constructor : + ts.SyntaxKind.FunctionDeclaration; const signFlags = ts.NodeBuilderFlags.WriteTypeArgumentsOfSignature | ts.NodeBuilderFlags.IgnoreErrors; const signDecl = this.tsTypeChecker.signatureToSignatureDeclaration( callSignature, @@ -5602,7 +5618,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const shouldCheck = this.shouldCheckGenericCallExpression(callLikeExpr as ts.CallExpression); if ( this.options.arkts2 && - (ts.isNewExpression(callLikeExpr) || (ts.isCallExpression(callLikeExpr) && shouldCheck)) + (ts.isNewExpression(callLikeExpr) || ts.isCallExpression(callLikeExpr) && shouldCheck) ) { shouldReportError = this.shouldReportGenericTypeArgsError( callLikeExpr, @@ -5699,9 +5715,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * in ArkTS and already have separate check for it. */ if (typeNode.kind === ts.SyntaxKind.UnknownKeyword) { - const autofix = ts.isCallExpression(callLikeExpr) - ? this.autofixer?.fixGenericCallNoTypeArgsForUnknown(callLikeExpr) - : undefined; + const autofix = ts.isCallExpression(callLikeExpr) ? + this.autofixer?.fixGenericCallNoTypeArgsForUnknown(callLikeExpr) : + undefined; this.incrementCounters(callLikeExpr, FaultID.GenericCallNoTypeArgs, autofix); break; } @@ -6001,6 +6017,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { expr, this.tsUtils.isLibraryType(this.tsTypeChecker.getTypeAtLocation(expr.expression)), (diagnostic, errorType) => { + /* * When a diagnostic meets the filter criteria, If it happens in an ets file in the 'oh_modules' directory. * the diagnostic is downgraded to warning. For other files, downgraded to nothing. @@ -6200,8 +6217,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const exprType = this.tsTypeChecker.getTypeAtLocation(tsAsExpr.expression).getNonNullableType(); // check for rule#65: 'number as Number' and 'boolean as Boolean' are disabled if ( - (this.tsUtils.isNumberLikeType(exprType) && this.tsUtils.isStdNumberType(targetType)) || - (TsUtils.isBooleanLikeType(exprType) && this.tsUtils.isStdBooleanType(targetType)) + this.tsUtils.isNumberLikeType(exprType) && this.tsUtils.isStdNumberType(targetType) || + TsUtils.isBooleanLikeType(exprType) && this.tsUtils.isStdBooleanType(targetType) ) { this.incrementCounters(node, FaultID.TypeAssertion); } @@ -6293,7 +6310,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const isRestrictedPrimitive = restrictedPrimitiveTypes.includes(type.kind); const isRestrictedArrayType = type.kind === ts.SyntaxKind.ArrayType || - (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName) && type.typeName.text === 'Array'); + ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName) && type.typeName.text === 'Array'; if (!isRestrictedPrimitive && !isRestrictedArrayType) { return; @@ -6320,7 +6337,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const type = tsAsExpr.type; const isNullAssertion = type.kind === ts.SyntaxKind.NullKeyword || - (ts.isLiteralTypeNode(type) && type.literal.kind === ts.SyntaxKind.NullKeyword) || + ts.isLiteralTypeNode(type) && type.literal.kind === ts.SyntaxKind.NullKeyword || type.getText() === 'null'; if (isNullAssertion) { this.incrementCounters(tsAsExpr, FaultID.InterOpConvertImport); @@ -6553,6 +6570,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private handleSpreadOp(node: ts.Node): void { + /* * spread assignment is disabled * spread element is allowed only for arrays as rest parameter @@ -6647,7 +6665,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { decl: ts.VariableDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration ): boolean | undefined { if ( - ((ts.isVariableDeclaration(decl) && ts.isVariableStatement(decl.parent.parent)) || + (ts.isVariableDeclaration(decl) && ts.isVariableStatement(decl.parent.parent) || ts.isPropertyDeclaration(decl)) && !decl.initializer ) { @@ -6770,6 +6788,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private handleCommentDirectives(sourceFile: ts.SourceFile): void { + /* * We use a dirty hack to retrieve list of parsed comment directives by accessing * internal properties of SourceFile node. @@ -6780,6 +6799,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (pragmas && pragmas instanceof Map) { const noCheckPragma = pragmas.get('ts-nocheck'); if (noCheckPragma) { + /* * The value is either a single entry or an array of entries. * Wrap up single entry with array to simplify processing. @@ -6803,9 +6823,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const range = directive.range as ts.TextRange; const kind: ts.SyntaxKind = - sourceFile.text.slice(range.pos, range.pos + 2) === '/*' - ? ts.SyntaxKind.MultiLineCommentTrivia - : ts.SyntaxKind.SingleLineCommentTrivia; + sourceFile.text.slice(range.pos, range.pos + 2) === '/*' ? + ts.SyntaxKind.MultiLineCommentTrivia : + ts.SyntaxKind.SingleLineCommentTrivia; const commentRange: ts.CommentRange = { pos: range.pos, end: range.end, @@ -6954,7 +6974,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const declPosition = decl.getStart(); if ( decl.getSourceFile().fileName !== node.getSourceFile().fileName || - (declPosition !== undefined && declPosition >= scope.getStart() && declPosition < scope.getEnd()) + declPosition !== undefined && declPosition >= scope.getStart() && declPosition < scope.getEnd() ) { return; } @@ -7151,6 +7171,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { rhsType: ts.Type, rhsExpr: ts.Expression ): boolean { + /* * When resolving the contextual type for return expression in async function, the TS compiler * infers 'PromiseLike' type instead of standard 'Promise' (see following link: @@ -7233,8 +7254,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private isSendableDecoratorValid(decl: ts.FunctionDeclaration | ts.TypeAliasDeclaration): boolean { if ( this.compatibleSdkVersion > SENDBALE_FUNCTION_START_VERSION || - (this.compatibleSdkVersion === SENDBALE_FUNCTION_START_VERSION && - !SENDABLE_FUNCTION_UNSUPPORTED_STAGES_IN_API12.includes(this.compatibleSdkVersionStage)) + this.compatibleSdkVersion === SENDBALE_FUNCTION_START_VERSION && + !SENDABLE_FUNCTION_UNSUPPORTED_STAGES_IN_API12.includes(this.compatibleSdkVersionStage) ) { return true; } @@ -7295,7 +7316,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ts.isExpressionStatement(node.parent) || ts.isVoidExpression(node.parent) || ts.isArrowFunction(node.parent) || - (ts.isConditionalExpression(node.parent) && ts.isExpressionStatement(node.parent.parent)) + ts.isConditionalExpression(node.parent) && ts.isExpressionStatement(node.parent.parent) ) { return; } @@ -7404,7 +7425,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return ts.isFunctionDeclaration(name) || ts.isMethodDeclaration(name); }); const isInternalFunction = decl.name && ts.isIdentifier(decl.name) && interanlFunction.includes(decl.name.text); - if ((isInternalFunction && filterDecl.length > 2) || (!isInternalFunction && filterDecl.length > 1)) { + if (isInternalFunction && filterDecl.length > 2 || !isInternalFunction && filterDecl.length > 1) { this.incrementCounters(decl, FaultID.TsOverload); } } else if (ts.isConstructorDeclaration(decl) && decl.getText()) { @@ -7450,8 +7471,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { t.flags & ts.TypeFlags.StringLike || typeText === 'String' || typeText === 'number' || - (t.flags & ts.TypeFlags.NumberLike && /^\d+$/.test(typeText)) || - (isLiteralInitialized && !hasExplicitTypeAnnotation) || + t.flags & ts.TypeFlags.NumberLike && (/^\d+$/).test(typeText) || + isLiteralInitialized && !hasExplicitTypeAnnotation || t.flags & ts.TypeFlags.EnumLike ); }; @@ -7584,7 +7605,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private evaluateNumericValueFromPrefixUnaryExpression(node: ts.PrefixUnaryExpression): number | null { if (node.operator === ts.SyntaxKind.MinusToken) { - if (ts.isNumericLiteral(node.operand) || (ts.isIdentifier(node.operand) && node.operand.text === 'Infinity')) { + if (ts.isNumericLiteral(node.operand) || ts.isIdentifier(node.operand) && node.operand.text === 'Infinity') { return node.operand.text === 'Infinity' ? Number.NEGATIVE_INFINITY : -Number(node.operand.text); } const operandValue = this.evaluateNumericValue(node.operand); @@ -7599,7 +7620,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const typeNode = node.type; if ( typeNode.kind === ts.SyntaxKind.NumberKeyword || - (ts.isTypeReferenceNode(typeNode) && typeNode.typeName.getText() === 'Number') + ts.isTypeReferenceNode(typeNode) && typeNode.typeName.getText() === 'Number' ) { return this.evaluateNumericValue(node.expression); } @@ -7712,10 +7733,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } if ( - (this.tsUtils.isOrDerivedFrom(lhsType, this.tsUtils.isArray) && - this.tsUtils.isOrDerivedFrom(rhsType, TsUtils.isTuple)) || - (this.tsUtils.isOrDerivedFrom(rhsType, this.tsUtils.isArray) && - this.tsUtils.isOrDerivedFrom(lhsType, TsUtils.isTuple)) + this.tsUtils.isOrDerivedFrom(lhsType, this.tsUtils.isArray) && + this.tsUtils.isOrDerivedFrom(rhsType, TsUtils.isTuple) || + this.tsUtils.isOrDerivedFrom(rhsType, this.tsUtils.isArray) && + this.tsUtils.isOrDerivedFrom(lhsType, TsUtils.isTuple) ) { this.incrementCounters(node, FaultID.NoTuplesArrays); } @@ -7944,7 +7965,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } const text = node.initializer.getText(); - if (!/^\$.+$/.test(text)) { + if (!(/^\$.+$/).test(text)) { return; } @@ -9151,7 +9172,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private shouldWarn(symbol: ts.Symbol): boolean { const parentApiName = this.getLocalApiListItemByKey(SdkNameInfo.ParentApiName); - return (symbol && this.isHeritageClauseisThirdPartyBySymbol(symbol)) || symbol.name === parentApiName; + return symbol && this.isHeritageClauseisThirdPartyBySymbol(symbol) || symbol.name === parentApiName; } private getFinalSymOnQuotedHyphenPropsDeprecated(node: ts.Node): ts.Symbol | undefined { @@ -9199,9 +9220,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private getTypeOfVariable(variable: ts.VariableDeclaration): ts.Symbol | undefined { if (variable.type) { - return ts.isArrayTypeNode(variable.type) - ? this.resolveTypeNodeSymbol(variable.type.elementType) - : this.resolveTypeNodeSymbol(variable.type); + return ts.isArrayTypeNode(variable.type) ? + this.resolveTypeNodeSymbol(variable.type.elementType) : + this.resolveTypeNodeSymbol(variable.type); } return variable.initializer ? this.tsTypeChecker.getTypeAtLocation(variable.initializer).getSymbol() : undefined; } @@ -9644,7 +9665,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return false; } - const propertyName = (ts.isIdentifier(decl.expression.name) && decl.expression.name.text) || ''; + const propertyName = ts.isIdentifier(decl.expression.name) && decl.expression.name.text || ''; if (propertyName !== 'self') { return false; } @@ -9658,13 +9679,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - const importApiName = (ts.isIdentifier(decl.expression.expression) && decl.expression.expression.text) || ''; + const importApiName = ts.isIdentifier(decl.expression.expression) && decl.expression.expression.text || ''; const sdkInfos = importApiName && this.interfaceMap.get(importApiName); if (!sdkInfos) { return; } - const apiName = (ts.isIdentifier(decl.name) && decl.name.text) || ''; + const apiName = ts.isIdentifier(decl.name) && decl.name.text || ''; const matchedApi = [...sdkInfos].find((sdkInfo) => { return sdkInfo.api_name === apiName; }); @@ -9877,7 +9898,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if ( decl && (ts.isFunctionDeclaration(decl) || - (ts.isVariableDeclaration(decl) && decl.initializer && ts.isArrowFunction(decl.initializer))) + ts.isVariableDeclaration(decl) && decl.initializer && ts.isArrowFunction(decl.initializer)) ) { this.incrementCounters(arg, FaultID.InteropJsObjectCallStaticFunc); } @@ -9939,16 +9960,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!TypeScriptLinter.isInForLoopBody(elementAccessExpr)) { return; } - const variableDeclaration = ts.isIdentifier(elementAccessExpr.expression) - ? this.tsUtils.findVariableDeclaration(elementAccessExpr.expression) - : undefined; + const variableDeclaration = ts.isIdentifier(elementAccessExpr.expression) ? + this.tsUtils.findVariableDeclaration(elementAccessExpr.expression) : + undefined; if (!variableDeclaration?.initializer) { return; } - const identifier = ts.isPropertyAccessExpression(variableDeclaration.initializer) - ? (variableDeclaration.initializer.expression as ts.Identifier) - : undefined; + const identifier = ts.isPropertyAccessExpression(variableDeclaration.initializer) ? + (variableDeclaration.initializer.expression as ts.Identifier) : + undefined; if (!identifier) { return; } @@ -9977,9 +9998,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (!this.options.arkts2 || !this.useStatic) { return; } - const objectExpr = ts.isNewExpression(propertyAccess.expression) - ? propertyAccess.expression.expression - : propertyAccess.expression; + const objectExpr = ts.isNewExpression(propertyAccess.expression) ? + propertyAccess.expression.expression : + propertyAccess.expression; // Step 1: Must be either setCloneList or setTransferList if (!TypeScriptLinter.isDeprecatedTaskPoolMethodCall(propertyAccess)) { return; @@ -9998,9 +10019,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } const faultId = - propertyAccess.name.text === DEPRECATED_TASKPOOL_METHOD_SETCLONELIST - ? FaultID.SetCloneListDeprecated - : FaultID.SetTransferListDeprecated; + propertyAccess.name.text === DEPRECATED_TASKPOOL_METHOD_SETCLONELIST ? + FaultID.SetCloneListDeprecated : + FaultID.SetTransferListDeprecated; this.incrementCounters(propertyAccess.name, faultId); } @@ -10015,7 +10036,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { private isTaskPoolTaskCreation(taskpoolExpr: ts.Expression): boolean { if ( ts.isIdentifier(taskpoolExpr) || - (ts.isPropertyAccessExpression(taskpoolExpr) && taskpoolExpr.name.text === STDLIB_TASK_CLASS_NAME) + ts.isPropertyAccessExpression(taskpoolExpr) && taskpoolExpr.name.text === STDLIB_TASK_CLASS_NAME ) { const objectExpr = ts.isIdentifier(taskpoolExpr) ? taskpoolExpr : taskpoolExpr.expression; return this.isTaskPoolReferenceisTaskPoolImportForTaskPoolDeprecatedUsages(objectExpr); @@ -10294,16 +10315,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { */ private isFieldTypeMatchingBetweenDerivedAndBaseClass(derivedType: ts.Type, baseType: ts.Type): boolean { // Split union type strings into trimmed member names - const derivedNames = this.tsTypeChecker - .typeToString(derivedType) - .split('|') - .map((s) => { + const derivedNames = this.tsTypeChecker. + typeToString(derivedType). + split('|'). + map((s) => { return s.trim(); }); - const baseNames = this.tsTypeChecker - .typeToString(baseType) - .split('|') - .map((s) => { + const baseNames = this.tsTypeChecker. + typeToString(baseType). + split('|'). + map((s) => { return s.trim(); }); @@ -10489,7 +10510,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { symbol?.declarations?.some((decl) => { return ( ts.isEnumDeclaration(decl) || - (ts.isVariableDeclaration(decl) && decl.initializer && ts.isEnumDeclaration(decl.initializer)) + ts.isVariableDeclaration(decl) && decl.initializer && ts.isEnumDeclaration(decl.initializer) ); }) ?? false ); @@ -10529,6 +10550,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if (superCall.arguments.length > 1) { + /* * STD Error Type have two constructors * either empty constructor which is just "Error" message @@ -11065,9 +11087,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - const parentType = node.type - ? this.tsTypeChecker.getTypeAtLocation(node.type) - : this.tsTypeChecker.getTypeAtLocation(node.initializer); + const parentType = node.type ? + this.tsTypeChecker.getTypeAtLocation(node.type) : + this.tsTypeChecker.getTypeAtLocation(node.initializer); this.processNestedObjectLiterals(node.initializer, parentType); } @@ -11762,7 +11784,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { }; const isBigIntAndNumberOperand = - (isNumber(leftType) && isBigInt(rightType)) || (isBigInt(leftType) && isNumber(rightType)); + isNumber(leftType) && isBigInt(rightType) || isBigInt(leftType) && isNumber(rightType); if (isBigIntAndNumberOperand) { this.incrementCounters(node, FaultID.NumericBigintCompare); } @@ -11774,7 +11796,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } const literalText = node.getText(); - if (/^0[box]/i.test(literalText)) { + if ((/^0[box]/i).test(literalText)) { this.incrementCounters(node, FaultID.NondecimalBigint); } } @@ -11853,7 +11875,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return binaryOperators.includes(kind); } - private checkArrayUsageWithoutBound(accessExpr: ts.ElementAccessExpression): void { if (this.shouldSkipArrayBoundCheck(accessExpr)) { return; @@ -12030,13 +12051,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName: string, arraySym: ts.Symbol ): { isValidBoundCheck: boolean; isVarModifiedBeforeAccess: boolean } { - const isValidBoundCheck = forNode.condition - ? this.checkBoundCondition(forNode.condition, loopVarName, arraySym) - : false; + const isValidBoundCheck = forNode.condition ? + this.checkBoundCondition(forNode.condition, loopVarName, arraySym) : + false; - const isVarModifiedBeforeAccess = forNode.statement - ? TypeScriptLinter.checkVarModifiedBeforeNode(forNode.statement, accessExpr, loopVarName) - : false; + const isVarModifiedBeforeAccess = forNode.statement ? + TypeScriptLinter.checkVarModifiedBeforeNode(forNode.statement, accessExpr, loopVarName) : + false; return { isValidBoundCheck, isVarModifiedBeforeAccess }; } @@ -12047,13 +12068,13 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName: string, arraySym: ts.Symbol ): { isValidBoundCheck: boolean; isVarModifiedBeforeAccess: boolean } { - const isValidBoundCheck = whileNode.expression - ? this.checkBoundCondition(whileNode.expression, loopVarName, arraySym) - : false; + const isValidBoundCheck = whileNode.expression ? + this.checkBoundCondition(whileNode.expression, loopVarName, arraySym) : + false; - const isVarModifiedBeforeAccess = whileNode.statement - ? TypeScriptLinter.checkVarModifiedBeforeNode(whileNode.statement, accessExpr, loopVarName) - : false; + const isVarModifiedBeforeAccess = whileNode.statement ? + TypeScriptLinter.checkVarModifiedBeforeNode(whileNode.statement, accessExpr, loopVarName) : + false; return { isValidBoundCheck, isVarModifiedBeforeAccess }; } @@ -12064,9 +12085,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName: string, arraySym: ts.Symbol ): { isValidBoundCheck: boolean; isVarModifiedBeforeAccess: boolean } { - const isValidBoundCheck = ifNode.expression - ? this.checkBoundCondition(ifNode.expression, loopVarName, arraySym) - : false; + const isValidBoundCheck = ifNode.expression ? + this.checkBoundCondition(ifNode.expression, loopVarName, arraySym) : + false; let isVarModifiedBeforeAccess = false; const statementBlock = ts.isBlock(ifNode.thenStatement) ? ifNode.thenStatement : undefined; @@ -12114,16 +12135,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { if (ts.isIdentifier(left) && left.text === varName && ts.isNumericLiteral(right)) { const value = parseFloat(right.text); return ( - (operatorToken.kind === ts.SyntaxKind.GreaterThanEqualsToken && value <= 0) || - (operatorToken.kind === ts.SyntaxKind.GreaterThanToken && value < 0) + operatorToken.kind === ts.SyntaxKind.GreaterThanEqualsToken && value <= 0 || + operatorToken.kind === ts.SyntaxKind.GreaterThanToken && value < 0 ); } if (ts.isPropertyAccessExpression(left) && left.name.text === LENGTH_IDENTIFIER && ts.isNumericLiteral(right)) { const constantValue = parseInt(right.text); return ( - (operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0) || - (operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0) + operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0 || + operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0 ); } @@ -12331,10 +12352,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const argType = this.tsTypeChecker.getTypeAtLocation(node); return ( (argType.flags & ts.TypeFlags.NumberLike) !== 0 || - (argType.isUnionOrIntersection() && + argType.isUnionOrIntersection() && argType.types.some((t) => { return t.flags & ts.TypeFlags.NumberLike; - })) + }) ); } @@ -12491,8 +12512,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const constantValue = parseInt(right.text); return ( - (operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0) || - (operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0) + operatorToken.kind === ts.SyntaxKind.LessThanToken && constantValue > 0 || + operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken && constantValue >= 0 ); } @@ -12571,7 +12592,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { accessExpr.parent.operatorToken.kind === ts.SyntaxKind.BarBarToken ) { const defaultValue = accessExpr.parent.right; - return ts.isNumericLiteral(defaultValue) || (ts.isIdentifier(defaultValue) && defaultValue.text === 'undefined'); + return ts.isNumericLiteral(defaultValue) || ts.isIdentifier(defaultValue) && defaultValue.text === 'undefined'; } return false; } diff --git a/ets2panda/linter/src/lib/utils/TsUtils.ts b/ets2panda/linter/src/lib/utils/TsUtils.ts index 54a6bf48a0740d8cabd9bdb957864db482ac97f5..91b0f4a998312ed0752d652b005f9a0b85c40817 100644 --- a/ets2panda/linter/src/lib/utils/TsUtils.ts +++ b/ets2panda/linter/src/lib/utils/TsUtils.ts @@ -3861,16 +3861,16 @@ export class TsUtils { } } - isNumberArrayType(type: ts.Type): boolean { - if (!type.symbol || !this.isGenericArrayType(type)) { - return false; - } - - const typeArguments = this.tsTypeChecker.getTypeArguments(type as ts.TypeReference); - if (!typeArguments || typeArguments.length === 0) { - return false; - } + isNumberArrayType(type: ts.Type): boolean { + if (!type.symbol || !this.isGenericArrayType(type)) { + return false; + } - return (typeArguments[0].flags & ts.TypeFlags.Number) !== 0; + const typeArguments = this.tsTypeChecker.getTypeArguments(type); + if (!typeArguments || typeArguments.length === 0) { + return false; } + + return (typeArguments[0].flags & ts.TypeFlags.Number) !== 0; + } } diff --git a/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts b/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts index 67bafa00b4e4c15453ab47d0648e11bbbcb7e930..a694f58fa004ea8041e4da278f499dab8c55142c 100644 --- a/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts +++ b/ets2panda/linter/src/lib/utils/consts/StringLiteral.ts @@ -25,3 +25,4 @@ export const STRINGLITERAL_ANY = 'ANY'; export const STRINGLITERAL_ENUM = 'enum'; export const STRINGLITERAL_FROM = 'from'; export const STRINGLITERAL_ARRAY = 'Array'; +export const STRINGLITERAL_INFINITY = 'Infinity'; diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets new file mode 100644 index 0000000000000000000000000000000000000000..7d078220853c9ea86f8ea7149435f95af0748872 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +-Infinity !== -1 ; ++Infinity !== -1 ; +Infinity !== -1 ; +~Infinity !== -1 ; diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json new file mode 100644 index 0000000000000000000000000000000000000000..948b846fe04969bf5ccbe8bd9dc4a18559ce0c2c --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.args.json @@ -0,0 +1,19 @@ +{ + "copyright": [ + "Copyright (c) 2025 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "mode": { + "arkts2": "" + } +} diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json new file mode 100644 index 0000000000000000000000000000000000000000..1a7e31f801c7fe8623b71db711009fa4f45fe3e9 --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.arkts2.json @@ -0,0 +1,28 @@ +{ + "copyright": [ + "Copyright (c) 2025 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "result": [ + { + "line": 19, + "column": 1, + "endLine": 19, + "endColumn": 10, + "problem": "PrefixUnaryInfinity", + "suggest": "", + "rule": "The bitwise inversion gives different result for \"Infinity\" (arkts-distinct-infinity-bitwise-inversion)", + "severity": "ERROR" + } + ] +} diff --git a/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json new file mode 100644 index 0000000000000000000000000000000000000000..9f305c86d7ff705098b1e480818e125d5e6e3a4a --- /dev/null +++ b/ets2panda/linter/test/main/arkts-distinct-infinity-bitwise-inversion.ets.json @@ -0,0 +1,17 @@ +{ + "copyright": [ + "Copyright (c) 2025 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "result": [] +} diff --git a/ets2panda/linter/test/main/index_negative.ets.arkts2.json b/ets2panda/linter/test/main/index_negative.ets.arkts2.json old mode 100755 new mode 100644 diff --git a/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json b/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json index fc7c0bef22453fff843456cd7381b91043a58246..f7d3a8c29cdebb57512afa7766c69fbf38b777e3 100644 --- a/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json +++ b/ets2panda/linter/test/main/numeric_semantics.ets.arkts2.json @@ -505,4 +505,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json b/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json index 132354c1a55bc6a6236757955422f049b788e806..da7ce528c0d4732b9dada9fa4a6560cc55b5acf8 100644 --- a/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json +++ b/ets2panda/linter/test/main/numeric_semantics.ets.autofix.json @@ -868,4 +868,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json b/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json index 8248685e059d76fe820075dab0c4a556a403938e..713d6b80a9f80a4a28d04d8144c139d62d844946 100644 --- a/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json +++ b/ets2panda/linter/test/main/numeric_semantics.ets.migrate.json @@ -255,4 +255,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json b/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json old mode 100755 new mode 100644 index 469e417b34ddcd2de0e454c5af3640a973a23250..2d6e11c515f6e34d3f46255fa7b34d289dfe2338 --- a/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json +++ b/ets2panda/linter/test/main/swicth_expr.ets.arkts2.json @@ -1,6 +1,6 @@ { "copyright": [ - "Copyright (c) 2023-2025 Huawei Device Co., Ltd.", + "Copyright (c) 2025 Huawei Device Co., Ltd.", "Licensed under the Apache License, Version 2.0 (the 'License');", "you may not use this file except in compliance with the License.", "You may obtain a copy of the License at",