1/* 2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { DiagnosticMessageChain } from "../_namespaces/ts"; 17import { DiagnosticChecker } from "../_namespaces/ts.ArkTSLinter_1_0"; 18// Current approach relates on error code and error message matching and it is quite fragile, 19// so this place should be checked thoroughly in the case of typescript upgrade 20export const TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE = 2322; 21export const TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type '(.*)\bunknown\b(.*)' is not assignable to type '.*'\.$/; 22export const TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'null' is not assignable to type '.*'\.$/; 23export const TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE = /^Type 'undefined' is not assignable to type '.*'\.$/; 24 25export const ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE = 2345; 26export 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 '.*'\.$/; 27export 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 '.*'\.$/; 28 29export const NO_OVERLOAD_MATCHES_THIS_CALL_ERROR_CODE = 2769; 30 31export class LibraryTypeCallDiagnosticChecker implements DiagnosticChecker { 32 inLibCall: boolean = false; 33 diagnosticMessages: Array<DiagnosticMessageChain> | undefined; 34 filteredDiagnosticMessages: DiagnosticMessageChain[] = []; 35 36 constructor(filteredDiagnosticMessages: DiagnosticMessageChain[]) { 37 this.filteredDiagnosticMessages = filteredDiagnosticMessages; 38 } 39 40 configure(inLibCall: boolean, diagnosticMessages: Array<DiagnosticMessageChain>) { 41 this.inLibCall = inLibCall; 42 this.diagnosticMessages = diagnosticMessages; 43 } 44 45 checkMessageText(msg: string): boolean { 46 if (this.inLibCall) { 47 const match = msg.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE) || 48 msg.match(ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE) || 49 msg.match(TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE) || 50 msg.match(TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE); 51 return !match; 52 } 53 return true; 54 } 55 56 checkMessageChain(chain: DiagnosticMessageChain): boolean { 57 if (chain.code == TYPE_0_IS_NOT_ASSIGNABLE_TO_TYPE_1_ERROR_CODE) { 58 if (chain.messageText.match(TYPE_UNKNOWN_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) { 59 return false; 60 } 61 if (this.inLibCall && chain.messageText.match(TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) { 62 return false; 63 } 64 if (this.inLibCall && chain.messageText.match(TYPE_NULL_IS_NOT_ASSIGNABLE_TO_TYPE_1_RE)) { 65 return false; 66 } 67 } 68 if (chain.code == ARGUMENT_OF_TYPE_0_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_ERROR_CODE) { 69 if (this.inLibCall && chain.messageText.match(ARGUMENT_OF_TYPE_UNDEFINED_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE)) { 70 return false; 71 } 72 if (this.inLibCall && chain.messageText.match(ARGUMENT_OF_TYPE_NULL_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE_1_RE)) { 73 return false; 74 } 75 } 76 return chain.next == undefined ? true : this.checkMessageChain(chain.next[0]); 77 }; 78 79 checkFilteredDiagnosticMessages(msgText: DiagnosticMessageChain | string) { 80 if (this.filteredDiagnosticMessages.length == 0) { 81 return true; 82 } 83 84 if (typeof msgText !== 'string' && this.filteredDiagnosticMessages.includes(msgText)) { 85 return false; 86 } 87 88 for (const msgChain of this.filteredDiagnosticMessages) { 89 if (typeof msgText == 'string') { 90 if (msgText == msgChain.messageText) { 91 return false; 92 } 93 continue; 94 } 95 96 let curMsg: DiagnosticMessageChain | undefined = msgText; 97 let curFilteredMsg: DiagnosticMessageChain | undefined = msgChain; 98 while (curMsg) { 99 if (!curFilteredMsg) { 100 return true; 101 } 102 103 if (curMsg.code != curFilteredMsg.code) { 104 return true; 105 } 106 107 if (curMsg.messageText != curFilteredMsg.messageText) { 108 return true; 109 } 110 111 curMsg = curMsg.next ? curMsg.next[0]: undefined; 112 curFilteredMsg = curFilteredMsg.next ? curFilteredMsg.next[0]: undefined; 113 } 114 115 return false; 116 } 117 return true; 118 } 119 120 checkDiagnosticMessage(msgText: string | DiagnosticMessageChain): boolean { 121 if (!this.diagnosticMessages) { 122 return false; 123 } 124 125 if (this.inLibCall && !this.checkFilteredDiagnosticMessages(msgText)) { 126 return false; 127 } 128 129 if (typeof msgText == 'string') { 130 return this.checkMessageText(msgText); 131 } 132 133 if (!this.checkMessageChain(msgText)) { 134 this.diagnosticMessages.push(msgText); 135 return false; 136 } 137 return true; 138 } 139} 140