Skip to content

Commit 6f229ee

Browse files
committed
support override hint
1 parent 33de948 commit 6f229ee

File tree

3 files changed

+143
-3
lines changed

3 files changed

+143
-3
lines changed

crates/code_analysis/src/semantic/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ impl<'a> SemanticModel<'a> {
7474
self.db.get_vfs().get_document(&file_id)
7575
}
7676

77+
pub fn get_root_by_file_id(&self, file_id: FileId) -> Option<LuaChunk> {
78+
Some(self.db.get_vfs().get_syntax_tree(&file_id)?.get_chunk_node())
79+
}
80+
7781
pub fn get_file_parse_error(&self) -> Option<Vec<(String, TextRange)>> {
7882
self.db.get_vfs().get_file_parse_error(&self.file_id)
7983
}

crates/code_analysis/src/vfs/document.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ impl<'a> LuaDocument<'a> {
9595
})
9696
}
9797

98+
pub fn to_lsp_position(&self, offset: TextSize) -> Option<lsp_types::Position> {
99+
let line_col = self.get_line_col(offset)?;
100+
Some(lsp_types::Position {
101+
line: line_col.0 as u32,
102+
character: line_col.1 as u32,
103+
})
104+
}
105+
98106
pub fn to_rowan_range(&self, range: lsp_types::Range) -> Option<TextRange> {
99107
let start = self.get_offset(range.start.line as usize, range.start.character as usize)?;
100108
let end = self.get_offset(range.end.line as usize, range.end.character as usize)?;

crates/emmylua_ls/src/handlers/inlay_hint/build_inlay_hint.rs

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
use std::collections::HashMap;
22

3-
use code_analysis::{LuaFunctionType, LuaPropertyOwnerId, LuaSignatureId, LuaType, SemanticModel};
4-
use emmylua_parser::{LuaAst, LuaAstNode, LuaCallExpr, LuaClosureExpr, LuaExpr, LuaLocalName};
5-
use lsp_types::{InlayHint, InlayHintKind, InlayHintLabel};
3+
use code_analysis::{
4+
FileId, InferGuard, LuaFunctionType, LuaMemberId, LuaMemberKey, LuaMemberOwner,
5+
LuaPropertyOwnerId, LuaSignatureId, LuaType, SemanticModel,
6+
};
7+
use emmylua_parser::{
8+
LuaAst, LuaAstNode, LuaCallExpr, LuaClosureExpr, LuaExpr, LuaFuncStat, LuaIndexExpr,
9+
LuaLocalName, LuaSyntaxId, LuaVarExpr,
10+
};
11+
use lsp_types::{InlayHint, InlayHintKind, InlayHintLabel, InlayHintLabelPart};
612
use rowan::NodeOrToken;
713

814
use crate::util::humanize_type;
@@ -22,6 +28,9 @@ pub fn build_inlay_hints(semantic_model: &mut SemanticModel) -> Option<Vec<Inlay
2228
LuaAst::LuaLocalName(local_name) => {
2329
build_local_name_hint(semantic_model, &mut result, local_name);
2430
}
31+
LuaAst::LuaFuncStat(func_stat) => {
32+
build_func_stat_override_hint(semantic_model, &mut result, func_stat);
33+
}
2534
_ => {}
2635
}
2736
}
@@ -360,3 +369,122 @@ fn build_local_name_hint(
360369

361370
Some(())
362371
}
372+
373+
fn build_func_stat_override_hint(
374+
semantic_model: &mut SemanticModel,
375+
result: &mut Vec<InlayHint>,
376+
func_stat: LuaFuncStat,
377+
) -> Option<()> {
378+
if !semantic_model.get_emmyrc().hint.override_hint {
379+
return Some(());
380+
}
381+
382+
let func_name = func_stat.get_func_name()?;
383+
if let LuaVarExpr::IndexExpr(index_expr) = func_name {
384+
let prefix_expr = index_expr.get_prefix_expr()?;
385+
let prefix_type = semantic_model.infer_expr(prefix_expr.into())?;
386+
if let LuaType::Def(id) = prefix_type {
387+
let supers = semantic_model
388+
.get_db()
389+
.get_type_index()
390+
.get_super_types(&id)?;
391+
392+
let name = index_expr.get_index_key()?;
393+
let member_key: LuaMemberKey = name.into();
394+
let infer_guard = &mut InferGuard::new();
395+
for super_type in supers {
396+
if let Some(member_id) =
397+
get_super_member_id(semantic_model, super_type, &member_key, infer_guard)
398+
{
399+
let member = semantic_model
400+
.get_db()
401+
.get_member_index()
402+
.get_member(&member_id)?;
403+
404+
let document = semantic_model.get_document();
405+
let last_paren_pos = func_stat
406+
.get_closure()?
407+
.get_params_list()?
408+
.get_range()
409+
.end();
410+
let last_paren_lsp_pos = document.to_lsp_position(last_paren_pos)?;
411+
412+
let file_id = member.get_file_id();
413+
let syntax_id = member.get_syntax_id();
414+
let lsp_location =
415+
get_override_lsp_location(semantic_model, file_id, syntax_id)?;
416+
let hint = InlayHint {
417+
kind: Some(InlayHintKind::TYPE),
418+
label: InlayHintLabel::LabelParts(vec![InlayHintLabelPart {
419+
value: "override".to_string(),
420+
location: Some(lsp_location),
421+
..Default::default()
422+
}]),
423+
position: last_paren_lsp_pos,
424+
text_edits: None,
425+
tooltip: None,
426+
padding_left: Some(true),
427+
padding_right: None,
428+
data: None,
429+
};
430+
result.push(hint);
431+
break;
432+
}
433+
}
434+
}
435+
}
436+
437+
Some(())
438+
}
439+
440+
fn get_super_member_id(
441+
semantic_model: &mut SemanticModel,
442+
super_type: LuaType,
443+
member_key: &LuaMemberKey,
444+
infer_guard: &mut InferGuard,
445+
) -> Option<LuaMemberId> {
446+
if let LuaType::Ref(super_type_id) = &super_type {
447+
infer_guard.check(super_type_id)?;
448+
let member_owner = LuaMemberOwner::Type(super_type_id.clone());
449+
let member_map = semantic_model
450+
.get_db()
451+
.get_member_index()
452+
.get_member_map(member_owner)?;
453+
454+
if let Some(member_id) = member_map.get(&member_key) {
455+
return Some(member_id.clone());
456+
}
457+
458+
let super_types = semantic_model
459+
.get_db()
460+
.get_type_index()
461+
.get_super_types(super_type_id)?;
462+
for super_type in super_types {
463+
if let Some(member_id) =
464+
get_super_member_id(semantic_model, super_type, member_key, infer_guard)
465+
{
466+
return Some(member_id);
467+
}
468+
}
469+
}
470+
471+
None
472+
}
473+
474+
fn get_override_lsp_location(
475+
semantic_model: &mut SemanticModel,
476+
file_id: FileId,
477+
syntax_id: LuaSyntaxId,
478+
) -> Option<lsp_types::Location> {
479+
let document = semantic_model.get_document_by_file_id(file_id)?;
480+
let root = semantic_model.get_root_by_file_id(file_id)?;
481+
let node = syntax_id.to_node_from_root(root.syntax())?;
482+
let range = if let Some(index_exor) = LuaIndexExpr::cast(node.clone()) {
483+
index_exor.get_index_name_token()?.text_range()
484+
} else {
485+
node.text_range()
486+
};
487+
488+
let lsp_range = document.to_lsp_location(range)?;
489+
Some(lsp_range)
490+
}

0 commit comments

Comments
 (0)