From 85a9662e5670c3cd314a1c014d443b20c38b83d1 Mon Sep 17 00:00:00 2001 From: ZhongNing Date: Wed, 28 May 2025 13:56:25 +0800 Subject: [PATCH 1/2] fix issue for arkts-no-structural-typing Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICAO2K Test scenarios:new tests update to the linter Signed-off-by: ZhongNing --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 41 +++++++++++++++++++ .../linter/test/main/structural_identity.ets | 13 +++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 309d60b1b1..b95d1f60bf 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -5126,6 +5126,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.options.arkts2 && this.tsUtils.needToDeduceStructuralIdentity(targetType, exprType, tsAsExpr.expression, true) ) { + if (this.isExemptedAsExpression(tsAsExpr)) { + return; + } if (!this.tsUtils.isObject(exprType)) { this.incrementCounters(node, FaultID.StructuralIdentity); } @@ -5134,6 +5137,41 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleNoTuplesArrays(node, targetType, exprType); } + private isExemptedAsExpression(node: ts.AsExpression): boolean { + if (!ts.isElementAccessExpression(node.expression)) { + return false; + } + + const sourceType = this.tsTypeChecker.getTypeAtLocation(node.expression); + const targetType = this.tsTypeChecker.getTypeAtLocation(node.type); + const isRecordIndexAccess = (): boolean => { + const exprType = this.tsTypeChecker.getTypeAtLocation(node.expression); + const hasNumberIndex = !!exprType.getNumberIndexType(); + const hasStringIndex = !!exprType.getStringIndexType(); + const hasBooleanIndex = !!exprType.getProperty('true') || !!exprType.getProperty('false'); + + return hasNumberIndex || hasStringIndex || hasBooleanIndex; + }; + + if (isRecordIndexAccess()) { + const targetSymbol = targetType.getSymbol(); + if (targetSymbol && targetSymbol.getName() === 'Array') { + return true; + } + } + const primitiveFlags = ts.TypeFlags.Number | ts.TypeFlags.String | ts.TypeFlags.Boolean; + const objectFlag = ts.TypeFlags.Object; + return ( + sourceType.isUnion() && + sourceType.types.some((t) => { + return t.flags & primitiveFlags; + }) && + sourceType.types.some((t) => { + return t.flags & objectFlag; + }) + ); + } + private handleAsExpressionImport(tsAsExpr: ts.AsExpression): void { const type = tsAsExpr.type; const restrictedTypes = [ @@ -5884,6 +5922,9 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } if (this.tsUtils.needToDeduceStructuralIdentity(lhsType, rhsType, rhsExpr, isStrict)) { + if (ts.isNewExpression(rhsExpr) && ts.isIdentifier(rhsExpr.expression) && rhsExpr.expression.text === 'Promise') { + return; + } this.incrementCounters(field, FaultID.StructuralIdentity); } } diff --git a/ets2panda/linter/test/main/structural_identity.ets b/ets2panda/linter/test/main/structural_identity.ets index eae4133097..406a7fee8e 100644 --- a/ets2panda/linter/test/main/structural_identity.ets +++ b/ets2panda/linter/test/main/structural_identity.ets @@ -692,4 +692,15 @@ interface goodPerson extends IPerson { sayHello:()=> { return new MyObj2() } - } \ No newline at end of file + } + + async function foo1(): Promise{ + + return new Promise(()=>{ + + }); +} + +function foo2(rule:Record){ + let b:Array = rule['123'] as Array +} \ No newline at end of file -- Gitee From ba145076a149411a092290062ef4e3cfd58da91f Mon Sep 17 00:00:00 2001 From: ZhongNing Date: Thu, 29 May 2025 16:34:29 +0800 Subject: [PATCH 2/2] fix issue for arkts-interop-js2s-convert-js-type Issue:https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICBBN9 Test scenarios:new tests update to the linter Signed-off-by: ZhongNing --- ets2panda/linter/src/lib/TypeScriptLinter.ts | 92 ++++++-------- .../test/interop/interop_convert_import.ets | 23 +++- .../interop_convert_import.ets.arkts2.json | 114 +++++++++++++++++- .../interop/interop_convert_import.ets.json | 2 +- .../test/interop/interop_convert_import_js.js | 5 +- .../linter/test/main/structural_identity.ets | 13 +- 6 files changed, 179 insertions(+), 70 deletions(-) diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index b95d1f60bf..854bed47c5 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -5126,9 +5126,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.options.arkts2 && this.tsUtils.needToDeduceStructuralIdentity(targetType, exprType, tsAsExpr.expression, true) ) { - if (this.isExemptedAsExpression(tsAsExpr)) { - return; - } if (!this.tsUtils.isObject(exprType)) { this.incrementCounters(node, FaultID.StructuralIdentity); } @@ -5137,61 +5134,55 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { this.handleNoTuplesArrays(node, targetType, exprType); } - private isExemptedAsExpression(node: ts.AsExpression): boolean { - if (!ts.isElementAccessExpression(node.expression)) { - return false; + private handleAsExpressionImport(tsAsExpr: ts.AsExpression): void { + if (!this.useStatic || !this.options.arkts2) { + return; } - const sourceType = this.tsTypeChecker.getTypeAtLocation(node.expression); - const targetType = this.tsTypeChecker.getTypeAtLocation(node.type); - const isRecordIndexAccess = (): boolean => { - const exprType = this.tsTypeChecker.getTypeAtLocation(node.expression); - const hasNumberIndex = !!exprType.getNumberIndexType(); - const hasStringIndex = !!exprType.getStringIndexType(); - const hasBooleanIndex = !!exprType.getProperty('true') || !!exprType.getProperty('false'); + const type = tsAsExpr.type; + const expression = tsAsExpr.expression; + const restrictedPrimitiveTypes = [ + ts.SyntaxKind.NumberKeyword, + ts.SyntaxKind.BooleanKeyword, + ts.SyntaxKind.StringKeyword, + ts.SyntaxKind.BigIntKeyword, + ts.SyntaxKind.UndefinedKeyword + ]; + this.handleAsExpressionImportNull(tsAsExpr); + const isRestrictedPrimitive = restrictedPrimitiveTypes.includes(type.kind); + const isRestrictedArrayType = + type.kind === ts.SyntaxKind.ArrayType || + ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName) && type.typeName.text === 'Array'; - return hasNumberIndex || hasStringIndex || hasBooleanIndex; - }; + if (!isRestrictedPrimitive && !isRestrictedArrayType) { + return; + } - if (isRecordIndexAccess()) { - const targetSymbol = targetType.getSymbol(); - if (targetSymbol && targetSymbol.getName() === 'Array') { - return true; + let identifier: ts.Identifier | undefined; + if (ts.isIdentifier(expression)) { + identifier = expression; + } else if (ts.isPropertyAccessExpression(expression)) { + identifier = ts.isIdentifier(expression.expression) ? expression.expression : undefined; + } + + if (identifier) { + const sym = this.tsUtils.trueSymbolAtLocation(identifier); + const decl = TsUtils.getDeclaration(sym); + if (decl?.getSourceFile().fileName.endsWith(EXTNAME_JS)) { + this.incrementCounters(tsAsExpr, FaultID.InterOpConvertImport); } } - const primitiveFlags = ts.TypeFlags.Number | ts.TypeFlags.String | ts.TypeFlags.Boolean; - const objectFlag = ts.TypeFlags.Object; - return ( - sourceType.isUnion() && - sourceType.types.some((t) => { - return t.flags & primitiveFlags; - }) && - sourceType.types.some((t) => { - return t.flags & objectFlag; - }) - ); } - private handleAsExpressionImport(tsAsExpr: ts.AsExpression): void { + private handleAsExpressionImportNull(tsAsExpr: ts.AsExpression): void { const type = tsAsExpr.type; - const restrictedTypes = [ - ts.SyntaxKind.NumberKeyword, - ts.SyntaxKind.BooleanKeyword, - ts.SyntaxKind.StringKeyword, - ts.SyntaxKind.BigIntKeyword - ]; - if (this.useStatic && this.options.arkts2 && restrictedTypes.includes(type.kind)) { - const expr = ts.isPropertyAccessExpression(tsAsExpr.expression) ? - tsAsExpr.expression.expression : - tsAsExpr.expression; - - if (ts.isIdentifier(expr)) { - const sym = this.tsUtils.trueSymbolAtLocation(expr); - const decl = TsUtils.getDeclaration(sym); - if (decl?.getSourceFile().fileName.endsWith(EXTNAME_JS)) { - this.incrementCounters(tsAsExpr, FaultID.InterOpConvertImport); - } - } + const isNullAssertion = + type.kind === ts.SyntaxKind.NullKeyword || + ts.isLiteralTypeNode(type) && type.literal.kind === ts.SyntaxKind.NullKeyword || + type.getText() === 'null'; + if (isNullAssertion) { + this.incrementCounters(tsAsExpr, FaultID.InterOpConvertImport); + } } @@ -5922,9 +5913,6 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } if (this.tsUtils.needToDeduceStructuralIdentity(lhsType, rhsType, rhsExpr, isStrict)) { - if (ts.isNewExpression(rhsExpr) && ts.isIdentifier(rhsExpr.expression) && rhsExpr.expression.text === 'Promise') { - return; - } this.incrementCounters(field, FaultID.StructuralIdentity); } } diff --git a/ets2panda/linter/test/interop/interop_convert_import.ets b/ets2panda/linter/test/interop/interop_convert_import.ets index 296d7bb3ed..5aa8263372 100755 --- a/ets2panda/linter/test/interop/interop_convert_import.ets +++ b/ets2panda/linter/test/interop/interop_convert_import.ets @@ -14,9 +14,28 @@ */ 'use static' - import {foo, foo2, foo3, foo4} from "./interop_convert_import_js.js" + import {foo, foo2, foo3, foo4, array_val, null_val, undefined_val} from "./interop_convert_import_js.js" let a: number = foo.num as number let a: boolean = foo2.bool as boolean let a: string = foo3.str as string - let a: bigint = foo4.big as bigint" \ No newline at end of file + let a: bigint = foo4.big as bigint" + +test_helper.test(() => { +return (array_val as Array).toString() === new Array(1, 2, 3).toString();// 扫描出 arkts-interop-js2s-convert-js-type - no pass +}, "array_val as Array === [1, 2, 3]"); + +// convert type - Array +test_helper.test(() => { +return (array_val as number[]).toString() === [1,2,3].toString();// 扫描出 arkts-interop-js2s-convert-js-type - no pass +}, "array_val as Array === [1, 2, 3]"); + +// convert type - null +test_helper.test(() => { +return null_val as null === null;// 扫描出 arkts-interop-js2s-convert-js-type - no pass +}, "null_val as null === null"); + +// convert type - undefined +test_helper.test(() => { +return undefined_val as undefined === undefined; // 扫描出 arkts-interop-js2s-convert-js-type - no pass +}, "undefined_val as undefined === undefined"); \ No newline at end of file diff --git a/ets2panda/linter/test/interop/interop_convert_import.ets.arkts2.json b/ets2panda/linter/test/interop/interop_convert_import.ets.arkts2.json index 8b318f2ad3..d824d726d2 100755 --- a/ets2panda/linter/test/interop/interop_convert_import.ets.arkts2.json +++ b/ets2panda/linter/test/interop/interop_convert_import.ets.arkts2.json @@ -18,7 +18,7 @@ "line": 17, "column": 2, "endLine": 17, - "endColumn": 70, + "endColumn": 106, "problem": "ImportAfterStatement", "suggest": "", "rule": "\"import\" statements after other statements are not allowed (arkts-no-misplaced-imports)", @@ -28,7 +28,7 @@ "line": 17, "column": 2, "endLine": 17, - "endColumn": 70, + "endColumn": 106, "problem": "InterOpImportJs", "suggest": "", "rule": "Importing directly from \"JS\" module is not supported (arkts-interop-js2s-import-js)", @@ -143,6 +143,116 @@ "suggest": "", "rule": "Direct usage of interop JS objects is not supported (arkts-interop-js-object-usage)", "severity": "ERROR" + }, + { + "line": 25, + "column": 9, + "endLine": 25, + "endColumn": 27, + "problem": "InterOpConvertImport", + "suggest": "", + "rule": "Casting interop JS objects to primitive types is not allowed (arkts-interop-js2s-convert-js-type)", + "severity": "ERROR" + }, + { + "line": 25, + "column": 44, + "endLine": 25, + "endColumn": 62, + "problem": "GenericCallNoTypeArgs", + "suggest": "", + "rule": "Type inference in case of generic function calls is limited (arkts-no-inferred-generic-params)", + "severity": "ERROR" + }, + { + "line": 25, + "column": 54, + "endLine": 25, + "endColumn": 55, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 25, + "column": 57, + "endLine": 25, + "endColumn": 58, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 25, + "column": 60, + "endLine": 25, + "endColumn": 61, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 30, + "column": 9, + "endLine": 30, + "endColumn": 30, + "problem": "InterOpConvertImport", + "suggest": "", + "rule": "Casting interop JS objects to primitive types is not allowed (arkts-interop-js2s-convert-js-type)", + "severity": "ERROR" + }, + { + "line": 30, + "column": 48, + "endLine": 30, + "endColumn": 49, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 30, + "column": 50, + "endLine": 30, + "endColumn": 51, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 30, + "column": 52, + "endLine": 30, + "endColumn": 53, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 35, + "column": 8, + "endLine": 35, + "endColumn": 24, + "problem": "InterOpConvertImport", + "suggest": "", + "rule": "Casting interop JS objects to primitive types is not allowed (arkts-interop-js2s-convert-js-type)", + "severity": "ERROR" + }, + { + "line": 40, + "column": 8, + "endLine": 40, + "endColumn": 34, + "problem": "InterOpConvertImport", + "suggest": "", + "rule": "Casting interop JS objects to primitive types is not allowed (arkts-interop-js2s-convert-js-type)", + "severity": "ERROR" } ] } \ No newline at end of file diff --git a/ets2panda/linter/test/interop/interop_convert_import.ets.json b/ets2panda/linter/test/interop/interop_convert_import.ets.json index 1d059f0d38..ac2dfbe6f8 100755 --- a/ets2panda/linter/test/interop/interop_convert_import.ets.json +++ b/ets2panda/linter/test/interop/interop_convert_import.ets.json @@ -18,7 +18,7 @@ "line": 17, "column": 2, "endLine": 17, - "endColumn": 70, + "endColumn": 106, "problem": "ImportAfterStatement", "suggest": "", "rule": "\"import\" statements after other statements are not allowed (arkts-no-misplaced-imports)", diff --git a/ets2panda/linter/test/interop/interop_convert_import_js.js b/ets2panda/linter/test/interop/interop_convert_import_js.js index f3895baaa7..cce72a8fb7 100755 --- a/ets2panda/linter/test/interop/interop_convert_import_js.js +++ b/ets2panda/linter/test/interop/interop_convert_import_js.js @@ -16,4 +16,7 @@ export let foo = {name: 123} export let foo2 = {bool: true} export let foo3 = {str: '123'} -export let foo4 = {big: 123n} \ No newline at end of file +export let foo4 = {big: 123n} +export let array_val = [1, 2, 3]; +export let null_val = null; +export let undefined_val = undefined; \ No newline at end of file diff --git a/ets2panda/linter/test/main/structural_identity.ets b/ets2panda/linter/test/main/structural_identity.ets index 406a7fee8e..eae4133097 100644 --- a/ets2panda/linter/test/main/structural_identity.ets +++ b/ets2panda/linter/test/main/structural_identity.ets @@ -692,15 +692,4 @@ interface goodPerson extends IPerson { sayHello:()=> { return new MyObj2() } - } - - async function foo1(): Promise{ - - return new Promise(()=>{ - - }); -} - -function foo2(rule:Record){ - let b:Array = rule['123'] as Array -} \ No newline at end of file + } \ No newline at end of file -- Gitee