Skip to content

Commit 4621da4

Browse files
committed
fix(hover): call function
1 parent 1405446 commit 4621da4

13 files changed

Lines changed: 619 additions & 360 deletions

File tree

crates/emmylua_code_analysis/src/semantic/infer/infer_call/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mod infer_setmetatable;
3030

3131
pub type InferCallFuncResult = Result<Arc<LuaFunctionType>, InferFailReason>;
3232

33+
// TODO: 如果没有完全匹配的签名也会返回一个不精确的类型, 考虑返回`None`
3334
pub fn infer_call_expr_func(
3435
db: &DbIndex,
3536
cache: &mut LuaInferCache,

crates/emmylua_code_analysis/src/semantic/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ impl<'a> SemanticModel<'a> {
183183
.ok()
184184
}
185185

186+
pub fn callable_accepts_args(
187+
&self,
188+
func: &LuaFunctionType,
189+
expr_types: &[LuaType],
190+
is_colon_call: bool,
191+
arg_count: Option<usize>,
192+
) -> bool {
193+
callable_accepts_args(self.db, func, expr_types, is_colon_call, arg_count)
194+
}
195+
186196
/// 推断表达式列表类型, 位于最后的表达式会触发多值推断
187197
pub fn infer_expr_list_types(
188198
&self,

crates/emmylua_ls/src/handlers/hover/build_hover.rs

Lines changed: 35 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ use lsp_types::{Hover, HoverContents, MarkedString, MarkupContent};
1010
use rowan::TextRange;
1111

1212
use crate::handlers::common::{find_decl_origin_owners, find_member_origin_owners};
13-
use crate::handlers::hover::function::{build_function_hover, is_function};
13+
use crate::handlers::hover::function::{build_function_hover, has_function_candidate, is_function};
1414
use crate::handlers::hover::humanize_type_decl::build_type_decl_hover;
1515
use crate::handlers::hover::humanize_types::hover_humanize_type;
1616

17-
use super::{hover_builder::HoverBuilder, humanize_types::hover_const_type};
17+
use super::{
18+
HoverDeclContext, HoverDeclInfo, hover_builder::HoverBuilder, humanize_types::hover_const_type,
19+
};
1820

1921
pub fn build_semantic_info_hover(
2022
semantic_model: &SemanticModel,
@@ -120,24 +122,25 @@ fn build_decl_hover(
120122
) -> Option<()> {
121123
let decl = db.get_decl_index().get_decl(&decl_id)?;
122124

123-
let mut semantic_decls =
125+
let semantic_decls =
124126
find_decl_origin_owners(builder.semantic_model, decl_id).get_types(builder.semantic_model);
125127

126128
// 处理类型签名
127129
if is_function(&typ) {
128-
adjust_semantic_decls(
129-
builder,
130-
&mut semantic_decls,
131-
&LuaSemanticDeclId::LuaDecl(decl_id),
132-
&typ,
130+
let origin_decls = into_hover_decl_infos(semantic_decls);
131+
let hover_decl_context = HoverDeclContext::new(
132+
HoverDeclInfo::new(LuaSemanticDeclId::LuaDecl(decl_id), typ.clone()),
133+
origin_decls,
133134
);
134135

135136
// 处理函数类型
136-
build_function_hover(builder, db, &semantic_decls);
137+
build_function_hover(builder, db, &hover_decl_context);
137138

138-
if let Some((LuaSemanticDeclId::Member(member_id), _)) = semantic_decls
139+
if let Some(decl_info) = hover_decl_context
140+
.origin_decls()
139141
.iter()
140-
.find(|(decl, _)| matches!(decl, LuaSemanticDeclId::Member(_)))
142+
.find(|decl_info| matches!(decl_info.id(), LuaSemanticDeclId::Member(_)))
143+
&& let LuaSemanticDeclId::Member(member_id) = decl_info.id()
141144
{
142145
let member = db.get_member_index().get_member(member_id);
143146
builder.set_location_path(member);
@@ -225,16 +228,15 @@ fn build_member_hover(
225228
_ => return None,
226229
};
227230

231+
let origin_decls = into_hover_decl_infos(semantic_decls);
232+
let hover_decl_context = HoverDeclContext::new(
233+
HoverDeclInfo::new(LuaSemanticDeclId::Member(member_id), typ.clone()),
234+
origin_decls,
235+
);
236+
228237
// 当为表字段时, 如果能够追溯到该成员的定义为 function, 那么我们也需要显示方法的签名而不是当前字段的真实类型
229-
if is_function(&typ) || (!semantic_decls.is_empty() && is_function(&semantic_decls.first()?.1))
230-
{
231-
adjust_semantic_decls(
232-
builder,
233-
&mut semantic_decls,
234-
&LuaSemanticDeclId::Member(member_id),
235-
&typ,
236-
);
237-
build_function_hover(builder, db, &semantic_decls);
238+
if has_function_candidate(&hover_decl_context) {
239+
build_function_hover(builder, db, &hover_decl_context);
238240

239241
builder.set_location_path(Some(member));
240242

@@ -266,7 +268,12 @@ fn build_member_hover(
266268
let member_decl = LuaSemanticDeclId::Member(member.get_id());
267269
semantic_decl_set.insert(&member_decl);
268270
if !is_completion {
269-
semantic_decl_set.extend(semantic_decls.iter().map(|(decl, _)| decl));
271+
semantic_decl_set.extend(
272+
hover_decl_context
273+
.origin_decls()
274+
.iter()
275+
.map(|decl_info| decl_info.id()),
276+
);
270277
}
271278
for semantic_decl in semantic_decl_set {
272279
builder.add_description(semantic_decl);
@@ -276,6 +283,13 @@ fn build_member_hover(
276283
Some(())
277284
}
278285

286+
fn into_hover_decl_infos(semantic_decls: Vec<(LuaSemanticDeclId, LuaType)>) -> Vec<HoverDeclInfo> {
287+
semantic_decls
288+
.into_iter()
289+
.map(|(semantic_decl_id, typ)| HoverDeclInfo::new(semantic_decl_id, typ))
290+
.collect()
291+
}
292+
279293
pub fn add_signature_param_description(
280294
db: &DbIndex,
281295
marked_strings: &mut Vec<MarkedString>,
@@ -371,38 +385,3 @@ pub fn get_hover_type(builder: &HoverBuilder, semantic_model: &SemanticModel) ->
371385

372386
None
373387
}
374-
375-
fn adjust_semantic_decls(
376-
_builder: &mut HoverBuilder,
377-
semantic_decls: &mut Vec<(LuaSemanticDeclId, LuaType)>,
378-
current_semantic_decl_id: &LuaSemanticDeclId,
379-
current_type: &LuaType,
380-
) -> Option<()> {
381-
if let Some(pos) = semantic_decls
382-
.iter()
383-
.position(|(_, typ)| current_type == typ)
384-
{
385-
if pos != 0 {
386-
let item = semantic_decls.remove(pos);
387-
semantic_decls.insert(0, item);
388-
}
389-
} else {
390-
// semantic_decls 是追溯最初定义的结果, 不包含当前内容
391-
let current_len = semantic_decls.len();
392-
if current_len == 0 {
393-
// 没有最初定义, 直接添加原始内容
394-
semantic_decls.push((current_semantic_decl_id.clone(), current_type.clone()));
395-
}
396-
}
397-
398-
// 将第一个是 Signature 的放至前面, 因为我们会使用第一个作为主要签名
399-
if let Some(pos) = semantic_decls
400-
.iter()
401-
.position(|(_, typ)| typ.is_signature())
402-
{
403-
let item = semantic_decls.remove(pos);
404-
semantic_decls.insert(0, item);
405-
}
406-
407-
Some(())
408-
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use emmylua_code_analysis::{LuaSemanticDeclId, LuaType};
2+
3+
#[derive(Debug, Clone, PartialEq)]
4+
pub(crate) struct HoverDeclInfo {
5+
id: LuaSemanticDeclId,
6+
typ: LuaType,
7+
}
8+
9+
impl HoverDeclInfo {
10+
pub(crate) fn new(id: LuaSemanticDeclId, typ: LuaType) -> Self {
11+
Self { id, typ }
12+
}
13+
14+
pub(crate) fn id(&self) -> &LuaSemanticDeclId {
15+
&self.id
16+
}
17+
18+
pub(crate) fn typ(&self) -> &LuaType {
19+
&self.typ
20+
}
21+
}
22+
23+
#[derive(Debug, Clone)]
24+
pub(crate) struct HoverDeclContext {
25+
current_decl: HoverDeclInfo,
26+
origin_decls: Vec<HoverDeclInfo>,
27+
}
28+
29+
impl HoverDeclContext {
30+
pub(crate) fn new(current_decl: HoverDeclInfo, origin_decls: Vec<HoverDeclInfo>) -> Self {
31+
Self {
32+
current_decl,
33+
origin_decls,
34+
}
35+
}
36+
37+
pub(crate) fn current_decl(&self) -> &HoverDeclInfo {
38+
&self.current_decl
39+
}
40+
41+
pub(crate) fn origin_decls(&self) -> &[HoverDeclInfo] {
42+
&self.origin_decls
43+
}
44+
45+
fn primary_decl(&self) -> &HoverDeclInfo {
46+
self.origin_decls
47+
.iter()
48+
.find(|decl| decl.typ().is_signature())
49+
.or_else(|| {
50+
self.origin_decls
51+
.iter()
52+
.find(|decl| decl.typ() == self.current_decl.typ())
53+
})
54+
.or_else(|| self.origin_decls.first())
55+
.unwrap_or(&self.current_decl)
56+
}
57+
58+
pub(crate) fn ordered_decl_refs(&self) -> Vec<&HoverDeclInfo> {
59+
let mut decls = if self.origin_decls.is_empty() {
60+
vec![&self.current_decl]
61+
} else {
62+
self.origin_decls.iter().collect::<Vec<_>>()
63+
};
64+
65+
if let Some(pos) = decls
66+
.iter()
67+
.position(|decl| decl.typ() == self.current_decl.typ())
68+
{
69+
if pos != 0 {
70+
let item = decls.remove(pos);
71+
decls.insert(0, item);
72+
}
73+
}
74+
75+
let primary_decl = self.primary_decl();
76+
if let Some(pos) = decls.iter().position(|decl| *decl == primary_decl) {
77+
if pos != 0 {
78+
let item = decls.remove(pos);
79+
decls.insert(0, item);
80+
}
81+
}
82+
83+
decls
84+
}
85+
}

0 commit comments

Comments
 (0)