From f2bd4e56931f7f5c6cbd89b522c97f58c453a8a5 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Wed, 23 Aug 2023 18:18:11 +0300 Subject: [PATCH] [ArkTS Linter] Terminate non-subset recursion in heritage Signed-off-by: Vsevolod Pukhov --- linter-4.2/src/Utils.ts | 8 +++++--- linter-4.2/test/type_declarations.ts | 15 +++++++++++++- .../test/type_declarations.ts.relax.json | 20 +++++++++++++++++++ .../test/type_declarations.ts.strict.json | 20 +++++++++++++++++++ linter/src/utils/TsUtils.ts | 8 +++++--- linter/test/type_declarations.ts | 15 +++++++++++++- linter/test/type_declarations.ts.relax.json | 20 +++++++++++++++++++ linter/test/type_declarations.ts.strict.json | 20 +++++++++++++++++++ 8 files changed, 118 insertions(+), 8 deletions(-) diff --git a/linter-4.2/src/Utils.ts b/linter-4.2/src/Utils.ts index 93d8ab0ed..084e2f3f8 100644 --- a/linter-4.2/src/Utils.ts +++ b/linter-4.2/src/Utils.ts @@ -580,17 +580,19 @@ export class TsUtils { !typeADecl.heritageClauses ) continue; for (let heritageClause of typeADecl.heritageClauses) { - if (this.processParentTypes(heritageClause.types, typeB)) return true; + let processInterfaces = typeA.isClass() ? (heritageClause.token != ts.SyntaxKind.ExtendsKeyword) : true; + if (this.processParentTypes(heritageClause.types, typeB, processInterfaces)) return true; } } return false; } - private processParentTypes(parentTypes: ts.NodeArray, typeB: ts.Type): boolean { + private processParentTypes(parentTypes: ts.NodeArray, typeB: ts.Type, processInterfaces: boolean): boolean { for (let baseTypeExpr of parentTypes) { let baseType = this.tsTypeChecker.getTypeAtLocation(baseTypeExpr); - if (baseType && this.relatedByInheritanceOrIdentical(baseType, typeB)) return true; + if (this.isTypeReference(baseType) && baseType.target !== baseType) baseType = baseType.target; + if (baseType && (baseType.isClass() != processInterfaces) && this.relatedByInheritanceOrIdentical(baseType, typeB)) return true; } return false; } diff --git a/linter-4.2/test/type_declarations.ts b/linter-4.2/test/type_declarations.ts index 376f7f059..3082b3f69 100644 --- a/linter-4.2/test/type_declarations.ts +++ b/linter-4.2/test/type_declarations.ts @@ -94,4 +94,17 @@ function classExpressionTest() { interface Box { contents: any; -} \ No newline at end of file +} + +class BadA implements BadD { } +class BadB extends BadA { } +interface BadD extends BadB { } + +class BadE implements BadE { } + +class Empty { }; + +function heritageRecursionTest() { + let e1: Empty = new BadA(); + let e2: Empty = new BadE(); +} diff --git a/linter-4.2/test/type_declarations.ts.relax.json b/linter-4.2/test/type_declarations.ts.relax.json index 1afccae65..3d5416802 100644 --- a/linter-4.2/test/type_declarations.ts.relax.json +++ b/linter-4.2/test/type_declarations.ts.relax.json @@ -74,6 +74,26 @@ "column": 13, "problem": "AnyType" }, + { + "line": 101, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 103, + "column": 23, + "problem": "ImplementsClass" + }, + { + "line": 108, + "column": 7, + "problem": "StructuralIdentity" + }, + { + "line": 109, + "column": 7, + "problem": "StructuralIdentity" + }, { "line": 42, "column": 11, diff --git a/linter-4.2/test/type_declarations.ts.strict.json b/linter-4.2/test/type_declarations.ts.strict.json index e34d68a7e..6bb3bf580 100644 --- a/linter-4.2/test/type_declarations.ts.strict.json +++ b/linter-4.2/test/type_declarations.ts.strict.json @@ -84,6 +84,26 @@ "column": 13, "problem": "AnyType" }, + { + "line": 101, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 103, + "column": 23, + "problem": "ImplementsClass" + }, + { + "line": 108, + "column": 7, + "problem": "StructuralIdentity" + }, + { + "line": 109, + "column": 7, + "problem": "StructuralIdentity" + }, { "line": 42, "column": 11, diff --git a/linter/src/utils/TsUtils.ts b/linter/src/utils/TsUtils.ts index 614816610..af21be03a 100644 --- a/linter/src/utils/TsUtils.ts +++ b/linter/src/utils/TsUtils.ts @@ -441,17 +441,19 @@ export class TsUtils { !typeADecl.heritageClauses ) continue; for (let heritageClause of typeADecl.heritageClauses) { - if (this.processParentTypes(heritageClause.types, typeB)) return true; + let processInterfaces = typeA.isClass() ? (heritageClause.token != ts.SyntaxKind.ExtendsKeyword) : true; + if (this.processParentTypes(heritageClause.types, typeB, processInterfaces)) return true; } } return false; } - private processParentTypes(parentTypes: ts.NodeArray, typeB: ts.Type): boolean { + private processParentTypes(parentTypes: ts.NodeArray, typeB: ts.Type, processInterfaces: boolean): boolean { for (let baseTypeExpr of parentTypes) { let baseType = this.tsTypeChecker.getTypeAtLocation(baseTypeExpr); - if (baseType && this.relatedByInheritanceOrIdentical(baseType, typeB)) return true; + if (this.isTypeReference(baseType) && baseType.target !== baseType) baseType = baseType.target; + if (baseType && (baseType.isClass() != processInterfaces) && this.relatedByInheritanceOrIdentical(baseType, typeB)) return true; } return false; } diff --git a/linter/test/type_declarations.ts b/linter/test/type_declarations.ts index 376f7f059..3082b3f69 100644 --- a/linter/test/type_declarations.ts +++ b/linter/test/type_declarations.ts @@ -94,4 +94,17 @@ function classExpressionTest() { interface Box { contents: any; -} \ No newline at end of file +} + +class BadA implements BadD { } +class BadB extends BadA { } +interface BadD extends BadB { } + +class BadE implements BadE { } + +class Empty { }; + +function heritageRecursionTest() { + let e1: Empty = new BadA(); + let e2: Empty = new BadE(); +} diff --git a/linter/test/type_declarations.ts.relax.json b/linter/test/type_declarations.ts.relax.json index 1afccae65..3d5416802 100644 --- a/linter/test/type_declarations.ts.relax.json +++ b/linter/test/type_declarations.ts.relax.json @@ -74,6 +74,26 @@ "column": 13, "problem": "AnyType" }, + { + "line": 101, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 103, + "column": 23, + "problem": "ImplementsClass" + }, + { + "line": 108, + "column": 7, + "problem": "StructuralIdentity" + }, + { + "line": 109, + "column": 7, + "problem": "StructuralIdentity" + }, { "line": 42, "column": 11, diff --git a/linter/test/type_declarations.ts.strict.json b/linter/test/type_declarations.ts.strict.json index e34d68a7e..6bb3bf580 100644 --- a/linter/test/type_declarations.ts.strict.json +++ b/linter/test/type_declarations.ts.strict.json @@ -84,6 +84,26 @@ "column": 13, "problem": "AnyType" }, + { + "line": 101, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 103, + "column": 23, + "problem": "ImplementsClass" + }, + { + "line": 108, + "column": 7, + "problem": "StructuralIdentity" + }, + { + "line": 109, + "column": 7, + "problem": "StructuralIdentity" + }, { "line": 42, "column": 11, -- Gitee