Skip to main content

emmylua_code_analysis/db_index/signature/
signature.rs

1use serde::de::{self, Visitor};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt;
4use std::{collections::HashMap, sync::Arc};
5
6use emmylua_parser::{LuaAstNode, LuaClosureExpr, LuaDocFuncType};
7use rowan::TextSize;
8
9use super::return_rows;
10use crate::db_index::signature::async_state::AsyncState;
11use crate::{
12    FileId,
13    db_index::{LuaFunctionType, LuaType},
14};
15use crate::{LuaAttributeUse, SemanticModel, first_param_may_not_self};
16
17#[derive(Debug)]
18pub struct LuaSignature {
19    pub generic_params: Vec<Arc<LuaGenericParamInfo>>,
20    pub overloads: Vec<Arc<LuaFunctionType>>,
21    pub param_docs: HashMap<usize, LuaDocParamInfo>,
22    pub params: Vec<String>,
23    pub return_docs: Vec<LuaDocReturnInfo>,
24    pub return_overloads: Vec<LuaDocReturnOverloadInfo>,
25    pub resolve_return: SignatureReturnStatus,
26    pub is_colon_define: bool,
27    pub async_state: AsyncState,
28    pub nodiscard: Option<LuaNoDiscard>,
29    pub is_vararg: bool,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum LuaNoDiscard {
34    NoDiscard,
35    NoDiscardWithMessage(Box<String>),
36}
37
38impl Default for LuaSignature {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl LuaSignature {
45    pub fn new() -> Self {
46        Self {
47            generic_params: Vec::new(),
48            overloads: Vec::new(),
49            param_docs: HashMap::new(),
50            params: Vec::new(),
51            return_docs: Vec::new(),
52            return_overloads: Vec::new(),
53            resolve_return: SignatureReturnStatus::UnResolve,
54            is_colon_define: false,
55            async_state: AsyncState::None,
56            nodiscard: None,
57            is_vararg: false,
58        }
59    }
60
61    pub fn is_generic(&self) -> bool {
62        !self.generic_params.is_empty()
63    }
64
65    pub fn is_resolve_return(&self) -> bool {
66        self.resolve_return != SignatureReturnStatus::UnResolve
67    }
68
69    pub fn get_type_params(&self) -> Vec<(String, Option<LuaType>)> {
70        let mut type_params = Vec::new();
71        for (idx, param_name) in self.params.iter().enumerate() {
72            if let Some(param_info) = self.param_docs.get(&idx) {
73                type_params.push((param_name.clone(), Some(param_info.type_ref.clone())));
74            } else {
75                type_params.push((param_name.clone(), None));
76            }
77        }
78
79        type_params
80    }
81
82    pub fn find_param_idx(&self, param_name: &str) -> Option<usize> {
83        self.params.iter().position(|name| name == param_name)
84    }
85
86    pub fn get_param_info_by_name(&self, param_name: &str) -> Option<&LuaDocParamInfo> {
87        // fast enough
88        let idx = self.params.iter().position(|name| name == param_name)?;
89        self.param_docs.get(&idx)
90    }
91
92    pub fn get_param_name_by_id(&self, idx: usize) -> Option<String> {
93        if idx < self.params.len() {
94            return Some(self.params[idx].clone());
95        } else if let Some(name) = self.params.last()
96            && name == "..."
97        {
98            return Some(name.clone());
99        }
100
101        None
102    }
103
104    pub fn get_param_info_by_id(&self, idx: usize) -> Option<&LuaDocParamInfo> {
105        if idx < self.params.len() {
106            return self.param_docs.get(&idx);
107        } else if let Some(name) = self.params.last()
108            && name == "..."
109        {
110            return self.param_docs.get(&(self.params.len() - 1));
111        }
112
113        None
114    }
115
116    pub fn get_return_type(&self) -> LuaType {
117        return_rows::get_return_type(&self.return_docs, &self.return_overloads)
118    }
119
120    pub(crate) fn get_overload_row_slot(row: &[LuaType], idx: usize) -> LuaType {
121        return_rows::get_overload_row_slot(row, idx)
122    }
123
124    pub(crate) fn row_to_return_type(row: Vec<LuaType>) -> LuaType {
125        return_rows::row_to_return_type(row)
126    }
127
128    pub(crate) fn return_type_to_row(return_type: LuaType) -> Vec<LuaType> {
129        return_rows::return_type_to_row(return_type)
130    }
131
132    pub fn is_method(&self, semantic_model: &SemanticModel, owner_type: Option<&LuaType>) -> bool {
133        if self.is_colon_define {
134            return true;
135        }
136
137        if let Some(param_info) = self.get_param_info_by_id(0) {
138            let param_type = &param_info.type_ref;
139            if param_type.is_self_infer() {
140                return true;
141            }
142            match owner_type {
143                Some(owner_type) => {
144                    // 一些类型不应该被视为 method
145                    if matches!(owner_type, LuaType::Ref(_) | LuaType::Def(_))
146                        && first_param_may_not_self(param_type)
147                    {
148                        return false;
149                    }
150
151                    semantic_model
152                        .type_check(owner_type, &param_info.type_ref)
153                        .is_ok()
154                }
155                None => param_info.name == "self",
156            }
157        } else {
158            false
159        }
160    }
161
162    pub fn to_doc_func_type(&self) -> Arc<LuaFunctionType> {
163        let params = self.get_type_params();
164        let return_type = self.get_return_type();
165        let is_vararg = self.is_vararg;
166        let func_type = LuaFunctionType::new(
167            self.async_state,
168            self.is_colon_define,
169            is_vararg,
170            params,
171            return_type,
172        );
173        Arc::new(func_type)
174    }
175
176    pub fn to_call_operator_func_type(&self) -> Arc<LuaFunctionType> {
177        let mut params = self.get_type_params();
178        if !params.is_empty() && !self.is_colon_define {
179            params.remove(0);
180        }
181
182        let return_type = self.get_return_type();
183        let func_type =
184            LuaFunctionType::new(self.async_state, false, self.is_vararg, params, return_type);
185        Arc::new(func_type)
186    }
187}
188
189#[derive(Debug)]
190pub struct LuaDocParamInfo {
191    pub name: String,
192    pub type_ref: LuaType,
193    pub nullable: bool,
194    pub description: Option<String>,
195    pub attributes: Option<Vec<LuaAttributeUse>>,
196}
197
198impl LuaDocParamInfo {
199    pub fn get_attribute_by_name(&self, name: &str) -> Option<&LuaAttributeUse> {
200        self.attributes
201            .iter()
202            .flatten()
203            .find(|attr| attr.id.get_name() == name)
204    }
205}
206
207#[derive(Debug, Clone)]
208pub struct LuaDocReturnInfo {
209    pub name: Option<String>,
210    pub type_ref: LuaType,
211    pub description: Option<String>,
212    pub attributes: Option<Vec<LuaAttributeUse>>,
213}
214
215#[derive(Debug, Clone)]
216pub struct LuaDocReturnOverloadInfo {
217    pub type_refs: Vec<LuaType>,
218    pub description: Option<String>,
219}
220
221#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
222pub struct LuaSignatureId {
223    file_id: FileId,
224    position: TextSize,
225}
226
227impl Serialize for LuaSignatureId {
228    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
229    where
230        S: Serializer,
231    {
232        let value = format!("{}|{}", self.file_id.id, u32::from(self.position));
233        serializer.serialize_str(&value)
234    }
235}
236
237impl<'de> Deserialize<'de> for LuaSignatureId {
238    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
239    where
240        D: Deserializer<'de>,
241    {
242        struct LuaSignatureIdVisitor;
243
244        impl<'de> Visitor<'de> for LuaSignatureIdVisitor {
245            type Value = LuaSignatureId;
246
247            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
248                formatter.write_str("a string with format 'file_id:position'")
249            }
250
251            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
252            where
253                E: de::Error,
254            {
255                let parts: Vec<&str> = value.split('|').collect();
256                if parts.len() != 2 {
257                    return Err(E::custom("expected format 'file_id:position'"));
258                }
259
260                let file_id = FileId {
261                    id: parts[0]
262                        .parse()
263                        .map_err(|e| E::custom(format!("invalid file_id: {}", e)))?,
264                };
265                let position = TextSize::new(
266                    parts[1]
267                        .parse()
268                        .map_err(|e| E::custom(format!("invalid position: {}", e)))?,
269                );
270
271                Ok(LuaSignatureId { file_id, position })
272            }
273        }
274
275        deserializer.deserialize_str(LuaSignatureIdVisitor)
276    }
277}
278
279impl LuaSignatureId {
280    pub fn from_closure(file_id: FileId, closure: &LuaClosureExpr) -> Self {
281        Self {
282            file_id,
283            position: closure.get_position(),
284        }
285    }
286
287    pub fn from_doc_func(file_id: FileId, func_type: &LuaDocFuncType) -> Self {
288        Self {
289            file_id,
290            position: func_type.get_position(),
291        }
292    }
293
294    pub fn get_file_id(&self) -> FileId {
295        self.file_id
296    }
297
298    pub fn get_position(&self) -> TextSize {
299        self.position
300    }
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
304pub enum SignatureReturnStatus {
305    UnResolve,
306    DocResolve,
307    InferResolve,
308}
309
310#[derive(Debug, Clone)]
311pub struct LuaGenericParamInfo {
312    pub name: String,
313    pub constraint: Option<LuaType>,
314    pub attributes: Option<Vec<LuaAttributeUse>>,
315}
316
317impl LuaGenericParamInfo {
318    pub fn new(
319        name: String,
320        constraint: Option<LuaType>,
321        attributes: Option<Vec<LuaAttributeUse>>,
322    ) -> Self {
323        Self {
324            name,
325            constraint,
326            attributes,
327        }
328    }
329}