mir_analyzer/call/
static_call.rs1use std::sync::Arc;
2
3use php_ast::ast::{ExprKind, StaticDynMethodCallExpr, StaticMethodCallExpr};
4use php_ast::Span;
5
6use mir_issues::{IssueKind, Severity};
7use mir_types::Union;
8
9use crate::context::Context;
10use crate::expr::ExpressionAnalyzer;
11use crate::symbol::SymbolKind;
12
13use super::args::{check_args, spread_element_type, substitute_static_in_return, CheckArgsParams};
14use super::CallAnalyzer;
15
16impl CallAnalyzer {
17 pub fn analyze_static_method_call<'a, 'arena, 'src>(
18 ea: &mut ExpressionAnalyzer<'a>,
19 call: &StaticMethodCallExpr<'arena, 'src>,
20 ctx: &mut Context,
21 span: Span,
22 ) -> Union {
23 let method_name = match &call.method.kind {
24 ExprKind::Identifier(name) => name.as_str(),
25 _ => return Union::mixed(),
26 };
27
28 let fqcn = match &call.class.kind {
29 ExprKind::Identifier(name) => ea.codebase.resolve_class_name(&ea.file, name.as_ref()),
30 _ => return Union::mixed(),
31 };
32
33 let fqcn = resolve_static_class(&fqcn, ctx);
34
35 let arg_types: Vec<Union> = call
36 .args
37 .iter()
38 .map(|arg| {
39 let ty = ea.analyze(&arg.value, ctx);
40 if arg.unpack {
41 spread_element_type(&ty)
42 } else {
43 ty
44 }
45 })
46 .collect();
47 let arg_spans: Vec<Span> = call.args.iter().map(|a| a.span).collect();
48
49 if let Some(method) = ea.codebase.get_method(&fqcn, method_name) {
50 let method_span = call.method.span;
51 ea.codebase.mark_method_referenced_at(
52 &fqcn,
53 method_name,
54 ea.file.clone(),
55 method_span.start,
56 method_span.end,
57 );
58 if let Some(msg) = method.deprecated.clone() {
59 ea.emit(
60 IssueKind::DeprecatedMethodCall {
61 class: fqcn.clone(),
62 method: method_name.to_string(),
63 message: Some(msg).filter(|m| !m.is_empty()),
64 },
65 Severity::Info,
66 span,
67 );
68 }
69 let arg_names: Vec<Option<String>> = call
70 .args
71 .iter()
72 .map(|a| a.name.as_ref().map(|n| n.to_string_repr().into_owned()))
73 .collect();
74 check_args(
75 ea,
76 CheckArgsParams {
77 fn_name: method_name,
78 params: &method.params,
79 arg_types: &arg_types,
80 arg_spans: &arg_spans,
81 arg_names: &arg_names,
82 call_span: span,
83 has_spread: call.args.iter().any(|a| a.unpack),
84 },
85 );
86 let ret_raw = method
87 .effective_return_type()
88 .cloned()
89 .unwrap_or_else(Union::mixed);
90 let fqcn_arc: Arc<str> = Arc::from(fqcn.as_str());
91 let ret = substitute_static_in_return(ret_raw, &fqcn_arc);
92 ea.record_symbol(
93 method_span,
94 SymbolKind::StaticCall {
95 class: fqcn_arc,
96 method: Arc::from(method_name),
97 },
98 ret.clone(),
99 );
100 ret
101 } else if ea.codebase.type_exists(&fqcn) && !ea.codebase.has_unknown_ancestor(&fqcn) {
102 let is_interface = ea.codebase.interfaces.contains_key(fqcn.as_str());
103 let is_abstract = ea.codebase.is_abstract_class(&fqcn);
104 if is_interface || is_abstract || ea.codebase.get_method(&fqcn, "__call").is_some() {
105 Union::mixed()
106 } else {
107 ea.emit(
108 IssueKind::UndefinedMethod {
109 class: fqcn,
110 method: method_name.to_string(),
111 },
112 Severity::Error,
113 span,
114 );
115 Union::mixed()
116 }
117 } else if !ea.codebase.type_exists(&fqcn)
118 && !matches!(fqcn.as_str(), "self" | "static" | "parent")
119 {
120 ea.emit(
121 IssueKind::UndefinedClass { name: fqcn },
122 Severity::Error,
123 call.class.span,
124 );
125 Union::mixed()
126 } else {
127 Union::mixed()
128 }
129 }
130
131 pub fn analyze_static_dyn_method_call<'a, 'arena, 'src>(
132 ea: &mut ExpressionAnalyzer<'a>,
133 call: &StaticDynMethodCallExpr<'arena, 'src>,
134 ctx: &mut Context,
135 ) -> Union {
136 for arg in call.args.iter() {
137 ea.analyze(&arg.value, ctx);
138 }
139 Union::mixed()
140 }
141}
142
143fn resolve_static_class(name: &str, ctx: &Context) -> String {
144 match name.to_lowercase().as_str() {
145 "self" => ctx.self_fqcn.as_deref().unwrap_or("self").to_string(),
146 "parent" => ctx.parent_fqcn.as_deref().unwrap_or("parent").to_string(),
147 "static" => ctx
148 .static_fqcn
149 .as_deref()
150 .unwrap_or(ctx.self_fqcn.as_deref().unwrap_or("static"))
151 .to_string(),
152 _ => name.to_string(),
153 }
154}