diff --git a/linter/lib/TypeScriptLinter.ts b/linter/lib/TypeScriptLinter.ts index a7c3ffb6cb2e9b8fb2911c873aeee3c258626122..d9a5b2d239b3fba6fa613a1ab30c63641b6636d0 100644 --- a/linter/lib/TypeScriptLinter.ts +++ b/linter/lib/TypeScriptLinter.ts @@ -80,7 +80,6 @@ export class TypeScriptLinter { currentErrorLine: number; currentWarningLine: number; - staticBlocks: Set; walkedComments: Set; libraryTypeCallDiagnosticChecker: LibraryTypeCallDiagnosticChecker; @@ -126,7 +125,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 @@ -204,6 +202,7 @@ export class TypeScriptLinter { // In relax mode skip migratable return; } + this.nodeCounters[faultId]++; const { line, character } = this.getLineAndCharacterOfNode(node); if (TypeScriptLinter.ideMode) { @@ -1223,7 +1222,6 @@ export class TypeScriptLinter { this.cancellationToken?.throwIfCancellationRequested(); const tsClassDecl = node as ts.ClassDeclaration; - this.staticBlocks.clear(); if (tsClassDecl.name) { this.countDeclarationsWithDuplicateName(tsClassDecl.name, tsClassDecl); } @@ -1246,6 +1244,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 { @@ -1387,18 +1396,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 70fd4abf2177a2b9a7d245344b0ec084cf9f16e1..3d9a5c6c85b540cee4206956d6ff24d7627716c6 100644 --- a/linter/lib/utils/TsUtils.ts +++ b/linter/lib/utils/TsUtils.ts @@ -1002,7 +1002,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 { @@ -1107,6 +1108,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 0000000000000000000000000000000000000000..0565b43804e5e7a1613c0085aa6960c633cf05a6 --- /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 0000000000000000000000000000000000000000..83ec646e2962f8ba924db5d86c6f3dcbc67c5270 --- /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 0000000000000000000000000000000000000000..cbbe46e47ae71ba4c70e8c1e36ca175fd5ca2b6f --- /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 0000000000000000000000000000000000000000..cbbe46e47ae71ba4c70e8c1e36ca175fd5ca2b6f --- /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