diff --git a/ets2panda/linter/lib/CookBookMsg.ts b/ets2panda/linter/lib/CookBookMsg.ts index 20763e1d1f8cb96195ae4aaefc8ece409766f181..fa948aa8a65948462d4ad74e0f45e599ab370553 100644 --- a/ets2panda/linter/lib/CookBookMsg.ts +++ b/ets2panda/linter/lib/CookBookMsg.ts @@ -16,7 +16,7 @@ export const cookBookMsg: string[] = []; export const cookBookTag: string[] = []; -for (let i = 0; i <= 151; i++) { +for (let i = 0; i <= 157; i++) { cookBookMsg[i] = ''; } @@ -177,3 +177,9 @@ cookBookTag[149] = 'Classes cannot be used as objects (arkts-no-classes-as-obj)' cookBookTag[150] = '"import" statements after other statements are not allowed (arkts-no-misplaced-imports)'; cookBookTag[151] = 'Usage of "ESObject" type is restricted (arkts-limited-esobj)'; cookBookTag[152] = '"Function.apply", "Function.call" are not supported (arkts-no-func-apply-call)'; +cookBookTag[153] = 'The inheritance for "Sendable" classes is limited (arkts-sendable-class-inheritance)'; +cookBookTag[154] = ''; +cookBookTag[155] = 'Definite assignment assertion in not allowed in "Sendable" classes and interfaces (arkts-sendable-definite-assignment)'; +cookBookTag[156] = ''; +cookBookTag[157] = 'Only imported variables can be captured by "Sendable" classes (arkts-sendable-imported-variables)'; + diff --git a/ets2panda/linter/lib/FaultAttrs.ts b/ets2panda/linter/lib/FaultAttrs.ts index 016d315f18ab689bee26a8efed909803c7531291..e42bd7c12b0c1d4c6369b07702566c80646d00c3 100644 --- a/ets2panda/linter/lib/FaultAttrs.ts +++ b/ets2panda/linter/lib/FaultAttrs.ts @@ -105,3 +105,7 @@ faultsAttrs[FaultID.ClassAsObject] = new FaultAttributes(149, ProblemSeverity.WA faultsAttrs[FaultID.ImportAfterStatement] = new FaultAttributes(150); faultsAttrs[FaultID.EsObjectType] = new FaultAttributes(151, ProblemSeverity.WARNING); faultsAttrs[FaultID.FunctionApplyCall] = new FaultAttributes(152); +faultsAttrs[FaultID.SendableClassInheritance] = new FaultAttributes(153); +faultsAttrs[FaultID.SendableDefiniteAssignment] = new FaultAttributes(155); +faultsAttrs[FaultID.SendableCapturedVars] = new FaultAttributes(157); + diff --git a/ets2panda/linter/lib/FaultDesc.ts b/ets2panda/linter/lib/FaultDesc.ts index b22f575ab536b75d227be2d0b8162c0e349693d1..326bb05af8774d96af564a2c4b4e829249f5f106 100644 --- a/ets2panda/linter/lib/FaultDesc.ts +++ b/ets2panda/linter/lib/FaultDesc.ts @@ -97,3 +97,7 @@ faultDesc[FaultID.ErrorSuppression] = 'Error suppression annotation'; faultDesc[FaultID.StrictDiagnostic] = 'Strict diagnostic'; faultDesc[FaultID.ImportAfterStatement] = 'Import declaration after other declaration or statement'; faultDesc[FaultID.EsObjectType] = 'Restricted "ESObject" type'; +faultDesc[FaultID.SendableClassInheritance] = 'Sendable class inheritance'; +faultDesc[FaultID.SendableDefiniteAssignment] = 'Use of definite assignment assertin in "Sendable" class of interface'; +faultDesc[FaultID.SendableCapturedVars] = 'Sendable class captured variables'; + diff --git a/ets2panda/linter/lib/Problems.ts b/ets2panda/linter/lib/Problems.ts index b8b43fc6b3532040e690922193b69bf09cf15cd1..9bf4f62f712b28e71b673b11acd67ae0192d6913 100644 --- a/ets2panda/linter/lib/Problems.ts +++ b/ets2panda/linter/lib/Problems.ts @@ -94,6 +94,8 @@ export enum FaultID { StrictDiagnostic, ImportAfterStatement, EsObjectType, - // this should always be last enum + SendableClassInheritance, + SendableDefiniteAssignment, + SendableCapturedVars, LAST_ID } diff --git a/ets2panda/linter/lib/TypeScriptLinter.ts b/ets2panda/linter/lib/TypeScriptLinter.ts index d43f928ed35ecf775a5bfaf633b01b79e30fed98..237f6aa067b15ac23e78c410b11ca34a2c95b70f 100644 --- a/ets2panda/linter/lib/TypeScriptLinter.ts +++ b/ets2panda/linter/lib/TypeScriptLinter.ts @@ -756,6 +756,10 @@ export class TypeScriptLinter { ); this.handleDeclarationInferredType(node); this.handleDefiniteAssignmentAssertion(node); + // check captured variables for sendable class + if (TsUtils.hasSendableDecorator(node.parent as ts.ClassDeclaration)) { + this.scanCapturedVarsInSendableScope(node); + } } private handlePropertyAssignment(node: ts.PropertyAssignment): void { @@ -815,13 +819,8 @@ export class TypeScriptLinter { // Filter out non-initializable property decorators from strict diagnostics. if (this.tscStrictDiagnostics && this.sourceFile) { if ( - decorators?.some((x) => { - let decoratorName = ''; - if (ts.isIdentifier(x.expression)) { - decoratorName = x.expression.text; - } else if (ts.isCallExpression(x.expression) && ts.isIdentifier(x.expression.expression)) { - decoratorName = x.expression.expression.text; - } + decorators?.some((decorator) => { + const decoratorName = TsUtils.getDecoratorName(decorator); // special case for property of type CustomDialogController of the @CustomDialog-decorated class if (expectedDecorators.includes(NON_INITIALIZABLE_PROPERTY_CLASS_DECORATORS[0])) { return expectedDecorators.includes(decoratorName) && propType === 'CustomDialogController'; @@ -1323,11 +1322,19 @@ export class TypeScriptLinter { } this.countClassMembersWithDuplicateName(tsClassDecl); + const isSendableClass = TsUtils.hasSendableDecorator(tsClassDecl); const visitHClause = (hClause: ts.HeritageClause): void => { for (const tsTypeExpr of hClause.types) { - const tsExprType = this.tsTypeChecker.getTypeAtLocation(tsTypeExpr.expression); - if (tsExprType.isClass() && hClause.token === ts.SyntaxKind.ImplementsKeyword) { - this.incrementCounters(tsTypeExpr, FaultID.ImplementsClass); + const tsExprType = TsUtils.reduceReference(this.tsTypeChecker.getTypeAtLocation(tsTypeExpr)); + if (tsExprType.isClass()) { + if (hClause.token === ts.SyntaxKind.ImplementsKeyword) { + this.incrementCounters(tsTypeExpr, FaultID.ImplementsClass); + } + + const isSendableBaseType = this.tsUtils.isSendableType(tsExprType); + if (isSendableClass && !isSendableBaseType || !isSendableClass && isSendableBaseType) { + this.incrementCounters(tsTypeExpr, FaultID.SendableClassInheritance); + } } } }; @@ -1463,6 +1470,10 @@ export class TypeScriptLinter { { begin: tsMethodDecl.parameters.end, end: tsMethodDecl.body?.getStart() ?? tsMethodDecl.parameters.end }, FUNCTION_HAS_NO_RETURN_ERROR_CODE ); + // check captured variables for sendable class + if (TsUtils.hasSendableDecorator(node.parent as ts.ClassDeclaration)) { + this.scanCapturedVarsInSendableScope(node); + } } private handleMethodSignature(node: ts.MethodSignature): void { @@ -1478,6 +1489,10 @@ export class TypeScriptLinter { return; } this.reportThisKeywordsInScope(classStaticBlockDecl.body); + // check captured variables for sendable class + if (TsUtils.hasSendableDecorator(node.parent as ts.ClassDeclaration)) { + this.scanCapturedVarsInSendableScope(node); + } } private handleIdentifier(node: ts.Node): void { @@ -2065,9 +2080,18 @@ export class TypeScriptLinter { } private handleDefiniteAssignmentAssertion(decl: ts.VariableDeclaration | ts.PropertyDeclaration): void { - if (decl.exclamationToken !== undefined) { - this.incrementCounters(decl, FaultID.DefiniteAssignment); + if (decl.exclamationToken === undefined) { + return; } + + if (decl.kind === ts.SyntaxKind.PropertyDeclaration) { + const parentDecl = decl.parent; + if (parentDecl.kind === ts.SyntaxKind.ClassDeclaration && TsUtils.hasSendableDecorator(parentDecl)) { + this.incrementCounters(decl, FaultID.SendableDefiniteAssignment); + return; + } + } + this.incrementCounters(decl, FaultID.DefiniteAssignment); } private readonly validatedTypesSet = new Set(); @@ -2260,6 +2284,34 @@ export class TypeScriptLinter { this.incrementCounters(node, FaultID.PrivateIdentifier, autofixable, autofix); } + private scanCapturedVarsInSendableScope( scope: ts.Node, ): void { + const inClass = scope.parent; + const callback = (node: ts.Node): void => { + if (node.kind === ts.SyntaxKind.Identifier) { + const symbol = this.tsTypeChecker.getSymbolAtLocation(node); + if (symbol === undefined) { + this.incrementCounters(node, FaultID.SendableCapturedVars); + return; + } + //if ( !(symbol.getFlags() & (ts.SymbolFlags.Variable)) ) + // return; + if( this.tsTypeChecker.isArgumentsSymbol(symbol)) + return; + const decl = symbol.getDeclarations(); + if (decl && decl[0].kind === ts.SyntaxKind.PropertyDeclaration) + return; + if (decl && decl[0].kind === ts.SyntaxKind.ImportSpecifier) + return; + let declPosition = decl?.[0].getStart(); + if(declPosition && (declPosition >= scope.getStart()) && (declPosition < scope.getEnd()) ) + return; + this.incrementCounters(node, FaultID.SendableCapturedVars); + } + }; + // scan all subtree + forEachNodeInSubtree(scope, callback); + } + private createSyncAutofixes(symbol: ts.Symbol, autofixes: Autofix[]): Autofix[] { if (!this.syncAutofixes.has(symbol)) { this.syncAutofixes.set(symbol, []); diff --git a/ets2panda/linter/lib/utils/TsUtils.ts b/ets2panda/linter/lib/utils/TsUtils.ts index bb43587435b683ecf1c1b7ad3b02bc24c8084a83..861f80eb14b1b171ebcae5f36b919d9500de14df 100644 --- a/ets2panda/linter/lib/utils/TsUtils.ts +++ b/ets2panda/linter/lib/utils/TsUtils.ts @@ -234,7 +234,7 @@ export class TsUtils { } // does something similar to relatedByInheritanceOrIdentical function - isOrDerivedFrom(tsType: ts.Type, checkType: CheckType): boolean { + isOrDerivedFrom(tsType: ts.Type, checkType: CheckType, checkedBaseTypes?: Set): boolean { tsType = TsUtils.reduceReference(tsType); if (checkType.call(this, tsType)) { @@ -245,6 +245,9 @@ export class TsUtils { return false; } + // Avoid type recursion in heritage by caching checked types. + (checkedBaseTypes ||= new Set()).add(tsType); + for (const tsTypeDecl of tsType.symbol.declarations) { const isClassOrInterfaceDecl = ts.isClassDeclaration(tsTypeDecl) || ts.isInterfaceDeclaration(tsTypeDecl); const isDerived = isClassOrInterfaceDecl && !!tsTypeDecl.heritageClauses; @@ -252,7 +255,7 @@ export class TsUtils { continue; } for (const heritageClause of tsTypeDecl.heritageClauses) { - if (this.processParentTypesCheck(heritageClause.types, checkType)) { + if (this.processParentTypesCheck(heritageClause.types, checkType, checkedBaseTypes)) { return true; } } @@ -584,10 +587,18 @@ export class TsUtils { return false; } - private processParentTypesCheck(parentTypes: ts.NodeArray, checkType: CheckType): boolean { + private processParentTypesCheck( + parentTypes: ts.NodeArray, + checkType: CheckType, + checkedBaseTypes: Set + ): boolean { for (const baseTypeExpr of parentTypes) { const baseType = TsUtils.reduceReference(this.tsTypeChecker.getTypeAtLocation(baseTypeExpr)); - if (baseType && this.isOrDerivedFrom(baseType, checkType)) { + if ( + baseType && + !checkedBaseTypes.has(baseType) && + this.isOrDerivedFrom(baseType, checkType, checkedBaseTypes) + ) { return true; } } @@ -1672,4 +1683,47 @@ export class TsUtils { return false; }); } + + static getDecoratorName(decorator: ts.Decorator): string { + let decoratorName = ''; + if (ts.isIdentifier(decorator.expression)) { + decoratorName = decorator.expression.text; + } else if (ts.isCallExpression(decorator.expression) && ts.isIdentifier(decorator.expression.expression)) { + decoratorName = decorator.expression.expression.text; + } + return decoratorName; + } + + isSendableType(type: ts.Type): boolean { + const sym = type.getSymbol(); + if (!sym) { + return false; + } + + // class with @Sendable decorator + if (type.isClass()) { + if (sym.declarations?.length) { + const decl = sym.declarations[0]; + if (ts.isClassDeclaration(decl) && TsUtils.hasSendableDecorator(decl)) { + return true; + } + } + } + + // ISendable interface, or a class/interface that implements/extends ISendable interface + return this.isOrDerivedFrom(type, TsUtils.isISendableInterface); + } + + static hasSendableDecorator(decl: ts.ClassDeclaration): boolean { + const decorators = ts.getDecorators(decl); + return decorators !== undefined && decorators.some((x) => { + return TsUtils.getDecoratorName(x) === 'Sendable'; + }); + } + + static isISendableInterface(type: ts.Type): boolean { + const sym = type.getSymbol(); + return sym !== undefined && TsUtils.isObjectType(type) && (type.objectFlags & ts.ObjectFlags.Interface) !== 0 && + sym.name === 'ISendable'; + } } diff --git a/ets2panda/linter/test/sendable_captured_variables.ts b/ets2panda/linter/test/sendable_captured_variables.ts new file mode 100644 index 0000000000000000000000000000000000000000..84e47cba75925d7ff7826f52e2a44cb05c3077cc --- /dev/null +++ b/ets2panda/linter/test/sendable_captured_variables.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ + + +import { libPi, libString, libFoo, libClass, libClassVar } from "./sendable_captured_varaibles_lib" + +let local = 'local'; + +function foo(): string { + return "local foo"; +} + +class localClass { } + +let localObj: localClass = {}; + +@Sendable +class SendableClass { + static pi: number = libPi; + static hdr: string = libString; + public p = local; // error + static ps = local; // error + + public foo(x: string): string { + let s = local; //error + let ss = this.p + x; + s = foo(); // error + s = libFoo(); + return s + ss; + } + static { + SendableClass.ps = local; //error + let pps: string = libString; + let lc: localClass; //error + lc = localObj; //error + let c: libClass; + c = libClassVar; + } + +} diff --git a/ets2panda/linter/test/sendable_captured_variables.ts.autofix.skip b/ets2panda/linter/test/sendable_captured_variables.ts.autofix.skip new file mode 100644 index 0000000000000000000000000000000000000000..e7ecbbc6a11fccc47996969f08d7026f3f984ac7 --- /dev/null +++ b/ets2panda/linter/test/sendable_captured_variables.ts.autofix.skip @@ -0,0 +1,44 @@ +{ + "nodes": [ + { + "line": 23, + "column": 13, + "problem": "SendableCapturedVars", + "autofixable": false, + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 24, + "column": 17, + "problem": "SendableCapturedVars", + "autofixable": false, + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 26, + "column": 11, + "problem": "SendableCapturedVars", + "autofixable": false, + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 31, + "column": 22, + "problem": "SendableCapturedVars", + "autofixable": false, + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 32, + "column": 7, + "problem": "AnyType", + "autofixable": false, + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/sendable_captured_variables.ts.json b/ets2panda/linter/test/sendable_captured_variables.ts.json new file mode 100644 index 0000000000000000000000000000000000000000..b54865af8c57e077ae774b163ec8622987a16a6c --- /dev/null +++ b/ets2panda/linter/test/sendable_captured_variables.ts.json @@ -0,0 +1,60 @@ +{ + "nodes": [ + { + "line": 33, + "column": 13, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 34, + "column": 14, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 37, + "column": 11, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 39, + "column": 7, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 44, + "column": 3, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 44, + "column": 22, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 46, + "column": 11, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + }, + { + "line": 47, + "column": 8, + "problem": "SendableCapturedVars", + "suggest": "", + "rule": "Only imported variables can be captured by \"Sendable\" classes (arkts-sendable-imported-variables)" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/sendable_captured_variables_lib.d.ts b/ets2panda/linter/test/sendable_captured_variables_lib.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6a904d0b22bb988c768faef3f4b15f86b246b5a --- /dev/null +++ b/ets2panda/linter/test/sendable_captured_variables_lib.d.ts @@ -0,0 +1,16 @@ +export const libPi = 3.14; +export let libString = "lib string"; + +export function libFoo(): string { + return "libFoo"; +} + +export enum libRGB = {RED, GREEN, BLUE }; + +export class libClass { + public foo(): string { + return "lib class foo"; +} + + +export let libClassVar: libClass; diff --git a/ets2panda/linter/test/sendable_class_inheritance.ts b/ets2panda/linter/test/sendable_class_inheritance.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef11032842401cbe946f49e6d35a19004123b7e9 --- /dev/null +++ b/ets2panda/linter/test/sendable_class_inheritance.ts @@ -0,0 +1,45 @@ +/* + * 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. + */ + +let Sendable = (x, y) => {} + +// Sendable class inheritance +class NonSendableClass {} + +@Sendable +class SendableClass {} // OK + +@Sendable +class BadInheritance1 extends NonSendableClass {} // ERROR, extends non-sendable + +class BadInheritance2 extends SendableClass {} // ERROR, no @Sendable decorator + +@Sendable +class GoodInheritance extends SendableClass {} // OK + +// Implement ISendable interface +interface ISendable {} + +class SendableImpl implements ISendable {} // OK, class is now sendable + +class BadInterfaceImpl extends SendableImpl {} // ERROR, no @Sendable decorator + +@Sendable +class GoodInterfaceImpl extends SendableImpl {} // OK + +// Implement interface extending ISendable +interface ISendableExt extends ISendable {} + +class GoodInterfaceExtImpl implements ISendableExt {} // OK, class implements interface that extends ISendable diff --git a/ets2panda/linter/test/sendable_class_inheritance.ts.autofix.json b/ets2panda/linter/test/sendable_class_inheritance.ts.autofix.json new file mode 100644 index 0000000000000000000000000000000000000000..122a08fed0d9b9882fa5f1b5f82b9a230c972de2 --- /dev/null +++ b/ets2panda/linter/test/sendable_class_inheritance.ts.autofix.json @@ -0,0 +1,55 @@ +{ + "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": 16, + "column": 17, + "problem": "AnyType", + "autofixable": false, + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)" + }, + { + "line": 16, + "column": 20, + "problem": "AnyType", + "autofixable": false, + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)" + }, + { + "line": 25, + "column": 31, + "problem": "SendableClassInheritance", + "autofixable": false, + "rule": "The inheritance for \"Sendable\" classes is limited (arkts-sendable-class-inheritance)" + }, + { + "line": 27, + "column": 31, + "problem": "SendableClassInheritance", + "autofixable": false, + "rule": "The inheritance for \"Sendable\" classes is limited (arkts-sendable-class-inheritance)" + }, + { + "line": 37, + "column": 32, + "problem": "SendableClassInheritance", + "autofixable": false, + "rule": "The inheritance for \"Sendable\" classes is limited (arkts-sendable-class-inheritance)" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test/sendable_class_inheritance.ts.json b/ets2panda/linter/test/sendable_class_inheritance.ts.json new file mode 100644 index 0000000000000000000000000000000000000000..524b6b0096aa7536f38a95b76ed3e97349d60567 --- /dev/null +++ b/ets2panda/linter/test/sendable_class_inheritance.ts.json @@ -0,0 +1,50 @@ +{ + "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": 16, + "column": 17, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)" + }, + { + "line": 16, + "column": 20, + "problem": "AnyType", + "suggest": "", + "rule": "Use explicit types instead of \"any\", \"unknown\" (arkts-no-any-unknown)" + }, + { + "line": 25, + "column": 31, + "problem": "SendableClassInheritance", + "rule": "The inheritance for \"Sendable\" classes is limited (arkts-sendable-class-inheritance)" + }, + { + "line": 27, + "column": 31, + "problem": "SendableClassInheritance", + "rule": "The inheritance for \"Sendable\" classes is limited (arkts-sendable-class-inheritance)" + }, + { + "line": 37, + "column": 32, + "problem": "SendableClassInheritance", + "rule": "The inheritance for \"Sendable\" classes is limited (arkts-sendable-class-inheritance)" + } + ] +} \ No newline at end of file diff --git a/ets2panda/linter/test_rules/rule155.ts b/ets2panda/linter/test_rules/rule155.ts new file mode 100644 index 0000000000000000000000000000000000000000..38cfeb1d0249f753b7ba69ebc9df44c9ef97367a --- /dev/null +++ b/ets2panda/linter/test_rules/rule155.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022-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. + */ + +@Sendable +class A{ + a: number; + b: number = 1; + c!: number; + d!: number = 1; + e?: number; +} + +class B{ + a: number; + b: number = 1; + c!: number; + d!: number = 1; + e?: number; +} diff --git a/ets2panda/linter/test_rules/rule155.ts.autofix.skip b/ets2panda/linter/test_rules/rule155.ts.autofix.skip new file mode 100644 index 0000000000000000000000000000000000000000..13982e9c910b164b802d0921a8cc7d56e1bf383e --- /dev/null +++ b/ets2panda/linter/test_rules/rule155.ts.autofix.skip @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023-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/ets2panda/linter/test_rules/rule155.ts.json b/ets2panda/linter/test_rules/rule155.ts.json new file mode 100644 index 0000000000000000000000000000000000000000..a19d7994a25a3fb0eecf68105a36df4749c1ef1d --- /dev/null +++ b/ets2panda/linter/test_rules/rule155.ts.json @@ -0,0 +1,58 @@ +{ + "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": 20, + "column": 5, + "problem": "SendableDefiniteAssignment", + "rule": "Definite assignment assertion in not allowed in \"Sendable\" classes and interfaces (arkts-sendable-definite-assignment)" + }, + { + "line": 21, + "column": 5, + "problem": "SendableDefiniteAssignment", + "rule": "Definite assignment assertion in not allowed in \"Sendable\" classes and interfaces (arkts-sendable-definite-assignment)" + }, + { + "line": 28, + "column": 5, + "problem": "DefiniteAssignment", + "suggest": "", + "rule": "Definite assignment assertions are not supported (arkts-no-definite-assignment)" + }, + { + "line": 29, + "column": 5, + "problem": "DefiniteAssignment", + "suggest": "", + "rule": "Definite assignment assertions are not supported (arkts-no-definite-assignment)" + }, + { + "line": 18, + "column": 5, + "problem": "StrictDiagnostic", + "suggest": "Property 'a' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'a' has no initializer and is not definitely assigned in the constructor." + }, + { + "line": 26, + "column": 5, + "problem": "StrictDiagnostic", + "suggest": "Property 'a' has no initializer and is not definitely assigned in the constructor.", + "rule": "Property 'a' has no initializer and is not definitely assigned in the constructor." + } + ] +}