11use std:: collections:: HashMap ;
2+ use std:: sync:: Arc ;
23
34use emmylua_code_analysis:: {
4- FileId , InferGuard , LuaFunctionType , LuaMemberId , LuaMemberKey , LuaSemanticDeclId , LuaType ,
5- SemanticModel ,
5+ FileId , InferGuard , LuaFunctionType , LuaMemberId , LuaMemberKey , LuaOperatorId ,
6+ LuaOperatorMetaMethod , LuaSemanticDeclId , LuaType , SemanticModel ,
67} ;
78use emmylua_parser:: {
89 LuaAst , LuaAstNode , LuaCallExpr , LuaExpr , LuaFuncStat , LuaIndexExpr , LuaLocalFuncStat ,
@@ -14,6 +15,7 @@ use rowan::NodeOrToken;
1415
1516use rowan:: TokenAtOffset ;
1617
18+ use crate :: handlers:: definition:: compare_function_types;
1719use crate :: handlers:: inlay_hint:: build_function_hint:: { build_closure_hint, build_label_parts} ;
1820
1921pub fn build_inlay_hints ( semantic_model : & SemanticModel ) -> Option < Vec < InlayHint > > {
@@ -26,7 +28,8 @@ pub fn build_inlay_hints(semantic_model: &SemanticModel) -> Option<Vec<InlayHint
2628 }
2729 LuaAst :: LuaCallExpr ( call_expr) => {
2830 build_call_expr_param_hint ( semantic_model, & mut result, call_expr. clone ( ) ) ;
29- build_call_expr_await_hint ( semantic_model, & mut result, call_expr) ;
31+ build_call_expr_await_hint ( semantic_model, & mut result, call_expr. clone ( ) ) ;
32+ build_call_expr_meta_call_hint ( semantic_model, & mut result, call_expr) ;
3033 }
3134 LuaAst :: LuaLocalName ( local_name) => {
3235 build_local_name_hint ( semantic_model, & mut result, local_name) ;
@@ -458,3 +461,154 @@ fn get_override_lsp_location(
458461 let lsp_range = document. to_lsp_location ( range) ?;
459462 Some ( lsp_range)
460463}
464+
465+ fn build_call_expr_meta_call_hint (
466+ semantic_model : & SemanticModel ,
467+ result : & mut Vec < InlayHint > ,
468+ call_expr : LuaCallExpr ,
469+ ) -> Option < ( ) > {
470+ if !semantic_model. get_emmyrc ( ) . hint . meta_call_hint {
471+ return Some ( ( ) ) ;
472+ }
473+
474+ let prefix_expr = call_expr. get_prefix_expr ( ) ?;
475+ let semantic_info =
476+ semantic_model. get_semantic_info ( NodeOrToken :: Node ( prefix_expr. syntax ( ) . clone ( ) ) ) ?;
477+
478+ match & semantic_info. typ {
479+ LuaType :: Ref ( id) | LuaType :: Def ( id) => {
480+ let decl = semantic_model. get_db ( ) . get_type_index ( ) . get_type_decl ( id) ?;
481+ if !decl. is_class ( ) {
482+ return Some ( ( ) ) ;
483+ }
484+
485+ let call_operator_ids = semantic_model
486+ . get_db ( )
487+ . get_operator_index ( )
488+ . get_operators ( & id. clone ( ) . into ( ) , LuaOperatorMetaMethod :: Call ) ?;
489+
490+ set_meta_call_part (
491+ semantic_model,
492+ result,
493+ call_operator_ids,
494+ call_expr,
495+ semantic_info. typ ,
496+ ) ?;
497+ }
498+ _ => { }
499+ }
500+ Some ( ( ) )
501+ }
502+
503+ fn set_meta_call_part (
504+ semantic_model : & SemanticModel ,
505+ result : & mut Vec < InlayHint > ,
506+ operator_ids : & Vec < LuaOperatorId > ,
507+ call_expr : LuaCallExpr ,
508+ target_type : LuaType ,
509+ ) -> Option < ( ) > {
510+ let ( operator_id, call_func) =
511+ find_match_meta_call_operator_id ( semantic_model, operator_ids, call_expr. clone ( ) ) ?;
512+
513+ let operator = semantic_model
514+ . get_db ( )
515+ . get_operator_index ( )
516+ . get_operator ( & operator_id) ?;
517+
518+ let location = {
519+ let range = operator. get_range ( ) ;
520+ let document = semantic_model. get_document_by_file_id ( operator. get_file_id ( ) ) ?;
521+ let lsp_range = document. to_lsp_range ( range) ?;
522+ Location :: new ( document. get_uri ( ) , lsp_range)
523+ } ;
524+
525+ let document = semantic_model. get_document ( ) ;
526+ let parent = call_expr. syntax ( ) . parent ( ) ?;
527+
528+ // 如果是 `Class(...)` 且调用返回值是 Class 类型, 则显示 `new` 提示
529+ let hint_new = {
530+ LuaStat :: can_cast ( parent. kind ( ) . into ( ) )
531+ && !matches ! ( call_expr. get_prefix_expr( ) ?, LuaExpr :: CallExpr ( _) )
532+ && semantic_model
533+ . type_check ( call_func. get_ret ( ) , & target_type)
534+ . is_ok ( )
535+ } ;
536+
537+ let ( value, hint_range, padding_right) = if hint_new {
538+ ( "new" . to_string ( ) , call_expr. get_range ( ) , Some ( true ) )
539+ } else {
540+ (
541+ "⚡" . to_string ( ) ,
542+ call_expr. get_prefix_expr ( ) ?. get_range ( ) ,
543+ None ,
544+ )
545+ } ;
546+
547+ let hint_position = {
548+ let lsp_range = document. to_lsp_range ( hint_range) ?;
549+ if hint_new {
550+ lsp_range. start
551+ } else {
552+ lsp_range. end
553+ }
554+ } ;
555+
556+ let part = InlayHintLabelPart {
557+ value,
558+ location : Some ( location) ,
559+ ..Default :: default ( )
560+ } ;
561+
562+ let hint = InlayHint {
563+ kind : Some ( InlayHintKind :: TYPE ) ,
564+ label : InlayHintLabel :: LabelParts ( vec ! [ part] ) ,
565+ position : hint_position,
566+ text_edits : None ,
567+ tooltip : None ,
568+ padding_left : None ,
569+ padding_right,
570+ data : None ,
571+ } ;
572+
573+ result. push ( hint) ;
574+ Some ( ( ) )
575+ }
576+
577+ fn find_match_meta_call_operator_id (
578+ semantic_model : & SemanticModel ,
579+ operator_ids : & Vec < LuaOperatorId > ,
580+ call_expr : LuaCallExpr ,
581+ ) -> Option < ( LuaOperatorId , Arc < LuaFunctionType > ) > {
582+ let call_func = semantic_model. infer_call_expr_func ( call_expr. clone ( ) , None ) ?;
583+ if operator_ids. len ( ) == 1 {
584+ return Some ( ( operator_ids. first ( ) . cloned ( ) ?, call_func) ) ;
585+ }
586+ for operator_id in operator_ids {
587+ let operator = semantic_model
588+ . get_db ( )
589+ . get_operator_index ( )
590+ . get_operator ( operator_id) ?;
591+ let operator_func = {
592+ let operator_type = operator. get_operator_func ( semantic_model. get_db ( ) ) ;
593+ match operator_type {
594+ LuaType :: DocFunction ( func) => func,
595+ LuaType :: Signature ( signature_id) => {
596+ let signature = semantic_model
597+ . get_db ( )
598+ . get_signature_index ( )
599+ . get ( & signature_id) ?;
600+ signature. to_doc_func_type ( )
601+ }
602+ _ => return None ,
603+ }
604+ } ;
605+ let is_match =
606+ compare_function_types ( semantic_model, & call_func, & operator_func, & call_expr)
607+ . unwrap_or ( false ) ;
608+
609+ if is_match {
610+ return Some ( ( operator_id. clone ( ) , operator_func) ) ;
611+ }
612+ }
613+ operator_ids. first ( ) . cloned ( ) . map ( |id| ( id, call_func) )
614+ }
0 commit comments