emmylua_code_analysis/db_index/signature/
signature.rs1use 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 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 = ¶m_info.type_ref;
139 if param_type.is_self_infer() {
140 return true;
141 }
142 match owner_type {
143 Some(owner_type) => {
144 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, ¶m_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}