• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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