Skip to content

Commit 95dfeb4

Browse files
robertoaloimeta-codesync[bot]
authored andcommitted
Include some of the 'erlang' functions when searching for dynamic calls
Summary: Extend detection for dynamic calls to the most common ones from the `erlang` module. Given that some of these calls refer to functions by arity, extend the original mechanism to support both variants. Later in the stack we will use a more performant data structure and a macro to reduce verbosity. Reviewed By: jcpetruzza Differential Revision: D83840802 fbshipit-source-id: 1fc91f1b368cda4fb3b12ee5fb934871ee672cad
1 parent 3177337 commit 95dfeb4

File tree

2 files changed

+799
-3
lines changed

2 files changed

+799
-3
lines changed

crates/hir/src/sema/to_def.rs

Lines changed: 271 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,10 @@ struct DynamicCallPattern {
794794
module_arg_index: Option<usize>,
795795
/// Index of the target function argument
796796
function_arg_index: usize,
797-
/// Index of the arguments list
797+
/// Index of the arguments list or arity argument
798798
args_list_index: usize,
799+
/// Whether to extract arity directly from an integer argument (true) or from list length (false)
800+
direct_arity: bool,
799801
}
800802

801803
static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
@@ -807,6 +809,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
807809
module_arg_index: None,
808810
function_arg_index: 0,
809811
args_list_index: 1,
812+
direct_arity: false,
810813
},
811814
// apply/3 (implicit erlang:apply/3) - apply(Module, Function, Args)
812815
DynamicCallPattern {
@@ -816,6 +819,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
816819
module_arg_index: Some(0),
817820
function_arg_index: 1,
818821
args_list_index: 2,
822+
direct_arity: false,
819823
},
820824
// erlang:apply/2 (explicit) - erlang:apply(Fun, Args)
821825
DynamicCallPattern {
@@ -825,6 +829,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
825829
module_arg_index: None,
826830
function_arg_index: 0,
827831
args_list_index: 1,
832+
direct_arity: false,
828833
},
829834
// erlang:apply/3 (explicit) - erlang:apply(Module, Function, Args)
830835
DynamicCallPattern {
@@ -834,6 +839,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
834839
module_arg_index: Some(0),
835840
function_arg_index: 1,
836841
args_list_index: 2,
842+
direct_arity: false,
837843
},
838844
// rpc:call/4 - rpc:call(Node, Module, Function, Args)
839845
DynamicCallPattern {
@@ -843,6 +849,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
843849
module_arg_index: Some(1),
844850
function_arg_index: 2,
845851
args_list_index: 3,
852+
direct_arity: false,
846853
},
847854
// rpc:call/5 - rpc:call(Node, Module, Function, Args, Timeout)
848855
DynamicCallPattern {
@@ -852,6 +859,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
852859
module_arg_index: Some(1),
853860
function_arg_index: 2,
854861
args_list_index: 3,
862+
direct_arity: false,
855863
},
856864
// rpc:async_call/4 - rpc:async_call(Node, Module, Function, Args)
857865
DynamicCallPattern {
@@ -861,6 +869,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
861869
module_arg_index: Some(1),
862870
function_arg_index: 2,
863871
args_list_index: 3,
872+
direct_arity: false,
864873
},
865874
// rpc:cast/4 - rpc:cast(Node, Module, Function, Args)
866875
DynamicCallPattern {
@@ -870,6 +879,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
870879
module_arg_index: Some(1),
871880
function_arg_index: 2,
872881
args_list_index: 3,
882+
direct_arity: false,
873883
},
874884
// rpc:multicall/3 - rpc:multicall(Module, Function, Args)
875885
DynamicCallPattern {
@@ -879,6 +889,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
879889
module_arg_index: Some(0),
880890
function_arg_index: 1,
881891
args_list_index: 2,
892+
direct_arity: false,
882893
},
883894
// rpc:multicall/4 - rpc:multicall(Module, Function, Args, Timeout)
884895
DynamicCallPattern {
@@ -888,6 +899,7 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
888899
module_arg_index: Some(0),
889900
function_arg_index: 1,
890901
args_list_index: 2,
902+
direct_arity: false,
891903
},
892904
// rpc:multicall/5 - rpc:multicall(Nodes, Module, Function, Args, Timeout)
893905
DynamicCallPattern {
@@ -897,6 +909,247 @@ static DYNAMIC_CALL_PATTERNS: &[DynamicCallPattern] = &[
897909
module_arg_index: Some(1),
898910
function_arg_index: 2,
899911
args_list_index: 3,
912+
direct_arity: false,
913+
},
914+
// function_exported/3 (implicit erlang:function_exported/3) - function_exported(Module, Function, Arity)
915+
DynamicCallPattern {
916+
module: None,
917+
function: "function_exported",
918+
arity: 3,
919+
module_arg_index: Some(0),
920+
function_arg_index: 1,
921+
args_list_index: 2,
922+
direct_arity: true,
923+
},
924+
// erlang:function_exported/3 (explicit) - erlang:function_exported(Module, Function, Arity)
925+
DynamicCallPattern {
926+
module: Some("erlang"),
927+
function: "function_exported",
928+
arity: 3,
929+
module_arg_index: Some(0),
930+
function_arg_index: 1,
931+
args_list_index: 2,
932+
direct_arity: true,
933+
},
934+
// is_builtin/3 (implicit erlang:is_builtin/3) - is_builtin(Module, Function, Arity)
935+
DynamicCallPattern {
936+
module: None,
937+
function: "is_builtin",
938+
arity: 3,
939+
module_arg_index: Some(0),
940+
function_arg_index: 1,
941+
args_list_index: 2,
942+
direct_arity: true,
943+
},
944+
// erlang:is_builtin/3 (explicit) - erlang:is_builtin(Module, Function, Arity)
945+
DynamicCallPattern {
946+
module: Some("erlang"),
947+
function: "is_builtin",
948+
arity: 3,
949+
module_arg_index: Some(0),
950+
function_arg_index: 1,
951+
args_list_index: 2,
952+
direct_arity: true,
953+
},
954+
// hibernate/3 (implicit erlang:hibernate/3) - hibernate(Module, Function, Args)
955+
DynamicCallPattern {
956+
module: None,
957+
function: "hibernate",
958+
arity: 3,
959+
module_arg_index: Some(0),
960+
function_arg_index: 1,
961+
args_list_index: 2,
962+
direct_arity: false,
963+
},
964+
// erlang:hibernate/3 (explicit) - erlang:hibernate(Module, Function, Args)
965+
DynamicCallPattern {
966+
module: Some("erlang"),
967+
function: "hibernate",
968+
arity: 3,
969+
module_arg_index: Some(0),
970+
function_arg_index: 1,
971+
args_list_index: 2,
972+
direct_arity: false,
973+
},
974+
// spawn/3 (implicit erlang:spawn/3) - spawn(Module, Function, Args)
975+
DynamicCallPattern {
976+
module: None,
977+
function: "spawn",
978+
arity: 3,
979+
module_arg_index: Some(0),
980+
function_arg_index: 1,
981+
args_list_index: 2,
982+
direct_arity: false,
983+
},
984+
// erlang:spawn/3 (explicit) - erlang:spawn(Module, Function, Args)
985+
DynamicCallPattern {
986+
module: Some("erlang"),
987+
function: "spawn",
988+
arity: 3,
989+
module_arg_index: Some(0),
990+
function_arg_index: 1,
991+
args_list_index: 2,
992+
direct_arity: false,
993+
},
994+
// spawn/4 (implicit erlang:spawn/4) - spawn(Node, Module, Function, Args)
995+
DynamicCallPattern {
996+
module: None,
997+
function: "spawn",
998+
arity: 4,
999+
module_arg_index: Some(1),
1000+
function_arg_index: 2,
1001+
args_list_index: 3,
1002+
direct_arity: false,
1003+
},
1004+
// erlang:spawn/4 (explicit) - erlang:spawn(Node, Module, Function, Args)
1005+
DynamicCallPattern {
1006+
module: Some("erlang"),
1007+
function: "spawn",
1008+
arity: 4,
1009+
module_arg_index: Some(1),
1010+
function_arg_index: 2,
1011+
args_list_index: 3,
1012+
direct_arity: false,
1013+
},
1014+
// spawn_link/3 (implicit erlang:spawn_link/3) - spawn_link(Module, Function, Args)
1015+
DynamicCallPattern {
1016+
module: None,
1017+
function: "spawn_link",
1018+
arity: 3,
1019+
module_arg_index: Some(0),
1020+
function_arg_index: 1,
1021+
args_list_index: 2,
1022+
direct_arity: false,
1023+
},
1024+
// erlang:spawn_link/3 (explicit) - erlang:spawn_link(Module, Function, Args)
1025+
DynamicCallPattern {
1026+
module: Some("erlang"),
1027+
function: "spawn_link",
1028+
arity: 3,
1029+
module_arg_index: Some(0),
1030+
function_arg_index: 1,
1031+
args_list_index: 2,
1032+
direct_arity: false,
1033+
},
1034+
// spawn_link/4 (implicit erlang:spawn_link/4) - spawn_link(Node, Module, Function, Args)
1035+
DynamicCallPattern {
1036+
module: None,
1037+
function: "spawn_link",
1038+
arity: 4,
1039+
module_arg_index: Some(1),
1040+
function_arg_index: 2,
1041+
args_list_index: 3,
1042+
direct_arity: false,
1043+
},
1044+
// erlang:spawn_link/4 (explicit) - erlang:spawn_link(Node, Module, Function, Args)
1045+
DynamicCallPattern {
1046+
module: Some("erlang"),
1047+
function: "spawn_link",
1048+
arity: 4,
1049+
module_arg_index: Some(1),
1050+
function_arg_index: 2,
1051+
args_list_index: 3,
1052+
direct_arity: false,
1053+
},
1054+
// spawn_monitor/3 (implicit erlang:spawn_monitor/3) - spawn_monitor(Module, Function, Args)
1055+
DynamicCallPattern {
1056+
module: None,
1057+
function: "spawn_monitor",
1058+
arity: 3,
1059+
module_arg_index: Some(0),
1060+
function_arg_index: 1,
1061+
args_list_index: 2,
1062+
direct_arity: false,
1063+
},
1064+
// erlang:spawn_monitor/3 (explicit) - erlang:spawn_monitor(Module, Function, Args)
1065+
DynamicCallPattern {
1066+
module: Some("erlang"),
1067+
function: "spawn_monitor",
1068+
arity: 3,
1069+
module_arg_index: Some(0),
1070+
function_arg_index: 1,
1071+
args_list_index: 2,
1072+
direct_arity: false,
1073+
},
1074+
// spawn_monitor/4 (implicit erlang:spawn_monitor/4) - spawn_monitor(Node, Module, Function, Args)
1075+
DynamicCallPattern {
1076+
module: None,
1077+
function: "spawn_monitor",
1078+
arity: 4,
1079+
module_arg_index: Some(1),
1080+
function_arg_index: 2,
1081+
args_list_index: 3,
1082+
direct_arity: false,
1083+
},
1084+
// erlang:spawn_monitor/4 (explicit) - erlang:spawn_monitor(Node, Module, Function, Args)
1085+
DynamicCallPattern {
1086+
module: Some("erlang"),
1087+
function: "spawn_monitor",
1088+
arity: 4,
1089+
module_arg_index: Some(1),
1090+
function_arg_index: 2,
1091+
args_list_index: 3,
1092+
direct_arity: false,
1093+
},
1094+
// spawn_opt/4 (implicit erlang:spawn_opt/4) - spawn_opt(Module, Function, Args, Options)
1095+
DynamicCallPattern {
1096+
module: None,
1097+
function: "spawn_opt",
1098+
arity: 4,
1099+
module_arg_index: Some(0),
1100+
function_arg_index: 1,
1101+
args_list_index: 2,
1102+
direct_arity: false,
1103+
},
1104+
// erlang:spawn_opt/4 (explicit) - erlang:spawn_opt(Module, Function, Args, Options)
1105+
DynamicCallPattern {
1106+
module: Some("erlang"),
1107+
function: "spawn_opt",
1108+
arity: 4,
1109+
module_arg_index: Some(0),
1110+
function_arg_index: 1,
1111+
args_list_index: 2,
1112+
direct_arity: false,
1113+
},
1114+
// spawn_opt/5 (implicit erlang:spawn_opt/5) - spawn_opt(Node, Module, Function, Args, Options)
1115+
DynamicCallPattern {
1116+
module: None,
1117+
function: "spawn_opt",
1118+
arity: 5,
1119+
module_arg_index: Some(1),
1120+
function_arg_index: 2,
1121+
args_list_index: 3,
1122+
direct_arity: false,
1123+
},
1124+
// erlang:spawn_opt/5 (explicit) - erlang:spawn_opt(Node, Module, Function, Args, Options)
1125+
DynamicCallPattern {
1126+
module: Some("erlang"),
1127+
function: "spawn_opt",
1128+
arity: 5,
1129+
module_arg_index: Some(1),
1130+
function_arg_index: 2,
1131+
args_list_index: 3,
1132+
direct_arity: false,
1133+
},
1134+
// spawn_request/5 (implicit erlang:spawn_request/5) - spawn_request(Node, Module, Function, Args, Options)
1135+
DynamicCallPattern {
1136+
module: None,
1137+
function: "spawn_request",
1138+
arity: 5,
1139+
module_arg_index: Some(1),
1140+
function_arg_index: 2,
1141+
args_list_index: 3,
1142+
direct_arity: false,
1143+
},
1144+
// erlang:spawn_request/5 (explicit) - erlang:spawn_request(Node, Module, Function, Args, Options)
1145+
DynamicCallPattern {
1146+
module: Some("erlang"),
1147+
function: "spawn_request",
1148+
arity: 5,
1149+
module_arg_index: Some(1),
1150+
function_arg_index: 2,
1151+
args_list_index: 3,
1152+
direct_arity: false,
9001153
},
9011154
];
9021155

@@ -958,8 +1211,14 @@ fn resolve_dynamic_call(
9581211
args: &[ExprId],
9591212
body: &Body,
9601213
) -> Option<CallDef> {
961-
// Extract arity from the arguments list
962-
let arity = arity_from_apply_args(args[pattern.args_list_index], body)?;
1214+
// Extract arity based on pattern type
1215+
let arity = if pattern.direct_arity {
1216+
// Extract arity directly from an integer argument
1217+
arity_from_integer_arg(args[pattern.args_list_index], body)?
1218+
} else {
1219+
// Extract arity from list length
1220+
arity_from_apply_args(args[pattern.args_list_index], body)?
1221+
};
9631222

9641223
// Build the call target
9651224
let call_target = if let Some(module_idx) = pattern.module_arg_index {
@@ -986,3 +1245,12 @@ fn arity_from_apply_args(args: ExprId, body: &Body) -> Option<u32> {
9861245
// Deal with a simple list only.
9871246
body[args].list_length().map(|l| l as u32)
9881247
}
1248+
1249+
/// Extract arity directly from an integer argument.
1250+
/// Given the `ExprId` of an integer parameter, return its value as arity.
1251+
fn arity_from_integer_arg(arity_arg: ExprId, body: &Body) -> Option<u32> {
1252+
match &body[arity_arg] {
1253+
Expr::Literal(Literal::Integer(int)) => int.value.try_into().ok(),
1254+
_ => None,
1255+
}
1256+
}

0 commit comments

Comments
 (0)