diff --git a/linter-4.2/src/TypeScriptLinter.ts b/linter-4.2/src/TypeScriptLinter.ts index 73f9b3e6110ef6b7f2be0aa30850982a78f2a4f0..7aad7c66af0f9d2416b3eea74d21b0ee3f2adf4b 100644 --- a/linter-4.2/src/TypeScriptLinter.ts +++ b/linter-4.2/src/TypeScriptLinter.ts @@ -1989,14 +1989,22 @@ export class TypeScriptLinter { } private handleLibraryTypeCall(callExpr: ts.CallExpression) { + // Current approach relates on error code and error message matching and it is quite fragile, + // so this place should be checked thoroughly in the case of typescript upgrade const TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE = 2322; - const TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'unknown' is not assignable to type '.*'.$/; + const TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'unknown' is not assignable to type '.*'\.$/; + const TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'null' is not assignable to type '.*'\.$/; + const TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'undefined' is not assignable to type '.*'\.$/; + const ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE = 2345; - const ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'null' is not assignable to parameter of type '.*'.$/; + const ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'null' is not assignable to parameter of type '.*'\.$/; + const ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'undefined' is not assignable to parameter of type '.*'\.$/; const chainCheck = (n: ts.DiagnosticMessageChain): boolean => { if (n.code == TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE && - n.messageText.match(TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) { + (n.messageText.match(TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE) || + n.messageText.match(TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE) || + n.messageText.match(TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE))) { return false; } return n.next == undefined ? true : chainCheck(n.next[0]); @@ -2004,7 +2012,8 @@ export class TypeScriptLinter { const msgCheck = (msg: string): boolean => { if (this.tsUtils.isLibraryType(this.tsTypeChecker.getTypeAtLocation(callExpr.expression))) { - const match = msg.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE); + const match = msg.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE) || + msg.match(ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE); return !match; } return true; diff --git a/linter-4.2/test/dynamic_lib.d.ts b/linter-4.2/test/dynamic_lib.d.ts index e8a16c2729a992f9f07befba4b8a92bfe991c64a..776c555daaf4050c0be5cf11579a2c3bcaa8d57d 100644 --- a/linter-4.2/test/dynamic_lib.d.ts +++ b/linter-4.2/test/dynamic_lib.d.ts @@ -39,3 +39,7 @@ export interface DynLibIC extends DynLibC {} export interface DynLibII extends DynLibI {} export class DynLibCC extends DynLibC {} export class DynLibCI implements DynLibI {} + +export declare class C1 {} + +export declare function f2(c: C1): void; diff --git a/linter-4.2/test/null_check_calls.ts b/linter-4.2/test/null_check_calls.ts index cce1b98a254515b4f0be5ca0066f8130459f0f48..18bcaa037e2ad9769e4af2be55978dc84bed139a 100644 --- a/linter-4.2/test/null_check_calls.ts +++ b/linter-4.2/test/null_check_calls.ts @@ -14,7 +14,18 @@ */ import { ff } from "./oh_modules/ohos_lib"; -import { f, bar, applyToUnknown, fooExecute } from "./dynamic_lib"; +import { f, f2, bar, applyToUnknown, fooExecute, C1 } from "./dynamic_lib"; + +let a1: C1 = new C1() + +function g1(): C1 | null { + if (a1) { + return a1 + } + return null +} + +f2(g1()) bar(null); bar(null, null); diff --git a/linter-4.2/test/null_check_calls.ts.relax.json b/linter-4.2/test/null_check_calls.ts.relax.json index 3450a6d1db5f576702852e7ae4dcba139d2933fd..3a804136536fcb112a1a46164903181e1c92e846 100644 --- a/linter-4.2/test/null_check_calls.ts.relax.json +++ b/linter-4.2/test/null_check_calls.ts.relax.json @@ -15,7 +15,7 @@ ], "nodes": [ { - "line": 26, + "line": 37, "column": 5, "problem": "StrictDiagnostic", "suggest": "Argument of type 'null' is not assignable to parameter of type 'number[]'.", diff --git a/linter-4.2/test/null_check_calls.ts.strict.json b/linter-4.2/test/null_check_calls.ts.strict.json index 3450a6d1db5f576702852e7ae4dcba139d2933fd..3a804136536fcb112a1a46164903181e1c92e846 100644 --- a/linter-4.2/test/null_check_calls.ts.strict.json +++ b/linter-4.2/test/null_check_calls.ts.strict.json @@ -15,7 +15,7 @@ ], "nodes": [ { - "line": 26, + "line": 37, "column": 5, "problem": "StrictDiagnostic", "suggest": "Argument of type 'null' is not assignable to parameter of type 'number[]'.", diff --git a/linter-4.2/test/undefined_check_calls.ts b/linter-4.2/test/undefined_check_calls.ts new file mode 100644 index 0000000000000000000000000000000000000000..45b97e57d2b236e1ec3b9a483733bd16154fee31 --- /dev/null +++ b/linter-4.2/test/undefined_check_calls.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022-2023 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 { ff } from "./oh_modules/ohos_lib"; +import { f, f2, bar, applyToUnknown, fooExecute, C1 } from "./dynamic_lib"; + +let a1: C1 = new C1() + +function g1(): C1 | undefined { + if (a1) { + return a1 + } + return undefined +} + +f2(g1()) + +bar(undefined); +bar(undefined, undefined); +applyToUnknown(undefined); +fooExecute(undefined); + +function fff(a: Array): void {} + +fff(undefined); +ff(undefined); +f(undefined); diff --git a/linter-4.2/test/undefined_check_calls.ts.autofix.skip b/linter-4.2/test/undefined_check_calls.ts.autofix.skip new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/linter-4.2/test/undefined_check_calls.ts.relax.json b/linter-4.2/test/undefined_check_calls.ts.relax.json new file mode 100644 index 0000000000000000000000000000000000000000..2340a8686acb7f368b97d63359037a983888b5a6 --- /dev/null +++ b/linter-4.2/test/undefined_check_calls.ts.relax.json @@ -0,0 +1,25 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 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": 37, + "column": 5, + "problem": "StrictDiagnostic", + "suggest": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'.", + "rule": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'." + } + ] +} \ No newline at end of file diff --git a/linter-4.2/test/undefined_check_calls.ts.strict.json b/linter-4.2/test/undefined_check_calls.ts.strict.json new file mode 100644 index 0000000000000000000000000000000000000000..2340a8686acb7f368b97d63359037a983888b5a6 --- /dev/null +++ b/linter-4.2/test/undefined_check_calls.ts.strict.json @@ -0,0 +1,25 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 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": 37, + "column": 5, + "problem": "StrictDiagnostic", + "suggest": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'.", + "rule": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'." + } + ] +} \ No newline at end of file diff --git a/linter/src/TypeScriptLinter.ts b/linter/src/TypeScriptLinter.ts index 68f26886d9ea2b7c468ef92ebb2000b7e831c2a1..3ed2c916f8e95fb3d7f7d8ec43da3c63c502848e 100644 --- a/linter/src/TypeScriptLinter.ts +++ b/linter/src/TypeScriptLinter.ts @@ -1564,14 +1564,22 @@ export class TypeScriptLinter { } private handleLibraryTypeCall(callExpr: ts.CallExpression) { + // Current approach relates on error code and error message matching and it is quite fragile, + // so this place should be checked thoroughly in the case of typescript upgrade const TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE = 2322; - const TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'unknown' is not assignable to type '.*'.$/; + const TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'unknown' is not assignable to type '.*'\.$/; + const TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'null' is not assignable to type '.*'\.$/; + const TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'undefined' is not assignable to type '.*'\.$/; + const ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE = 2345; - const ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'null' is not assignable to parameter of type '.*'.$/; + const ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'null' is not assignable to parameter of type '.*'\.$/; + const ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE = /^Argument of type 'undefined' is not assignable to parameter of type '.*'\.$/; const chainCheck = (n: ts.DiagnosticMessageChain): boolean => { if (n.code == TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE && - n.messageText.match(TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) { + (n.messageText.match(TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE) || + n.messageText.match(TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE) || + n.messageText.match(TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE))) { return false; } return n.next == undefined ? true : chainCheck(n.next[0]); @@ -1579,7 +1587,8 @@ export class TypeScriptLinter { const msgCheck = (msg: string): boolean => { if (this.tsUtils.isLibraryType(this.tsTypeChecker.getTypeAtLocation(callExpr.expression))) { - const match = msg.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE); + const match = msg.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE) || + msg.match(ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE); return !match; } return true; diff --git a/linter/test/dynamic_lib.d.ts b/linter/test/dynamic_lib.d.ts index e8a16c2729a992f9f07befba4b8a92bfe991c64a..776c555daaf4050c0be5cf11579a2c3bcaa8d57d 100644 --- a/linter/test/dynamic_lib.d.ts +++ b/linter/test/dynamic_lib.d.ts @@ -39,3 +39,7 @@ export interface DynLibIC extends DynLibC {} export interface DynLibII extends DynLibI {} export class DynLibCC extends DynLibC {} export class DynLibCI implements DynLibI {} + +export declare class C1 {} + +export declare function f2(c: C1): void; diff --git a/linter/test/null_check_calls.ts b/linter/test/null_check_calls.ts index cce1b98a254515b4f0be5ca0066f8130459f0f48..18bcaa037e2ad9769e4af2be55978dc84bed139a 100644 --- a/linter/test/null_check_calls.ts +++ b/linter/test/null_check_calls.ts @@ -14,7 +14,18 @@ */ import { ff } from "./oh_modules/ohos_lib"; -import { f, bar, applyToUnknown, fooExecute } from "./dynamic_lib"; +import { f, f2, bar, applyToUnknown, fooExecute, C1 } from "./dynamic_lib"; + +let a1: C1 = new C1() + +function g1(): C1 | null { + if (a1) { + return a1 + } + return null +} + +f2(g1()) bar(null); bar(null, null); diff --git a/linter/test/null_check_calls.ts.relax.json b/linter/test/null_check_calls.ts.relax.json index 3450a6d1db5f576702852e7ae4dcba139d2933fd..3a804136536fcb112a1a46164903181e1c92e846 100644 --- a/linter/test/null_check_calls.ts.relax.json +++ b/linter/test/null_check_calls.ts.relax.json @@ -15,7 +15,7 @@ ], "nodes": [ { - "line": 26, + "line": 37, "column": 5, "problem": "StrictDiagnostic", "suggest": "Argument of type 'null' is not assignable to parameter of type 'number[]'.", diff --git a/linter/test/null_check_calls.ts.strict.json b/linter/test/null_check_calls.ts.strict.json index 3450a6d1db5f576702852e7ae4dcba139d2933fd..3a804136536fcb112a1a46164903181e1c92e846 100644 --- a/linter/test/null_check_calls.ts.strict.json +++ b/linter/test/null_check_calls.ts.strict.json @@ -15,7 +15,7 @@ ], "nodes": [ { - "line": 26, + "line": 37, "column": 5, "problem": "StrictDiagnostic", "suggest": "Argument of type 'null' is not assignable to parameter of type 'number[]'.", diff --git a/linter/test/undefined_check_calls.ts b/linter/test/undefined_check_calls.ts new file mode 100644 index 0000000000000000000000000000000000000000..45b97e57d2b236e1ec3b9a483733bd16154fee31 --- /dev/null +++ b/linter/test/undefined_check_calls.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022-2023 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 { ff } from "./oh_modules/ohos_lib"; +import { f, f2, bar, applyToUnknown, fooExecute, C1 } from "./dynamic_lib"; + +let a1: C1 = new C1() + +function g1(): C1 | undefined { + if (a1) { + return a1 + } + return undefined +} + +f2(g1()) + +bar(undefined); +bar(undefined, undefined); +applyToUnknown(undefined); +fooExecute(undefined); + +function fff(a: Array): void {} + +fff(undefined); +ff(undefined); +f(undefined); diff --git a/linter/test/undefined_check_calls.ts.autofix.skip b/linter/test/undefined_check_calls.ts.autofix.skip new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/linter/test/undefined_check_calls.ts.relax.json b/linter/test/undefined_check_calls.ts.relax.json new file mode 100644 index 0000000000000000000000000000000000000000..2340a8686acb7f368b97d63359037a983888b5a6 --- /dev/null +++ b/linter/test/undefined_check_calls.ts.relax.json @@ -0,0 +1,25 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 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": 37, + "column": 5, + "problem": "StrictDiagnostic", + "suggest": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'.", + "rule": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'." + } + ] +} \ No newline at end of file diff --git a/linter/test/undefined_check_calls.ts.strict.json b/linter/test/undefined_check_calls.ts.strict.json new file mode 100644 index 0000000000000000000000000000000000000000..2340a8686acb7f368b97d63359037a983888b5a6 --- /dev/null +++ b/linter/test/undefined_check_calls.ts.strict.json @@ -0,0 +1,25 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 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": 37, + "column": 5, + "problem": "StrictDiagnostic", + "suggest": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'.", + "rule": "Argument of type 'undefined' is not assignable to parameter of type 'number[]'." + } + ] +} \ No newline at end of file