From 88b305528d6b4870d6a9e4acb59eb10b2df62e72 Mon Sep 17 00:00:00 2001 From: Utku Enes GURSEL Date: Wed, 2 Jul 2025 19:04:09 +0300 Subject: [PATCH] rewrite super-call checking rule Issue: ICJKKN Description: Old implementation just looked at if there is any super with args, new rule checks the types and tries to see if they are matching, also checks if there is multiple constructors. Signed-off-by: Utku Enes GURSEL --- ets2panda/linter/src/lib/FaultAttrs.ts | 2 +- ets2panda/linter/src/lib/TypeScriptLinter.ts | 268 +++++++++++++++--- .../linter/src/lib/autofixes/Autofixer.ts | 35 ++- .../src/lib/utils/consts/ArkuiImportList.ts | 70 ++--- .../linter/src/lib/utils/consts/ErrorProp.ts | 1 - .../linter/src/lib/utils/consts/Types.ts | 37 +++ .../lib/utils/consts/WorkloadRelatedConst.ts | 2 +- .../test/main/explicit_function_type.ets | 6 +- .../explicit_function_type.ets.arkts2.json | 12 +- .../explicit_function_type.ets.autofix.json | 74 +++-- .../test/main/explicit_function_type.ets.json | 42 ++- .../explicit_function_type.ets.migrate.ets | 6 +- .../explicit_function_type.ets.migrate.json | 12 +- ...object_literals_properties.ets.arkts2.json | 16 +- ...bject_literals_properties.ets.autofix.json | 16 +- ...bject_literals_properties.ets.migrate.json | 26 +- .../linter/test/main/subclass_super_call.ets | 48 +++- .../main/subclass_super_call.ets.args.json | 2 +- .../main/subclass_super_call.ets.arkts2.json | 142 +++++++--- 19 files changed, 574 insertions(+), 243 deletions(-) create mode 100644 ets2panda/linter/src/lib/utils/consts/Types.ts mode change 100755 => 100644 ets2panda/linter/test/main/explicit_function_type.ets.arkts2.json mode change 100755 => 100644 ets2panda/linter/test/main/explicit_function_type.ets.json diff --git a/ets2panda/linter/src/lib/FaultAttrs.ts b/ets2panda/linter/src/lib/FaultAttrs.ts index c183485e36..a7cf470e6d 100644 --- a/ets2panda/linter/src/lib/FaultAttrs.ts +++ b/ets2panda/linter/src/lib/FaultAttrs.ts @@ -266,4 +266,4 @@ faultsAttrs[FaultID.NumericBigintCompare] = new FaultAttributes(376); faultsAttrs[FaultID.NondecimalBigint] = new FaultAttributes(377); faultsAttrs[FaultID.UnsupportOperator] = new FaultAttributes(378); faultsAttrs[FaultID.StateStylesBlockNeedArrowFunc] = new FaultAttributes(381); -faultsAttrs[FaultID.PromiseVoidNeedResolveArg] = new FaultAttributes(382); \ No newline at end of file +faultsAttrs[FaultID.PromiseVoidNeedResolveArg] = new FaultAttributes(382); diff --git a/ets2panda/linter/src/lib/TypeScriptLinter.ts b/ets2panda/linter/src/lib/TypeScriptLinter.ts index 1760649828..2d8e5b93d4 100644 --- a/ets2panda/linter/src/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/src/lib/TypeScriptLinter.ts @@ -157,6 +157,9 @@ import { ERROR_PROP_LIST } from './utils/consts/ErrorProp'; import { D_ETS, D_TS } from './utils/consts/TsSuffix'; import { arkTsBuiltInTypeName } from './utils/consts/ArkuiImportList'; import { ERROR_TASKPOOL_PROP_LIST } from './utils/consts/ErrorProp'; +import type { BaseClassConstructorInfo, ConstructorParameter, ExtendedIdentifierInfo } from './utils/consts/Types'; +import { ExtendedIdentifierType } from './utils/consts/Types'; +import { STRING_ERROR_LITERAL } from './utils/consts/Literals'; interface InterfaceSymbolTypeResult { propNames: string[]; @@ -8924,7 +8927,7 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { * @param node The HeritageClause node (extends clause) to analyze. */ private handleMissingSuperCallInExtendedClass(node: ts.HeritageClause): void { - if (!this.options.arkts2 || !this.useStatic) { + if (!this.options.arkts2) { return; } @@ -8933,78 +8936,249 @@ export class TypeScriptLinter extends BaseTypeScriptLinter { return; } - // Get the parent class declaration (what the child class extends) - const parentClass = this.getParentClassDeclaration(node); - if (!parentClass) { + if (!ts.isClassDeclaration(node.parent)) { return; } - // If parent class has a parameterless constructor (or no constructor at all), child is fine - if (TypeScriptLinter.parentHasParameterlessConstructor(parentClass)) { + /* + * Get the parent class declaration (what the child class extends) + * This could be a stdlib error type + */ + const identInfo = this.getExtendedIdentifiersInfo(node); + if (identInfo.type === ExtendedIdentifierType.UNKNOWN) { + // if it's unknown return return; } - // The child class node (the one extending) - const childClass = node.parent; - if (!ts.isClassDeclaration(childClass)) { + if (identInfo.type === ExtendedIdentifierType.ERROR) { + this.handleErrorClassExtend(node.parent); + // handled error case return return; } - // Look for child class constructor - const childConstructor = childClass.members.find(ts.isConstructorDeclaration); + if (identInfo.type === ExtendedIdentifierType.CLASS) { + // If it's class, get the constructor's parameters and match against it. + const extendedClassInfo = this.extractExtendedClassConstructorInfo(identInfo.decl); + if (!extendedClassInfo) { + return; + } - /* - * If child has no constructor → error (super() cannot be called) - * If child constructor exists but does not contain super() → error - */ - if (!childConstructor?.body || !TypeScriptLinter.childHasSuperCall(childConstructor)) { - this.incrementCounters(node, FaultID.MissingSuperCall); + this.handleExtendCustomClass(node.parent, extendedClassInfo); } } - /** - * Retrieves the parent class declaration node from an extends heritage clause. - */ - private getParentClassDeclaration(node: ts.HeritageClause): ts.ClassDeclaration | undefined { - const parentExpr = node.types[0]?.expression; - if (!parentExpr) { + private handleExtendCustomClass( + classDecl: ts.ClassDeclaration, + extendedClassInfo: Set + ): void { + const superCall = TypeScriptLinter.checkIfSuperCallExists(classDecl); + if (!superCall) { + this.incrementCounters(classDecl, FaultID.MissingSuperCall); + return; + } + + outer: for (const ctorParams of extendedClassInfo) { + const matches: boolean[] = []; + if (superCall.arguments.length > ctorParams.length) { + continue; + } + + for (const [idx, param] of ctorParams.entries()) { + const argument = superCall.arguments[idx]; + if (!param.isOptional && !argument) { + matches[idx] = false; + continue outer; + } + + if (!argument && param.isOptional) { + matches[idx] = true; + continue; + } + if (argument !== undefined) { + matches[idx] = this.checkIfArgumentAndParamMatches(param, argument); + if (!matches[idx]) { + continue outer; + } + } + } + + if ( + matches.some((val) => { + return !val; + }) + ) { + continue; + } + return; + } + + this.incrementCounters(classDecl, FaultID.MissingSuperCall); + } + + private checkIfArgumentAndParamMatches(param: ConstructorParameter, argument: ts.Expression): boolean { + const typeNode = this.tsTypeChecker.getTypeAtLocation(argument); + const typeString = this.tsTypeChecker.typeToString(typeNode); + + if (param.type.includes(STRINGLITERAL_STRING) && argument.kind === ts.SyntaxKind.StringLiteral) { + return true; + } + if (param.type.includes(NUMBER_LITERAL) && argument.kind === ts.SyntaxKind.NumericLiteral) { + return true; + } + + if ( + param.type.includes('boolean') && + (argument.kind === ts.SyntaxKind.FalseKeyword || argument.kind === ts.SyntaxKind.TrueKeyword) + ) { + return true; + } + + if (param.type === typeString) { + return true; + } + + return false; + } + + private handleErrorClassExtend(classDecl: ts.ClassDeclaration): void { + // if it's Error, the super method should be called with no arguments or a single string argument + const superCall = TypeScriptLinter.checkIfSuperCallExists(classDecl); + if (!superCall) { + this.incrementCounters(classDecl, FaultID.MissingSuperCall); + return; + } + + if (superCall.arguments.length > 1) { + + /* + * STD Error Type have two constructors + * either empty constructor which is just "Error" message + * or the message you provide, so if it's more than one argument provided, + * this should be raised as an issue + */ + this.incrementCounters(classDecl, FaultID.MissingSuperCall); + return; + } + + if (superCall.arguments.length === 1) { + const argument = superCall.arguments[0]; + const typeNode = this.tsTypeChecker.getTypeAtLocation(argument); + const typeString = this.tsTypeChecker.typeToString(typeNode); + + if (typeString === 'string' || ts.isStringLiteral(argument) || ts.isNumericLiteral(argument)) { + return; + } + this.incrementCounters(classDecl, FaultID.MissingSuperCall); + } + } + + private static checkIfSuperCallExists(classDecl: ts.ClassDeclaration): ts.CallExpression | undefined { + // check if current class has constructor + const constructor = TypeScriptLinter.getConstructorOfClass(classDecl); + if (!constructor) { return undefined; } - const parentSymbol = this.tsUtils.trueSymbolAtLocation(parentExpr); - return parentSymbol?.declarations?.find(ts.isClassDeclaration); + const superCallExpr = TypeScriptLinter.getSuperCallExpr(constructor); + if (!superCallExpr) { + return undefined; + } + + return superCallExpr; } /** - * Determines if a parent class has a parameterless constructor. - * If it has no constructor at all, that counts as parameterless. + * Extracts the type of the Identifier node from an extends heritage clause. */ - private static parentHasParameterlessConstructor(parentClass: ts.ClassDeclaration): boolean { - const constructors = parentClass.members.filter(ts.isConstructorDeclaration); - return ( - constructors.length === 0 || - constructors.some((ctor) => { - return ctor.parameters.length === 0; - }) - ); + private getExtendedIdentifiersInfo(node: ts.HeritageClause): ExtendedIdentifierInfo { + const extendedIdentifier = node.types[0]?.expression; + if (!extendedIdentifier) { + return { type: ExtendedIdentifierType.UNKNOWN }; + } + + const symbol = this.tsUtils.trueSymbolAtLocation(extendedIdentifier); + if (!symbol) { + return { type: ExtendedIdentifierType.UNKNOWN }; + } + + if (symbol.getName().includes(STRING_ERROR_LITERAL)) { + const declaration = this.tsUtils.getDeclarationNode(extendedIdentifier); + if (!declaration) { + return { type: ExtendedIdentifierType.ERROR }; + } + + if (declaration.getSourceFile().fileName !== this.sourceFile.fileName) { + return { type: ExtendedIdentifierType.ERROR }; + } + } + + const classDecl = symbol?.declarations?.find(ts.isClassDeclaration); + if (!classDecl) { + return { type: ExtendedIdentifierType.UNKNOWN }; + } + + return { type: ExtendedIdentifierType.CLASS, decl: classDecl }; } - private static childHasSuperCall(constructor: ts.ConstructorDeclaration): boolean { - let superCalled = false; + private extractExtendedClassConstructorInfo(extendedClass: ts.ClassDeclaration): BaseClassConstructorInfo { + const constructors = extendedClass.members.filter(ts.isConstructorDeclaration); + if (constructors.length === 0) { + return undefined; + } + const allConstructorInformation: BaseClassConstructorInfo = new Set(); + for (const ctor of constructors) { + const allParams: ConstructorParameter[] = []; + const parameters = ctor.parameters; + for (const param of parameters) { + const ident = param.name; + const name = ident.getText(); + const type = this.tsTypeChecker.getTypeAtLocation(ident); + const typeString = this.tsTypeChecker.typeToString(type); + const isOptional = !!param.questionToken; + const info = { name, type: typeString, isOptional }; + + allParams.push(info); + } + allConstructorInformation.add(allParams); + } + + return allConstructorInformation; + } + + private static getConstructorOfClass(classDecl: ts.ClassDeclaration): ts.ConstructorDeclaration | undefined { + if (classDecl.members.length === 0) { + return undefined; + } + + for (const member of classDecl.members) { + if (!ts.isConstructorDeclaration(member)) { + continue; + } + return member; + } + return undefined; + } + + private static getSuperCallExpr(constructor: ts.ConstructorDeclaration): ts.CallExpression | undefined { if (!constructor.body) { - return false; + return undefined; } - ts.forEachChild(constructor.body, (stmt) => { - if ( - ts.isExpressionStatement(stmt) && - ts.isCallExpression(stmt.expression) && - stmt.expression.expression.kind === ts.SyntaxKind.SuperKeyword - ) { - superCalled = true; + for (const stmt of constructor.body.statements) { + if (!ts.isExpressionStatement(stmt)) { + continue; } - }); - return superCalled; + const callExpr = stmt.expression; + if (!ts.isCallExpression(callExpr)) { + continue; + } + if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) { + continue; + } + + return callExpr; + } + return undefined; } private handleInterOpImportJs(importDecl: ts.ImportDeclaration): void { diff --git a/ets2panda/linter/src/lib/autofixes/Autofixer.ts b/ets2panda/linter/src/lib/autofixes/Autofixer.ts index 323536e118..1a87fe3eb9 100644 --- a/ets2panda/linter/src/lib/autofixes/Autofixer.ts +++ b/ets2panda/linter/src/lib/autofixes/Autofixer.ts @@ -3701,18 +3701,17 @@ export class Autofixer { }); if (items.length > 1) { - const formattedList = items - .map((item) => { + const formattedList = items. + map((item) => { return ` ${item.trim()},`; - }) - .join('\n'); + }). + join('\n'); return `{\n${formattedList}\n}`; } return `{${importList}}`; }); } - fixStylesDecoratorGlobal( funcDecl: ts.FunctionDeclaration, calls: ts.Identifier[], @@ -4693,17 +4692,17 @@ export class Autofixer { const expr = callExpr.expression; const hasOptionalChain = !!callExpr.questionDotToken; - const replacementText = hasOptionalChain - ? `${expr.getText()}${callExpr.questionDotToken.getText()}unsafeCall` - : `${expr.getText()}.unsafeCall`; + const replacementText = hasOptionalChain ? + `${expr.getText()}${callExpr.questionDotToken.getText()}unsafeCall` : + `${expr.getText()}.unsafeCall`; - return [{ + return [ + { start: expr.getStart(), - end: hasOptionalChain - ? callExpr.questionDotToken.getEnd() - : expr.getEnd(), + end: hasOptionalChain ? callExpr.questionDotToken.getEnd() : expr.getEnd(), replacementText - }]; + } + ]; } private static createBuiltInTypeInitializer(type: ts.TypeReferenceNode): ts.Expression | undefined { @@ -4958,7 +4957,10 @@ export class Autofixer { return [{ start: insertPos, end: insertPos, replacementText: typeArgsText }]; } - private fixGenericCallNoTypeArgsForArrayType(node: ts.NewExpression, arrayTypeNode: ts.ArrayTypeNode): Autofix[] | undefined { + private fixGenericCallNoTypeArgsForArrayType( + node: ts.NewExpression, + arrayTypeNode: ts.ArrayTypeNode + ): Autofix[] | undefined { const elementTypeNode = arrayTypeNode.elementType; const srcFile = node.getSourceFile(); const typeArgsText = `<${this.printer.printNode(ts.EmitHint.Unspecified, elementTypeNode, srcFile)}>`; @@ -4966,7 +4968,10 @@ export class Autofixer { return [{ start: insertPos, end: insertPos, replacementText: typeArgsText }]; } - private fixGenericCallNoTypeArgsForUnionType(node: ts.NewExpression, unionType: ts.UnionTypeNode): Autofix[] | undefined { + private fixGenericCallNoTypeArgsForUnionType( + node: ts.NewExpression, + unionType: ts.UnionTypeNode + ): Autofix[] | undefined { const matchingTypes = unionType.types.filter((type) => { return ts.isTypeReferenceNode(type) && type.typeName.getText() === node.expression.getText(); }) as ts.TypeReferenceNode[]; diff --git a/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts b/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts index 3beae87577..f8ab0145c5 100644 --- a/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts +++ b/ets2panda/linter/src/lib/utils/consts/ArkuiImportList.ts @@ -1616,52 +1616,52 @@ export const arkuiImportList: Set = new Set([ ]); export const arkTsBuiltInTypeName: Set = new Set([ - 'Object', - 'Function', - 'Boolean', - 'Symbol', - 'Number', - 'BigInt', - 'Math', + 'Object', + 'Function', + 'Boolean', + 'Symbol', + 'Number', + 'BigInt', + 'Math', 'Date', - 'String', + 'String', 'RegExp', - 'Array', - 'Int8Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Int16Array', - 'Uint16Array', - 'Int32Array', + 'Array', + 'Int8Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Int16Array', + 'Uint16Array', + 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', - 'BigInt64Array', + 'BigInt64Array', 'BigUint64Array', - 'Map', - 'Set', + 'Map', + 'Set', 'WeakMap', 'WeakSet', - 'ArrayBuffer', - 'SharedArrayBuffer', - 'DataView', - 'JSON', - 'Promise', - 'Generator', - 'GeneratorFunction', + 'ArrayBuffer', + 'SharedArrayBuffer', + 'DataView', + 'JSON', + 'Promise', + 'Generator', + 'GeneratorFunction', 'AsyncFunction', - 'AsyncGenerator', - 'AsyncGeneratorFunction', - 'Reflect', - 'Proxy', + 'AsyncGenerator', + 'AsyncGeneratorFunction', + 'Reflect', + 'Proxy', 'Error', 'EvalError', - 'RangeError', - 'ReferenceError', - 'SyntaxError', - 'TypeError', - 'URIError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', 'AggregateError', 'Intl', 'WebAssembly' -]); \ No newline at end of file +]); diff --git a/ets2panda/linter/src/lib/utils/consts/ErrorProp.ts b/ets2panda/linter/src/lib/utils/consts/ErrorProp.ts index 212bb02ae4..9bdc9da573 100644 --- a/ets2panda/linter/src/lib/utils/consts/ErrorProp.ts +++ b/ets2panda/linter/src/lib/utils/consts/ErrorProp.ts @@ -1,4 +1,3 @@ - /* * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ets2panda/linter/src/lib/utils/consts/Types.ts b/ets2panda/linter/src/lib/utils/consts/Types.ts new file mode 100644 index 0000000000..86abf3d58c --- /dev/null +++ b/ets2panda/linter/src/lib/utils/consts/Types.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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. + */ +import type { ClassDeclaration } from 'typescript'; + +export enum ExtendedIdentifierType { + UNKNOWN, + CLASS, + ERROR +} + +export type ExtendedIdentifierInfo = + | { + type: ExtendedIdentifierType.UNKNOWN | ExtendedIdentifierType.ERROR; + } + | { type: ExtendedIdentifierType.CLASS; decl: ClassDeclaration }; + +export type ConstructorParameter = { + name: string; + isOptional: boolean; + type: string; +}; + +export type ParameterName = string; + +export type BaseClassConstructorInfo = Set | undefined; diff --git a/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts b/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts index c0c5efc0cc..676b1fb1e7 100644 --- a/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts +++ b/ets2panda/linter/src/lib/utils/consts/WorkloadRelatedConst.ts @@ -17,4 +17,4 @@ export const AVERAGE_LINE_FOR_REPAIRE_RULE_COEFFICIENT = 3; export const TEST_DEBUG_WORKLOAD_COEFFICIENT = 1.2; -export const NPAI_REPAIRE_WORKLOADA_COEFFICIEN = 0.2; \ No newline at end of file +export const NPAI_REPAIRE_WORKLOADA_COEFFICIEN = 0.2; diff --git a/ets2panda/linter/test/main/explicit_function_type.ets b/ets2panda/linter/test/main/explicit_function_type.ets index c42f90e3fb..45278cb9e4 100755 --- a/ets2panda/linter/test/main/explicit_function_type.ets +++ b/ets2panda/linter/test/main/explicit_function_type.ets @@ -75,8 +75,8 @@ class I24 { constructor(par: Function, par1?: string) {} } class I24_1 extends I24 { - constructor() { - super(Function) + constructor(par: Function) { + super(par) } } @@ -177,4 +177,4 @@ fn29[1](); SysApiWrapper.setTimeout = (handler: Function | string, delay?: number): number => { (handler as Function)?.(); return Math.random(); -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/explicit_function_type.ets.arkts2.json b/ets2panda/linter/test/main/explicit_function_type.ets.arkts2.json old mode 100755 new mode 100644 index 3427352803..c771599a28 --- a/ets2panda/linter/test/main/explicit_function_type.ets.arkts2.json +++ b/ets2panda/linter/test/main/explicit_function_type.ets.arkts2.json @@ -74,16 +74,6 @@ "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "ERROR" }, - { - "line": 79, - "column": 11, - "endLine": 79, - "endColumn": 19, - "problem": "ClassAsObjectError", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "ERROR" - }, { "line": 93, "column": 11, @@ -355,4 +345,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/explicit_function_type.ets.autofix.json b/ets2panda/linter/test/main/explicit_function_type.ets.autofix.json index 9512b29aac..968aec7d48 100644 --- a/ets2panda/linter/test/main/explicit_function_type.ets.autofix.json +++ b/ets2panda/linter/test/main/explicit_function_type.ets.autofix.json @@ -1,6 +1,6 @@ { "copyright": [ - "Copyright (c) 2025 Huawei Device Co., Ltd.", + "Copyright (c) 2024-2025 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", @@ -129,16 +129,6 @@ "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "ERROR" }, - { - "line": 79, - "column": 11, - "endLine": 79, - "endColumn": 19, - "problem": "ClassAsObjectError", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "ERROR" - }, { "line": 93, "column": 11, @@ -147,8 +137,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2073, - "end": 2074, + "start": 2081, + "end": 2082, "replacementText": "2.0", "line": 93, "column": 11, @@ -178,8 +168,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2550, - "end": 2551, + "start": 2558, + "end": 2559, "replacementText": "1.0", "line": 118, "column": 26, @@ -199,8 +189,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2553, - "end": 2554, + "start": 2561, + "end": 2562, "replacementText": "2.0", "line": 118, "column": 29, @@ -220,8 +210,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2556, - "end": 2557, + "start": 2564, + "end": 2565, "replacementText": "3.0", "line": 118, "column": 32, @@ -281,8 +271,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2719, - "end": 2720, + "start": 2727, + "end": 2728, "replacementText": "1.0", "line": 128, "column": 31, @@ -322,8 +312,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2768, - "end": 2769, + "start": 2776, + "end": 2777, "replacementText": "1.0", "line": 128, "column": 80, @@ -353,8 +343,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2849, - "end": 2850, + "start": 2857, + "end": 2858, "replacementText": "1.0", "line": 133, "column": 10, @@ -374,8 +364,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 2921, - "end": 2929, + "start": 2929, + "end": 2937, "replacementText": "callback.unsafeCall", "line": 139, "column": 3, @@ -395,8 +385,8 @@ "problem": "NumericSemantics", "autofix": [ { - "start": 2995, - "end": 2996, + "start": 3003, + "end": 3004, "replacementText": "1.0", "line": 142, "column": 41, @@ -446,8 +436,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 3458, - "end": 3462, + "start": 3466, + "end": 3470, "replacementText": "curr.unsafeCall", "line": 160, "column": 62, @@ -467,8 +457,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 3463, - "end": 3467, + "start": 3471, + "end": 3475, "replacementText": "prev.unsafeCall", "line": 160, "column": 67, @@ -488,8 +478,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 3586, - "end": 3588, + "start": 3594, + "end": 3596, "replacementText": "f1.unsafeCall", "line": 166, "column": 1, @@ -509,8 +499,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 3656, - "end": 3663, + "start": 3664, + "end": 3671, "replacementText": "ab3.fn3.unsafeCall", "line": 172, "column": 1, @@ -530,8 +520,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 3697, - "end": 3704, + "start": 3705, + "end": 3712, "replacementText": "fn29[1].unsafeCall", "line": 175, "column": 1, @@ -561,8 +551,8 @@ "problem": "ExplicitFunctionType", "autofix": [ { - "start": 3796, - "end": 3819, + "start": 3804, + "end": 3827, "replacementText": "(handler as Function)?.unsafeCall", "line": 178, "column": 3, @@ -575,4 +565,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/explicit_function_type.ets.json b/ets2panda/linter/test/main/explicit_function_type.ets.json old mode 100755 new mode 100644 index d138186989..a3424dbdf2 --- a/ets2panda/linter/test/main/explicit_function_type.ets.json +++ b/ets2panda/linter/test/main/explicit_function_type.ets.json @@ -1,19 +1,19 @@ { - "copyright": [ - "Copyright (c) 2024-2025 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." - ], - "result": [ + "copyright": [ + "Copyright (c) 2024-2025 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." + ], + "result": [ { "line": 16, "column": 20, @@ -44,16 +44,6 @@ "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "WARNING" }, - { - "line": 79, - "column": 11, - "endLine": 79, - "endColumn": 19, - "problem": "ClassAsObject", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "WARNING" - }, { "line": 118, "column": 16, @@ -75,4 +65,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/explicit_function_type.ets.migrate.ets b/ets2panda/linter/test/main/explicit_function_type.ets.migrate.ets index c5ecffb429..94cd68114e 100644 --- a/ets2panda/linter/test/main/explicit_function_type.ets.migrate.ets +++ b/ets2panda/linter/test/main/explicit_function_type.ets.migrate.ets @@ -75,8 +75,8 @@ class I24 { constructor(par: Function, par1?: string) {} } class I24_1 extends I24 { - constructor() { - super(Function) + constructor(par: Function) { + super(par) } } @@ -177,4 +177,4 @@ fn29[1].unsafeCall(); SysApiWrapper.setTimeout = (handler: Function | string, delay?: number): number => { (handler as Function)?.unsafeCall(); return Math.random(); -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/explicit_function_type.ets.migrate.json b/ets2panda/linter/test/main/explicit_function_type.ets.migrate.json index b4e8db486e..43ff503ff4 100644 --- a/ets2panda/linter/test/main/explicit_function_type.ets.migrate.json +++ b/ets2panda/linter/test/main/explicit_function_type.ets.migrate.json @@ -24,16 +24,6 @@ "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", "severity": "ERROR" }, - { - "line": 79, - "column": 11, - "endLine": 79, - "endColumn": 19, - "problem": "ClassAsObjectError", - "suggest": "", - "rule": "Classes cannot be used as objects (arkts-no-classes-as-obj)", - "severity": "ERROR" - }, { "line": 118, "column": 16, @@ -155,4 +145,4 @@ "severity": "ERROR" } ] -} \ No newline at end of file +} diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json b/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json index b72ff900ba..8ed64f688b 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.arkts2.json @@ -1164,6 +1164,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 216, + "column": 1, + "endLine": 218, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, { "line": 219, "column": 18, @@ -1196,9 +1206,9 @@ }, { "line": 226, - "column": 16, - "endLine": 226, - "endColumn": 29, + "column": 1, + "endLine": 228, + "endColumn": 2, "problem": "MissingSuperCall", "suggest": "", "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json b/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json index ccf6076bdc..bbb319af18 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.autofix.json @@ -2072,6 +2072,16 @@ "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", "severity": "ERROR" }, + { + "line": 216, + "column": 1, + "endLine": 218, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, { "line": 219, "column": 18, @@ -2135,9 +2145,9 @@ }, { "line": 226, - "column": 16, - "endLine": 226, - "endColumn": 29, + "column": 1, + "endLine": 228, + "endColumn": 2, "problem": "MissingSuperCall", "suggest": "", "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", diff --git a/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json b/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json index cb49576162..675cc2476a 100644 --- a/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json +++ b/ets2panda/linter/test/main/object_literals_properties.ets.migrate.json @@ -284,11 +284,21 @@ "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", "severity": "ERROR" }, + { + "line": 274, + "column": 1, + "endLine": 276, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, { "line": 286, - "column": 16, - "endLine": 286, - "endColumn": 29, + "column": 1, + "endLine": 288, + "endColumn": 2, "problem": "MissingSuperCall", "suggest": "", "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", @@ -314,6 +324,16 @@ "rule": "Object literal properties can only contain name-value pairs (arkts-obj-literal-props)", "severity": "ERROR" }, + { + "line": 303, + "column": 1, + "endLine": 305, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, { "line": 342, "column": 5, diff --git a/ets2panda/linter/test/main/subclass_super_call.ets b/ets2panda/linter/test/main/subclass_super_call.ets index d275725c9c..7e80348064 100644 --- a/ets2panda/linter/test/main/subclass_super_call.ets +++ b/ets2panda/linter/test/main/subclass_super_call.ets @@ -36,4 +36,50 @@ class E extends A { // NO ERROR constructor is called } } -class F extends B {} // NO ERROR +class Base { + constructor(a?: string) {} + constructor(a: string, b:string, c?:string) {} +} + +class Foo extends Base { + constructor() { + super() + } +} + +class Bar extends Base { + constructor() { + super("foo") + } +} + +class FooTheSecond extends Base { + constructor() { + super("Foo", "Bar", "Baz") + } +} + +class FaultyBar extends Base { + constructor() { + super(12) // should error + } +} + + +class FaultyFooTheSecond extends Base { + constructor() { + super("foo", "bar", false) // should error + } +} + +class EpicFoo extends Error { + constructor() { + super() + } +} + +class EpicBar extends Error { + constructor() { + super("foo") + } +} diff --git a/ets2panda/linter/test/main/subclass_super_call.ets.args.json b/ets2panda/linter/test/main/subclass_super_call.ets.args.json index 948b846fe0..bc4d2071da 100644 --- a/ets2panda/linter/test/main/subclass_super_call.ets.args.json +++ b/ets2panda/linter/test/main/subclass_super_call.ets.args.json @@ -14,6 +14,6 @@ "limitations under the License." ], "mode": { - "arkts2": "" + "arkts2": "" } } diff --git a/ets2panda/linter/test/main/subclass_super_call.ets.arkts2.json b/ets2panda/linter/test/main/subclass_super_call.ets.arkts2.json index 289a83337b..83dc3263ef 100644 --- a/ets2panda/linter/test/main/subclass_super_call.ets.arkts2.json +++ b/ets2panda/linter/test/main/subclass_super_call.ets.arkts2.json @@ -1,38 +1,108 @@ { - "copyright": [ - "Copyright (c) 2025 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." - ], - "result": [ - { - "line": 27, - "column": 9, - "endLine": 27, - "endColumn": 18, - "problem": "MissingSuperCall", - "suggest": "", - "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", - "severity": "ERROR" - }, - { - "line": 29, - "column": 9, - "endLine": 29, - "endColumn": 18, - "problem": "MissingSuperCall", - "suggest": "", - "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", - "severity": "ERROR" - } - ] + "copyright": [ + "Copyright (c) 2025 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." + ], + "result": [ + { + "line": 27, + "column": 1, + "endLine": 27, + "endColumn": 21, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, + { + "line": 29, + "column": 1, + "endLine": 31, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, + { + "line": 40, + "column": 5, + "endLine": 40, + "endColumn": 31, + "problem": "TsOverload", + "suggest": "", + "rule": "Class TS overloading is not supported(arkts-no-ts-overload)", + "severity": "ERROR" + }, + { + "line": 41, + "column": 5, + "endLine": 41, + "endColumn": 51, + "problem": "TsOverload", + "suggest": "", + "rule": "Class TS overloading is not supported(arkts-no-ts-overload)", + "severity": "ERROR" + }, + { + "line": 62, + "column": 1, + "endLine": 66, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, + { + "line": 64, + "column": 15, + "endLine": 64, + "endColumn": 17, + "problem": "NumericSemantics", + "suggest": "", + "rule": "Numeric semantics is different for integer values (arkts-numeric-semantic)", + "severity": "ERROR" + }, + { + "line": 69, + "column": 1, + "endLine": 73, + "endColumn": 2, + "problem": "MissingSuperCall", + "suggest": "", + "rule": "The subclass constructor must call the parent class's parametered constructor (arkts-subclass-must-call-super-constructor-with-args)", + "severity": "ERROR" + }, + { + "line": 77, + "column": 9, + "endLine": 77, + "endColumn": 14, + "problem": "BuiltinNoCtorFunc", + "suggest": "", + "rule": "API is not support ctor signature and func (arkts-builtin-cotr)", + "severity": "ERROR" + }, + { + "line": 83, + "column": 9, + "endLine": 83, + "endColumn": 14, + "problem": "BuiltinNoCtorFunc", + "suggest": "", + "rule": "API is not support ctor signature and func (arkts-builtin-cotr)", + "severity": "ERROR" + } + ] } -- Gitee