From 2411271cb97a9f3a633d40cd01b72a3e3a189d87 Mon Sep 17 00:00:00 2001 From: Evgeniy Okolnov Date: Tue, 23 Jan 2024 00:02:02 +0300 Subject: [PATCH] [ArkTS Linter] Fix #15431: Multiple static blocks Change-Id: I309144c01622858237db225f3e4f6a7a2c8d166f Signed-off-by: Evgeniy Okolnov --- linter/lib/TypeScriptLinter.ts | 25 +++++---- linter/lib/utils/TsUtils.ts | 7 ++- linter/test_regression/15431.ts | 58 ++++++++++++++++++++ linter/test_regression/15431.ts.autofix.skip | 14 +++++ linter/test_regression/15431.ts.relax.json | 39 +++++++++++++ linter/test_regression/15431.ts.strict.json | 39 +++++++++++++ 6 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 linter/test_regression/15431.ts create mode 100644 linter/test_regression/15431.ts.autofix.skip create mode 100644 linter/test_regression/15431.ts.relax.json create mode 100644 linter/test_regression/15431.ts.strict.json diff --git a/linter/lib/TypeScriptLinter.ts b/linter/lib/TypeScriptLinter.ts index 27000657..4f49e26a 100644 --- a/linter/lib/TypeScriptLinter.ts +++ b/linter/lib/TypeScriptLinter.ts @@ -84,7 +84,6 @@ export class TypeScriptLinter { currentErrorLine: number; currentWarningLine: number; - staticBlocks: Set; walkedComments: Set; libraryTypeCallDiagnosticChecker: LibraryTypeCallDiagnosticChecker; @@ -130,7 +129,6 @@ export class TypeScriptLinter { this.tsUtils = new TsUtils(this.tsTypeChecker, TypeScriptLinter.testMode, TypeScriptLinter.advancedClassChecks); this.currentErrorLine = 0; this.currentWarningLine = 0; - this.staticBlocks = new Set(); this.walkedComments = new Set(); this.libraryTypeCallDiagnosticChecker = new LibraryTypeCallDiagnosticChecker( TypeScriptLinter.filteredDiagnosticMessages @@ -208,6 +206,7 @@ export class TypeScriptLinter { // In relax mode skip migratable return; } + this.nodeCounters[faultId]++; const { line, character } = this.getLineAndCharacterOfNode(node); if (TypeScriptLinter.ideMode) { @@ -1233,7 +1232,6 @@ export class TypeScriptLinter { this.cancellationToken?.throwIfCancellationRequested(); const tsClassDecl = node as ts.ClassDeclaration; - this.staticBlocks.clear(); if (tsClassDecl.name) { this.countDeclarationsWithDuplicateName(tsClassDecl.name, tsClassDecl); } @@ -1256,6 +1254,17 @@ export class TypeScriptLinter { visitHClause(hClause); } } + + let hasStaticBlock = false; + for (const element of tsClassDecl.members) { + if (ts.isClassStaticBlockDeclaration(element)) { + if (hasStaticBlock) { + this.incrementCounters(element, FaultID.MultipleStaticBlocks); + } else { + hasStaticBlock = true; + } + } + } } private handleModuleDeclaration(node: ts.Node): void { @@ -1397,18 +1406,10 @@ export class TypeScriptLinter { private handleClassStaticBlockDeclaration(node: ts.Node): void { const classStaticBlockDecl = node as ts.ClassStaticBlockDeclaration; - const parent = classStaticBlockDecl.parent; - if (!ts.isClassDeclaration(parent)) { + if (!ts.isClassDeclaration(classStaticBlockDecl.parent)) { return; } this.reportThisKeywordsInScope(classStaticBlockDecl.body); - // May be undefined in `export default class { ... }`. - const className = parent.name?.text ?? ''; - if (this.staticBlocks.has(className)) { - this.incrementCounters(classStaticBlockDecl, FaultID.MultipleStaticBlocks); - } else { - this.staticBlocks.add(className); - } } private handleIdentifier(node: ts.Node): void { diff --git a/linter/lib/utils/TsUtils.ts b/linter/lib/utils/TsUtils.ts index b2782b14..49725d12 100644 --- a/linter/lib/utils/TsUtils.ts +++ b/linter/lib/utils/TsUtils.ts @@ -1005,7 +1005,8 @@ export class TsUtils { [FaultID.FunctionApplyCall, TsUtils.getFunctionApplyCallHighlightRange], [FaultID.DeclWithDuplicateName, TsUtils.getDeclWithDuplicateNameHighlightRange], [FaultID.ObjectLiteralNoContextType, TsUtils.getObjectLiteralNoContextTypeHighlightRange], - [FaultID.ClassExpression, TsUtils.getClassExpressionHighlightRange] + [FaultID.ClassExpression, TsUtils.getClassExpressionHighlightRange], + [FaultID.MultipleStaticBlocks, TsUtils.getMultipleStaticBlocksHighlightRange] ]); static getVarDeclarationHighlightRange(nodeOrComment: ts.Node | ts.CommentRange): [number, number] | undefined { @@ -1110,6 +1111,10 @@ export class TsUtils { return this.getKeywordHighlightRange(nodeOrComment, 'class'); } + static getMultipleStaticBlocksHighlightRange(nodeOrComment: ts.Node | ts.CommentRange): [number, number] | undefined { + return this.getKeywordHighlightRange(nodeOrComment, 'static'); + } + static getKeywordHighlightRange(nodeOrComment: ts.Node | ts.CommentRange, keyword: string): [number, number] { const start = this.getStartPos(nodeOrComment); return [start, start + keyword.length]; diff --git a/linter/test_regression/15431.ts b/linter/test_regression/15431.ts new file mode 100644 index 00000000..0565b438 --- /dev/null +++ b/linter/test_regression/15431.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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. + */ + +class C1 { + static a: number = 1; + + static { + } + + static { // should report error `arkts-no-multiple-static-blocks` + } +} + +class C2 { + static a: number = 1; + + static { + this.a; // should report error arkts-no-standalone-this + } +} + +class C3 { + static a: number = 1; + + static { + class C3 { + } + } + + static { // should report error + } +} + +class C4 { + static a: number = 1; + + static f() { + class C4 { + static { + } + } + } + + static { // shouldn't report error + } +} \ No newline at end of file diff --git a/linter/test_regression/15431.ts.autofix.skip b/linter/test_regression/15431.ts.autofix.skip new file mode 100644 index 00000000..83ec646e --- /dev/null +++ b/linter/test_regression/15431.ts.autofix.skip @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 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. + */ diff --git a/linter/test_regression/15431.ts.relax.json b/linter/test_regression/15431.ts.relax.json new file mode 100644 index 00000000..cbbe46e4 --- /dev/null +++ b/linter/test_regression/15431.ts.relax.json @@ -0,0 +1,39 @@ +{ + "copyright": [ + "Copyright (c) 2024 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." + ], + "nodes": [ + { + "line": 22, + "column": 3, + "problem": "MultipleStaticBlocks", + "suggest": "", + "rule": "Only one static block is supported (arkts-no-multiple-static-blocks)" + }, + { + "line": 30, + "column": 5, + "problem": "FunctionContainsThis", + "suggest": "", + "rule": "Using \"this\" inside stand-alone functions is not supported (arkts-no-standalone-this)" + }, + { + "line": 42, + "column": 3, + "problem": "MultipleStaticBlocks", + "suggest": "", + "rule": "Only one static block is supported (arkts-no-multiple-static-blocks)" + } + ] +} \ No newline at end of file diff --git a/linter/test_regression/15431.ts.strict.json b/linter/test_regression/15431.ts.strict.json new file mode 100644 index 00000000..cbbe46e4 --- /dev/null +++ b/linter/test_regression/15431.ts.strict.json @@ -0,0 +1,39 @@ +{ + "copyright": [ + "Copyright (c) 2024 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." + ], + "nodes": [ + { + "line": 22, + "column": 3, + "problem": "MultipleStaticBlocks", + "suggest": "", + "rule": "Only one static block is supported (arkts-no-multiple-static-blocks)" + }, + { + "line": 30, + "column": 5, + "problem": "FunctionContainsThis", + "suggest": "", + "rule": "Using \"this\" inside stand-alone functions is not supported (arkts-no-standalone-this)" + }, + { + "line": 42, + "column": 3, + "problem": "MultipleStaticBlocks", + "suggest": "", + "rule": "Only one static block is supported (arkts-no-multiple-static-blocks)" + } + ] +} \ No newline at end of file -- Gitee