11use std:: collections:: HashMap ;
22
33use emmylua_code_analysis:: {
4- FileId , InferGuard , LuaFunctionType , LuaMemberId , LuaMemberKey , LuaSemanticDeclId , LuaType ,
5- SemanticModel ,
4+ FileId , InferGuard , LuaFunctionType , LuaMemberId , LuaMemberKey , LuaOperatorId ,
5+ LuaOperatorMetaMethod , LuaSemanticDeclId , LuaType , SemanticModel ,
66} ;
77use emmylua_parser:: {
88 LuaAst , LuaAstNode , LuaCallExpr , LuaExpr , LuaFuncStat , LuaIndexExpr , LuaLocalFuncStat ,
@@ -14,6 +14,7 @@ use rowan::NodeOrToken;
1414
1515use rowan:: TokenAtOffset ;
1616
17+ use crate :: handlers:: definition:: compare_function_types;
1718use crate :: handlers:: inlay_hint:: build_function_hint:: { build_closure_hint, build_label_parts} ;
1819
1920pub fn build_inlay_hints ( semantic_model : & SemanticModel ) -> Option < Vec < InlayHint > > {
@@ -26,7 +27,8 @@ pub fn build_inlay_hints(semantic_model: &SemanticModel) -> Option<Vec<InlayHint
2627 }
2728 LuaAst :: LuaCallExpr ( call_expr) => {
2829 build_call_expr_param_hint ( semantic_model, & mut result, call_expr. clone ( ) ) ;
29- build_call_expr_await_hint ( semantic_model, & mut result, call_expr) ;
30+ build_call_expr_await_hint ( semantic_model, & mut result, call_expr. clone ( ) ) ;
31+ build_call_expr_meta_call_hint ( semantic_model, & mut result, call_expr) ;
3032 }
3133 LuaAst :: LuaLocalName ( local_name) => {
3234 build_local_name_hint ( semantic_model, & mut result, local_name) ;
@@ -458,3 +460,115 @@ fn get_override_lsp_location(
458460 let lsp_range = document. to_lsp_location ( range) ?;
459461 Some ( lsp_range)
460462}
463+
464+ fn build_call_expr_meta_call_hint (
465+ semantic_model : & SemanticModel ,
466+ result : & mut Vec < InlayHint > ,
467+ call_expr : LuaCallExpr ,
468+ ) -> Option < ( ) > {
469+ if !semantic_model. get_emmyrc ( ) . hint . meta_call_hint {
470+ return Some ( ( ) ) ;
471+ }
472+
473+ let prefix_expr = call_expr. get_prefix_expr ( ) ?;
474+ let semantic_info =
475+ semantic_model. get_semantic_info ( NodeOrToken :: Node ( prefix_expr. syntax ( ) . clone ( ) ) ) ?;
476+
477+ match & semantic_info. typ {
478+ LuaType :: Ref ( id) | LuaType :: Def ( id) => {
479+ let decl = semantic_model. get_db ( ) . get_type_index ( ) . get_type_decl ( id) ?;
480+ if !decl. is_class ( ) {
481+ return Some ( ( ) ) ;
482+ }
483+
484+ let call_operator_ids = semantic_model
485+ . get_db ( )
486+ . get_operator_index ( )
487+ . get_operators ( & id. clone ( ) . into ( ) , LuaOperatorMetaMethod :: Call ) ?;
488+ let call_operator_parts =
489+ get_meta_call_part ( semantic_model, call_operator_ids, call_expr) ?;
490+ if call_operator_parts. is_empty ( ) {
491+ return Some ( ( ) ) ;
492+ }
493+
494+ let hint_position = {
495+ let range = prefix_expr. get_range ( ) ;
496+ let document = semantic_model. get_document ( ) ;
497+ let lsp_range = document. to_lsp_range ( range) ?;
498+ lsp_range. end
499+ } ;
500+
501+ let hint = InlayHint {
502+ kind : Some ( InlayHintKind :: TYPE ) ,
503+ label : InlayHintLabel :: LabelParts ( call_operator_parts) ,
504+ position : hint_position,
505+ text_edits : None ,
506+ tooltip : None ,
507+ padding_left : None ,
508+ padding_right : Some ( true ) ,
509+ data : None ,
510+ } ;
511+ result. push ( hint) ;
512+ }
513+ _ => { }
514+ }
515+ Some ( ( ) )
516+ }
517+
518+ fn get_meta_call_part (
519+ semantic_model : & SemanticModel ,
520+ operator_ids : & Vec < LuaOperatorId > ,
521+ call_expr : LuaCallExpr ,
522+ ) -> Option < Vec < InlayHintLabelPart > > {
523+ let call_func = semantic_model. infer_call_expr_func ( call_expr. clone ( ) , None ) ?;
524+
525+ let mut parts = Vec :: new ( ) ;
526+ for ( idx, operator_id) in operator_ids. iter ( ) . enumerate ( ) {
527+ let operator = semantic_model
528+ . get_db ( )
529+ . get_operator_index ( )
530+ . get_operator ( operator_id) ?;
531+ let operator_func = {
532+ let operator_type = operator. get_operator_func ( semantic_model. get_db ( ) ) ;
533+ match operator_type {
534+ LuaType :: DocFunction ( func) => func,
535+ LuaType :: Signature ( signature_id) => {
536+ let signature = semantic_model
537+ . get_db ( )
538+ . get_signature_index ( )
539+ . get ( & signature_id) ?;
540+ signature. to_doc_func_type ( )
541+ }
542+ _ => return None ,
543+ }
544+ } ;
545+ let is_match =
546+ compare_function_types ( semantic_model, & call_func, & operator_func, & call_expr)
547+ . unwrap_or ( false ) ;
548+
549+ // 不匹配且不是第一个, 跳过
550+ if !is_match && idx != 0 {
551+ continue ;
552+ }
553+ // 清空
554+ parts. clear ( ) ;
555+
556+ let location = {
557+ let range = operator. get_range ( ) ;
558+ let document = semantic_model. get_document_by_file_id ( operator. get_file_id ( ) ) ?;
559+ let lsp_range = document. to_lsp_range ( range) ?;
560+ Location :: new ( document. get_uri ( ) , lsp_range)
561+ } ;
562+
563+ parts. push ( InlayHintLabelPart {
564+ value : ": call" . to_string ( ) ,
565+ location : Some ( location) ,
566+ ..Default :: default ( )
567+ } ) ;
568+
569+ if is_match {
570+ return Some ( parts) ;
571+ }
572+ }
573+ Some ( parts)
574+ }
0 commit comments