From 315a780dd47a9a9fda3bff0b98655be4f1ba7e73 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Mon, 18 Sep 2023 21:02:34 +0300 Subject: [PATCH] [ArkTS Linter] Permit class as value use in interop calls Signed-off-by: Vsevolod Pukhov --- linter-4.2/src/TypeScriptLinter.ts | 12 ++++++++++ linter-4.2/src/Utils.ts | 4 ++++ linter-4.2/test/class_as_object.ts | 9 +++++++ linter-4.2/test/class_as_object.ts.relax.json | 24 +++++++++---------- .../test/class_as_object.ts.strict.json | 24 +++++++++---------- linter-4.2/test/oh_modules/ohos_factory.ts | 11 +++++++++ linter/src/TypeScriptLinter.ts | 12 ++++++++++ linter/src/utils/TsUtils.ts | 4 ++++ linter/test/class_as_object.ts | 9 +++++++ linter/test/class_as_object.ts.relax.json | 24 +++++++++---------- linter/test/class_as_object.ts.strict.json | 24 +++++++++---------- linter/test/oh_modules/ohos_factory.ts | 11 +++++++++ 12 files changed, 120 insertions(+), 48 deletions(-) create mode 100644 linter-4.2/test/oh_modules/ohos_factory.ts create mode 100644 linter/test/oh_modules/ohos_factory.ts diff --git a/linter-4.2/src/TypeScriptLinter.ts b/linter-4.2/src/TypeScriptLinter.ts index 5fe2f80a4..8d5fc0b42 100644 --- a/linter-4.2/src/TypeScriptLinter.ts +++ b/linter-4.2/src/TypeScriptLinter.ts @@ -1573,6 +1573,18 @@ export class TypeScriptLinter { if ((tsIdentSym.flags & illegalValues) == 0 || !this.identiferUseInValueContext(tsIdentifier)) { return; } + + if ((tsIdentSym.flags & ts.SymbolFlags.Class) != 0) { + let ctxNode: ts.Node = tsIdentifier; + while (ts.isPropertyAccessExpression(ctxNode.parent) || ts.isQualifiedName(ctxNode.parent)) { + ctxNode = ctxNode.parent; + } + ctxNode = ctxNode.parent; + if (ts.isCallExpression(ctxNode) && this.tsUtils.hasLibraryType((ctxNode as ts.CallExpression).expression)) { + return; + } + } + if (tsIdentSym.flags & ts.SymbolFlags.ValueModule) { this.incrementCounters(tsIdentifier, FaultID.NamespaceAsObject); } else { diff --git a/linter-4.2/src/Utils.ts b/linter-4.2/src/Utils.ts index d3b9ecc0a..804e838a2 100644 --- a/linter-4.2/src/Utils.ts +++ b/linter-4.2/src/Utils.ts @@ -1108,6 +1108,10 @@ export class TsUtils { return this.isLibrarySymbol(type.aliasSymbol ?? type.getSymbol()); } + public hasLibraryType(node: ts.Node): boolean { + return this.isLibraryType(this.tsTypeChecker.getTypeAtLocation(node)); + } + public isLibrarySymbol(sym: ts.Symbol | undefined) { if (sym && sym.declarations && sym.declarations.length > 0) { const srcFile = sym.declarations[0].getSourceFile(); diff --git a/linter-4.2/test/class_as_object.ts b/linter-4.2/test/class_as_object.ts index fb5de2dc6..7a20f0a9f 100644 --- a/linter-4.2/test/class_as_object.ts +++ b/linter-4.2/test/class_as_object.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import { Something, SomethingFactory, SomethingBar } from "./oh_modules/ohos_factory"; + class C { static a = 5; static b = 8; @@ -58,3 +60,10 @@ class D { new D(C); type X = D; + +namespace test1 { + class SomethingFoo extends Something { } + + let x = SomethingFactory.getInstance().create(SomethingFoo).beep(); + let y = SomethingFactory.getInstance().create(SomethingBar).beep(); +} diff --git a/linter-4.2/test/class_as_object.ts.relax.json b/linter-4.2/test/class_as_object.ts.relax.json index e0222de36..41ee80cd4 100644 --- a/linter-4.2/test/class_as_object.ts.relax.json +++ b/linter-4.2/test/class_as_object.ts.relax.json @@ -13,62 +13,62 @@ ], "nodes": [ { - "line": 25, + "line": 27, "column": 9, "problem": "ClassAsObject" }, { - "line": 26, + "line": 28, "column": 5, "problem": "ClassAsObject" }, { - "line": 27, + "line": 29, "column": 11, "problem": "ClassAsObject" }, { - "line": 28, + "line": 30, "column": 7, "problem": "ClassAsObject" }, { - "line": 36, + "line": 38, "column": 20, "problem": "TypeQuery" }, { - "line": 37, + "line": 39, "column": 6, "problem": "ClassAsObject" }, { - "line": 40, + "line": 42, "column": 10, "problem": "ClassAsObject" }, { - "line": 43, + "line": 45, "column": 20, "problem": "TypeQuery" }, { - "line": 44, + "line": 46, "column": 8, "problem": "ClassAsObject" }, { - "line": 47, + "line": 49, "column": 12, "problem": "ClassAsObject" }, { - "line": 56, + "line": 58, "column": 20, "problem": "TypeQuery" }, { - "line": 58, + "line": 60, "column": 7, "problem": "ClassAsObject" } diff --git a/linter-4.2/test/class_as_object.ts.strict.json b/linter-4.2/test/class_as_object.ts.strict.json index e0222de36..41ee80cd4 100644 --- a/linter-4.2/test/class_as_object.ts.strict.json +++ b/linter-4.2/test/class_as_object.ts.strict.json @@ -13,62 +13,62 @@ ], "nodes": [ { - "line": 25, + "line": 27, "column": 9, "problem": "ClassAsObject" }, { - "line": 26, + "line": 28, "column": 5, "problem": "ClassAsObject" }, { - "line": 27, + "line": 29, "column": 11, "problem": "ClassAsObject" }, { - "line": 28, + "line": 30, "column": 7, "problem": "ClassAsObject" }, { - "line": 36, + "line": 38, "column": 20, "problem": "TypeQuery" }, { - "line": 37, + "line": 39, "column": 6, "problem": "ClassAsObject" }, { - "line": 40, + "line": 42, "column": 10, "problem": "ClassAsObject" }, { - "line": 43, + "line": 45, "column": 20, "problem": "TypeQuery" }, { - "line": 44, + "line": 46, "column": 8, "problem": "ClassAsObject" }, { - "line": 47, + "line": 49, "column": 12, "problem": "ClassAsObject" }, { - "line": 56, + "line": 58, "column": 20, "problem": "TypeQuery" }, { - "line": 58, + "line": 60, "column": 7, "problem": "ClassAsObject" } diff --git a/linter-4.2/test/oh_modules/ohos_factory.ts b/linter-4.2/test/oh_modules/ohos_factory.ts new file mode 100644 index 000000000..506f00e62 --- /dev/null +++ b/linter-4.2/test/oh_modules/ohos_factory.ts @@ -0,0 +1,11 @@ +export declare class Something { beep(): number } + +export declare class SomethingFactory { + private constructor(); + + public static getInstance(): SomethingFactory; + + public create(smth: { new(): T }): T; +} + +export declare class SomethingBar extends Something {} diff --git a/linter/src/TypeScriptLinter.ts b/linter/src/TypeScriptLinter.ts index 84cba26f7..ff65347c7 100644 --- a/linter/src/TypeScriptLinter.ts +++ b/linter/src/TypeScriptLinter.ts @@ -1293,6 +1293,18 @@ export class TypeScriptLinter { if ((tsIdentSym.flags & illegalValues) == 0 || !identiferUseInValueContext(tsIdentifier)) { return; } + + if ((tsIdentSym.flags & ts.SymbolFlags.Class) != 0) { + let ctxNode: ts.Node = tsIdentifier; + while (ts.isPropertyAccessExpression(ctxNode.parent) || ts.isQualifiedName(ctxNode.parent)) { + ctxNode = ctxNode.parent; + } + ctxNode = ctxNode.parent; + if (ts.isCallExpression(ctxNode) && this.tsUtils.hasLibraryType((ctxNode as ts.CallExpression).expression)) { + return; + } + } + if (tsIdentSym.flags & ts.SymbolFlags.ValueModule) { this.incrementCounters(tsIdentifier, FaultID.NamespaceAsObject); } else { diff --git a/linter/src/utils/TsUtils.ts b/linter/src/utils/TsUtils.ts index 256819a7e..cfaceadae 100644 --- a/linter/src/utils/TsUtils.ts +++ b/linter/src/utils/TsUtils.ts @@ -917,6 +917,10 @@ export class TsUtils { return this.isLibrarySymbol(type.aliasSymbol ?? type.getSymbol()); } + public hasLibraryType(node: ts.Node): boolean { + return this.isLibraryType(this.tsTypeChecker.getTypeAtLocation(node)); + } + public isLibrarySymbol(sym: ts.Symbol | undefined): boolean { if (sym && sym.declarations && sym.declarations.length > 0) { const srcFile = sym.declarations[0].getSourceFile(); diff --git a/linter/test/class_as_object.ts b/linter/test/class_as_object.ts index e65e7ec59..6a8807056 100644 --- a/linter/test/class_as_object.ts +++ b/linter/test/class_as_object.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import { Something, SomethingFactory, SomethingBar } from "./oh_modules/ohos_factory"; + class C { static a = 5 static b = 8 @@ -58,3 +60,10 @@ class D { new D(C) type X = D; + +namespace test1 { + class SomethingFoo extends Something { } + + let x = SomethingFactory.getInstance().create(SomethingFoo).beep(); + let y = SomethingFactory.getInstance().create(SomethingBar).beep(); +} diff --git a/linter/test/class_as_object.ts.relax.json b/linter/test/class_as_object.ts.relax.json index 9a21b256e..2d3f8a850 100644 --- a/linter/test/class_as_object.ts.relax.json +++ b/linter/test/class_as_object.ts.relax.json @@ -13,62 +13,62 @@ ], "nodes": [ { - "line": 25, + "line": 27, "column": 9, "problem": "ClassAsObject" }, { - "line": 26, + "line": 28, "column": 5, "problem": "ClassAsObject" }, { - "line": 27, + "line": 29, "column": 11, "problem": "ClassAsObject" }, { - "line": 28, + "line": 30, "column": 7, "problem": "ClassAsObject" }, { - "line": 36, + "line": 38, "column": 20, "problem": "TypeQuery" }, { - "line": 37, + "line": 39, "column": 6, "problem": "ClassAsObject" }, { - "line": 40, + "line": 42, "column": 12, "problem": "ClassAsObject" }, { - "line": 43, + "line": 45, "column": 20, "problem": "TypeQuery" }, { - "line": 44, + "line": 46, "column": 8, "problem": "ClassAsObject" }, { - "line": 47, + "line": 49, "column": 14, "problem": "ClassAsObject" }, { - "line": 56, + "line": 58, "column": 22, "problem": "TypeQuery" }, { - "line": 58, + "line": 60, "column": 7, "problem": "ClassAsObject" } diff --git a/linter/test/class_as_object.ts.strict.json b/linter/test/class_as_object.ts.strict.json index 9a21b256e..2d3f8a850 100644 --- a/linter/test/class_as_object.ts.strict.json +++ b/linter/test/class_as_object.ts.strict.json @@ -13,62 +13,62 @@ ], "nodes": [ { - "line": 25, + "line": 27, "column": 9, "problem": "ClassAsObject" }, { - "line": 26, + "line": 28, "column": 5, "problem": "ClassAsObject" }, { - "line": 27, + "line": 29, "column": 11, "problem": "ClassAsObject" }, { - "line": 28, + "line": 30, "column": 7, "problem": "ClassAsObject" }, { - "line": 36, + "line": 38, "column": 20, "problem": "TypeQuery" }, { - "line": 37, + "line": 39, "column": 6, "problem": "ClassAsObject" }, { - "line": 40, + "line": 42, "column": 12, "problem": "ClassAsObject" }, { - "line": 43, + "line": 45, "column": 20, "problem": "TypeQuery" }, { - "line": 44, + "line": 46, "column": 8, "problem": "ClassAsObject" }, { - "line": 47, + "line": 49, "column": 14, "problem": "ClassAsObject" }, { - "line": 56, + "line": 58, "column": 22, "problem": "TypeQuery" }, { - "line": 58, + "line": 60, "column": 7, "problem": "ClassAsObject" } diff --git a/linter/test/oh_modules/ohos_factory.ts b/linter/test/oh_modules/ohos_factory.ts new file mode 100644 index 000000000..506f00e62 --- /dev/null +++ b/linter/test/oh_modules/ohos_factory.ts @@ -0,0 +1,11 @@ +export declare class Something { beep(): number } + +export declare class SomethingFactory { + private constructor(); + + public static getInstance(): SomethingFactory; + + public create(smth: { new(): T }): T; +} + +export declare class SomethingBar extends Something {} -- Gitee