From 5bb956ad822af55e97bc00320ae389263ca4cf87 Mon Sep 17 00:00:00 2001 From: Utku Enes GURSEL Date: Tue, 29 Jul 2025 13:07:36 +0300 Subject: [PATCH] array bound check for object arrays Issue: ICPLUV Description: Array bound rule was not scanning the arrays inside another object or class. Signed-off-by: Utku Enes GURSEL --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 375 +++++++++--------- .../ohos_matrix4.ets.arkts2.json | 22 +- .../linter/test/main/runtime_array_bound.ets | 12 + .../main/runtime_array_bound.ets.arkts2.json | 40 ++ .../main/runtime_array_bound.ets.migrate.ets | 12 + .../main/runtime_array_bound.ets.migrate.json | 20 + 6 files changed, 290 insertions(+), 191 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index e535b3251a..60fce68fa6 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -259,7 +259,6 @@ 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 @@ -477,7 +476,6 @@ 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 @@ -585,7 +583,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 { @@ -659,8 +657,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))) ); } @@ -722,7 +720,6 @@ 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. @@ -920,7 +917,6 @@ 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 @@ -1203,7 +1199,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 { @@ -1281,7 +1277,6 @@ 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, @@ -1453,9 +1448,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, @@ -1514,9 +1509,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); } @@ -1551,7 +1546,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; @@ -1714,7 +1709,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 { @@ -1780,7 +1775,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); } @@ -1848,7 +1843,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; } @@ -2201,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) { @@ -2750,7 +2745,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); } @@ -2803,9 +2798,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. @@ -2822,9 +2817,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); } } @@ -3293,7 +3288,6 @@ 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' @@ -3309,9 +3303,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) { @@ -3496,7 +3490,6 @@ 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 @@ -3627,10 +3620,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; @@ -3845,24 +3838,31 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } - private checkMethodType(allBaseTypes: ts.Type[], methodName: string, node: ts.MethodDeclaration, isStatic: boolean = false): void { + private checkMethodType( + allBaseTypes: ts.Type[], + methodName: string, + node: ts.MethodDeclaration, + isStatic: boolean = false + ): void { for (const baseType of allBaseTypes) { let baseMethod: ts.Symbol | undefined; - const symbol = baseType.getSymbol(); + const symbol = baseType.getSymbol(); if (isStatic && symbol) { const constructorType = this.tsTypeChecker.getTypeOfSymbolAtLocation(symbol, node); - baseMethod = constructorType.getProperty(methodName) || - symbol.members?.get(ts.escapeLeadingUnderscores(methodName)); + baseMethod = + constructorType.getProperty(methodName) || symbol.members?.get(ts.escapeLeadingUnderscores(methodName)); } else { baseMethod = baseType.getProperty(methodName); } if (!baseMethod) { continue; } - const baseMethodDecl = baseMethod.declarations?.find(d => - (ts.isMethodDeclaration(d) || ts.isMethodSignature(d)) && - this.isSameDeclarationType(d.parent, baseType, isStatic) - ) as ts.MethodDeclaration | ts.MethodSignature; + const baseMethodDecl = baseMethod.declarations?.find((d) => { + return ( + (ts.isMethodDeclaration(d) || ts.isMethodSignature(d)) && + this.isSameDeclarationType(d.parent, baseType, isStatic) + ); + }) as ts.MethodDeclaration | ts.MethodSignature; if (!baseMethodDecl) { continue; @@ -4022,7 +4022,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { }); } } - return [...resolvedBaseClasses, ...interfaces]; + return [...resolvedBaseClasses, ...interfaces]; } private getStaticAllBaseTypes(classDecl: ts.ClassDeclaration): ts.Type[] | undefined { @@ -4093,7 +4093,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { derivedMethod: ts.MethodDeclaration, baseMethod: ts.MethodDeclaration | ts.MethodSignature ): void { - if(this.shouldSkipTypeParameterCheck(derivedMethod, baseMethod)) { + if (this.shouldSkipTypeParameterCheck(derivedMethod, baseMethod)) { return; } const baseMethodType = this.getActualReturnType(baseMethod); @@ -4144,8 +4144,8 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { ): boolean { const baseMethodType = this.getActualReturnType(baseMethod); const derivedMethodType = this.getActualReturnType(derivedMethod); - - if (baseMethodType && (baseMethodType.flags & ts.TypeFlags.TypeParameter)) { + + if (baseMethodType && baseMethodType.flags & ts.TypeFlags.TypeParameter) { if (derivedMethodType && !(derivedMethodType.flags & ts.TypeFlags.TypeParameter)) { return true; } @@ -4263,7 +4263,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; } } @@ -4614,7 +4614,6 @@ 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 @@ -4665,7 +4664,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) ) { @@ -4737,8 +4736,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) @@ -4791,8 +4790,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; } @@ -5553,7 +5552,6 @@ 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 @@ -5584,9 +5582,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, @@ -5604,7 +5602,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, @@ -5701,9 +5699,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; } @@ -6003,7 +6001,6 @@ 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. @@ -6203,8 +6200,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); } @@ -6296,7 +6293,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; @@ -6323,7 +6320,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); @@ -6556,7 +6553,6 @@ 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 @@ -6651,7 +6647,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 ) { @@ -6774,7 +6770,6 @@ 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. @@ -6785,7 +6780,6 @@ 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. @@ -6809,9 +6803,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, @@ -6960,7 +6954,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; } @@ -7157,7 +7151,6 @@ 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: @@ -7240,8 +7233,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; } @@ -7302,7 +7295,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; } @@ -7411,7 +7404,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()) { @@ -7457,8 +7450,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 ); }; @@ -7591,7 +7584,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); @@ -7606,7 +7599,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); } @@ -7719,10 +7712,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); } @@ -7951,7 +7944,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } const text = node.initializer.getText(); - if (!(/^\$.+$/).test(text)) { + if (!/^\$.+$/.test(text)) { return; } @@ -8207,7 +8200,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } } - /** + /** * Ensures classes fully implement all properties from their interfaces. */ private handleInterfaceFieldImplementation(clause: ts.HeritageClause): void { @@ -9164,7 +9157,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 { @@ -9212,9 +9205,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; } @@ -9631,7 +9624,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; } @@ -9645,13 +9638,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; }); @@ -9864,7 +9857,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); } @@ -9926,16 +9919,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; } @@ -9964,9 +9957,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; @@ -9985,9 +9978,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); } @@ -10002,7 +9995,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); @@ -10265,16 +10258,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(); }); @@ -10454,7 +10447,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 ); @@ -10494,7 +10487,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } if (superCall.arguments.length > 1) { - /* * STD Error Type have two constructors * either empty constructor which is just "Error" message @@ -11031,9 +11023,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); } @@ -11745,7 +11737,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); } @@ -11757,7 +11749,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); } } @@ -11854,11 +11846,11 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { }; const isStandardFloatFormat = (): boolean => { const text = node.getText(); - return (/\.\d*0+$/).test(text); + return /\.\d*0+$/.test(text); }; const isNoNeedFix = isInElementAccessExpression(node) || - 'name' in node.parent && node.parent.name === node || + ('name' in node.parent && node.parent.name === node) || isStandardFloatFormat(); if (isNoNeedFix) { return; @@ -11866,7 +11858,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { const value = parseFloat(node.text); const nodeText = node.getText(); - const hasScientificOrRadixNotation = (/[a-zA-Z]/).test(nodeText); + const hasScientificOrRadixNotation = /[a-zA-Z]/.test(nodeText); const isIntegerWithoutZero = Number.isInteger(value) && !nodeText.endsWith('.0'); if (isIntegerWithoutZero && !hasScientificOrRadixNotation) { const autofix = this.autofixer?.fixNumericLiteralIntToNumber(node); @@ -11935,6 +11927,11 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return true; } } + + if (ts.isNumericLiteral(accessExpr.argumentExpression)) { + return false; + } + if (this.isObjectPropertyAccess(accessExpr)) { return true; } @@ -11951,7 +11948,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } return; } - const { arrayIdent } = arrayAccessInfo; const arraySym = this.tsUtils.trueSymbolAtLocation(arrayIdent); if (!arraySym) { @@ -11961,12 +11957,10 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.incrementCounters(accessExpr, FaultID.RuntimeArrayCheck); return; } - const arrayDecl = TypeScriptLinter.findArrayDeclaration(arraySym); if (arrayDecl && TypeScriptLinter.isArrayCreatedWithOtherArrayLength(arrayDecl)) { return; } - const indexExpr = accessExpr.argumentExpression; const loopVarName = ts.isIdentifier(indexExpr) ? indexExpr.text : undefined; if (ts.isPrefixUnaryExpression(indexExpr) && indexExpr.operator === ts.SyntaxKind.PlusPlusToken) { @@ -11978,18 +11972,16 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { loopVarName, arraySym ); - if (TypeScriptLinter.isIncrementOrDecrement(indexExpr)) { return; } - if (isInSafeContext) { if (!isValidBoundCheck || isVarModifiedBeforeAccess) { this.incrementCounters(arrayIdent.parent, FaultID.RuntimeArrayCheck); } - } else { - this.incrementCounters(arrayIdent.parent, FaultID.RuntimeArrayCheck); + return; } + this.incrementCounters(arrayIdent.parent, FaultID.RuntimeArrayCheck); } static isIncrementOrDecrement(expr: ts.Expression): boolean { @@ -12081,13 +12073,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 }; } @@ -12098,13 +12090,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 }; } @@ -12115,9 +12107,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; @@ -12165,16 +12157,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) ); } @@ -12345,56 +12337,58 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { } private getArrayAccessInfo(expr: ts.ElementAccessExpression): false | ArrayAccess { - if (!ts.isIdentifier(expr.expression)) { + let accessedExpression: ts.Node = expr.expression; + if (ts.isPropertyAccessExpression(accessedExpression)) { + accessedExpression = accessedExpression.name; + } + if (!ts.isIdentifier(accessedExpression)) { return false; } - const baseType = this.tsTypeChecker.getTypeAtLocation(expr.expression); - if (!this.tsUtils.isArray(baseType) && !this.isConcatArray(expr.expression)) { + const baseType = this.tsTypeChecker.getTypeAtLocation(accessedExpression); + if (!this.tsUtils.isArray(baseType) && !this.isConcatArray(accessedExpression)) { return false; } - const accessArgument = expr.argumentExpression; + const accessArgument = expr.argumentExpression; if (this.isInstanceOfCheck(expr.parent, expr)) { return false; } - TypeScriptLinter.isFunctionCall(accessArgument); - - const checkNumericType = (node: ts.Node): boolean => { - const argType = this.tsTypeChecker.getTypeAtLocation(node); - return ( - (argType.flags & ts.TypeFlags.NumberLike) !== 0 || - argType.isUnionOrIntersection() && - argType.types.some((t) => { - return t.flags & ts.TypeFlags.NumberLike; - }) - ); - }; - - const isEnumMember = (node: ts.Node): boolean => { - if (ts.isPropertyAccessExpression(node)) { - const symbol = this.tsUtils.trueSymbolAtLocation(node); - return !!symbol && (symbol.flags & ts.SymbolFlags.EnumMember) !== 0; - } - return false; - }; - if (TypeScriptLinter.isFunctionCall(accessArgument)) { return false; } - if (checkNumericType(accessArgument) || isEnumMember(accessArgument)) { + if (this.checkNumericType(accessArgument) || this.isEnumMember(accessArgument)) { return { pos: expr.getEnd(), accessingIdentifier: accessArgument, - arrayIdent: expr.expression + arrayIdent: accessedExpression }; } return false; } + private checkNumericType(node: ts.Node): boolean { + const argType = this.tsTypeChecker.getTypeAtLocation(node); + return ( + (argType.flags & ts.TypeFlags.NumberLike) !== 0 || + (argType.isUnionOrIntersection() && + argType.types.some((t) => { + return t.flags & ts.TypeFlags.NumberLike; + })) + ); + } + + private isEnumMember(node: ts.Node): boolean { + if (ts.isPropertyAccessExpression(node)) { + const symbol = this.tsUtils.trueSymbolAtLocation(node); + return !!symbol && (symbol.flags & ts.SymbolFlags.EnumMember) !== 0; + } + return false; + } + static isArrayCreatedWithOtherArrayLength(decl: ts.VariableDeclaration): boolean { if (!decl.initializer || !ts.isNewExpression(decl.initializer)) { return false; @@ -12540,8 +12534,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) ); } @@ -12620,7 +12614,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; } @@ -12781,11 +12775,12 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return true; } current = current.expression; - } else if (ts.isPropertyAccessExpression(current)) { + continue; + } + if (ts.isPropertyAccessExpression(current)) { return true; - } else { - break; } + break; } return false; @@ -13483,7 +13478,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return true; } - private handleESObjectUsage(typeRef: ts.TypeReferenceNode): void { + private handleESObjectUsage(typeRef: ts.TypeReferenceNode): void { if (!this.options.arkts2) { return; } diff --git a/ets2panda/linter/test/deprecatedapi/ohos_matrix4.ets.arkts2.json b/ets2panda/linter/test/deprecatedapi/ohos_matrix4.ets.arkts2.json index c3cf76ae53..119d080a26 100755 --- a/ets2panda/linter/test/deprecatedapi/ohos_matrix4.ets.arkts2.json +++ b/ets2panda/linter/test/deprecatedapi/ohos_matrix4.ets.arkts2.json @@ -104,6 +104,26 @@ "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)", "severity": "ERROR" }, + { + "line": 31, + "column": 52, + "endLine": 31, + "endColumn": 68, + "problem": "RuntimeArrayCheck", + "suggest": "", + "rule": "Array bound not checked. (arkts-runtime-array-check)", + "severity": "ERROR" + }, + { + "line": 31, + "column": 73, + "endLine": 31, + "endColumn": 89, + "problem": "RuntimeArrayCheck", + "suggest": "", + "rule": "Array bound not checked. (arkts-runtime-array-check)", + "severity": "ERROR" + }, { "line": 32, "column": 3, @@ -235,4 +255,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets b/ets2panda/linter/test/main/runtime_array_bound.ets index 33c5e11fbf..6e495cef33 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets +++ b/ets2panda/linter/test/main/runtime_array_bound.ets @@ -308,3 +308,15 @@ for (let i = 0; i < concatArray.length; i++) { if (concatArray.length > 10) { concatArray[10] }; + +class DummyClass { + public a1: Array = new Array(); + + foo() { + this.a1[123] = 123; + } +} + +let dc = new DummyClass(); + +dc.a1[123] = 1234; diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json b/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json index eeab471943..6b6a89fb8a 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.arkts2.json @@ -2553,6 +2553,46 @@ "suggest": "", "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" + }, + { + "line": 316, + "column": 9, + "endLine": 316, + "endColumn": 16, + "problem": "RuntimeArrayCheck", + "suggest": "", + "rule": "Array bound not checked. (arkts-runtime-array-check)", + "severity": "ERROR" + }, + { + "line": 316, + "column": 24, + "endLine": 316, + "endColumn": 27, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 322, + "column": 1, + "endLine": 322, + "endColumn": 6, + "problem": "RuntimeArrayCheck", + "suggest": "", + "rule": "Array bound not checked. (arkts-runtime-array-check)", + "severity": "ERROR" + }, + { + "line": 322, + "column": 14, + "endLine": 322, + "endColumn": 18, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" } ] } diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets index 5531ae7190..eca7e15901 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.ets @@ -308,3 +308,15 @@ for (let i: number = 0.0; i < concatArray.length; i++) { if (concatArray.length > 10.0) { concatArray[10] }; + +class DummyClass { + public a1: Array = new Array(); + + foo() { + this.a1[123] = 123.0; + } +} + +let dc = new DummyClass(); + +dc.a1[123] = 1234.0; diff --git a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json index 84420569c7..31242ad2a5 100644 --- a/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json +++ b/ets2panda/linter/test/main/runtime_array_bound.ets.migrate.json @@ -243,6 +243,26 @@ "suggest": "", "rule": "Array bound not checked. (arkts-runtime-array-check)", "severity": "ERROR" + }, + { + "line": 316, + "column": 9, + "endLine": 316, + "endColumn": 16, + "problem": "RuntimeArrayCheck", + "suggest": "", + "rule": "Array bound not checked. (arkts-runtime-array-check)", + "severity": "ERROR" + }, + { + "line": 322, + "column": 1, + "endLine": 322, + "endColumn": 6, + "problem": "RuntimeArrayCheck", + "suggest": "", + "rule": "Array bound not checked. (arkts-runtime-array-check)", + "severity": "ERROR" } ] } -- Gitee