From bab06d876bf49587f04347966a88d9ead5a0feac Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Wed, 7 Aug 2024 14:13:44 -0400 Subject: [PATCH] Make MessageFormatter::formatMessage pure passthrough --- .../call/function_call_return_type_fetcher.rs | 11 +---- .../call/method_call_return_type_fetcher.rs | 47 ++++++++++++++++++- src/analyzer/expr/expression_identifier.rs | 23 +++++---- src/code_info_builder/functionlike_scanner.rs | 4 ++ src/str/build.rs | 2 + 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/analyzer/expr/call/function_call_return_type_fetcher.rs b/src/analyzer/expr/call/function_call_return_type_fetcher.rs index 6dad41a4..9931c6a3 100644 --- a/src/analyzer/expr/call/function_call_return_type_fetcher.rs +++ b/src/analyzer/expr/call/function_call_return_type_fetcher.rs @@ -29,8 +29,8 @@ use crate::expr::binop::concat_analyzer::{analyze_concat_nodes, get_concat_nodes use crate::expr::fetch::array_fetch_analyzer::handle_array_access_on_dict; use crate::expr::variable_fetch_analyzer; use crate::function_analysis_data::FunctionAnalysisData; -use crate::scope_analyzer::ScopeAnalyzer; use crate::scope::BlockContext; +use crate::scope_analyzer::ScopeAnalyzer; use crate::statements_analyzer::StatementsAnalyzer; use hakana_type::template::{TemplateBound, TemplateResult}; @@ -832,12 +832,7 @@ fn add_dataflow( let (param_offsets, variadic_path) = if !functionlike_storage.user_defined && (!expr.2.is_empty() || expr.3.is_some()) { - get_special_argument_nodes( - functionlike_id, - expr, - functionlike_storage, - statements_analyzer.get_interner(), - ) + get_special_argument_nodes(functionlike_id, expr) } else { (vec![], None) }; @@ -977,8 +972,6 @@ fn get_special_argument_nodes( &Vec<(ast_defs::ParamKind, aast::Expr<(), ()>)>, &Option>, ), - _functionlike_info: &FunctionLikeInfo, - _interner: &Interner, ) -> (Vec<(usize, PathKind)>, Option) { match functionlike_id { FunctionLikeIdentifier::Function(function_name) => match *function_name { diff --git a/src/analyzer/expr/call/method_call_return_type_fetcher.rs b/src/analyzer/expr/call/method_call_return_type_fetcher.rs index 3089d06d..47511a52 100644 --- a/src/analyzer/expr/call/method_call_return_type_fetcher.rs +++ b/src/analyzer/expr/call/method_call_return_type_fetcher.rs @@ -22,8 +22,8 @@ use oxidized::ast_defs::Pos; use crate::expr::expression_identifier::get_expr_id; use crate::function_analysis_data::FunctionAnalysisData; -use crate::scope_analyzer::ScopeAnalyzer; use crate::scope::BlockContext; +use crate::scope_analyzer::ScopeAnalyzer; use crate::statements_analyzer::StatementsAnalyzer; use hakana_reflection_info::functionlike_info::FunctionLikeInfo; use hakana_type::template::{TemplateBound, TemplateResult}; @@ -208,6 +208,14 @@ fn get_special_method_return(method_id: &MethodIdentifier, interner: &Interner) } _ => {} }, + StrId::MESSAGE_FORMATTER => match method_id.1 { + StrId::FORMAT_MESSAGE => { + let mut u = TUnion::new(vec![TAtomic::TString, TAtomic::TFalse]); + u.ignore_falsable_issues = true; + return Some(u); + } + _ => {} + }, _ => {} } @@ -460,6 +468,43 @@ fn add_dataflow( &method_call_node, PathKind::Aggregate, ); + } else if method_id.0 == StrId::MESSAGE_FORMATTER && method_id.1 == StrId::FORMAT_MESSAGE { + add_special_param_dataflow( + statements_analyzer, + &FunctionLikeIdentifier::Method(method_id.0, method_id.1), + true, + 0, + statements_analyzer.get_hpos(call_expr.1[0].1.pos()), + call_pos, + &FxHashMap::default(), + data_flow_graph, + &method_call_node, + PathKind::Aggregate, + ); + add_special_param_dataflow( + statements_analyzer, + &FunctionLikeIdentifier::Method(method_id.0, method_id.1), + true, + 1, + statements_analyzer.get_hpos(call_expr.1[1].1.pos()), + call_pos, + &FxHashMap::default(), + data_flow_graph, + &method_call_node, + PathKind::Default, + ); + add_special_param_dataflow( + statements_analyzer, + &FunctionLikeIdentifier::Method(method_id.0, method_id.1), + true, + 2, + statements_analyzer.get_hpos(call_expr.1[2].1.pos()), + call_pos, + &FxHashMap::default(), + data_flow_graph, + &method_call_node, + PathKind::UnknownArrayFetch(hakana_reflection_info::data_flow::path::ArrayDataKind::ArrayValue), + ); } data_flow_graph.add_node(method_call_node.clone()); diff --git a/src/analyzer/expr/expression_identifier.rs b/src/analyzer/expr/expression_identifier.rs index ccd7ff05..176a15e1 100644 --- a/src/analyzer/expr/expression_identifier.rs +++ b/src/analyzer/expr/expression_identifier.rs @@ -195,22 +195,21 @@ pub fn get_static_functionlike_id_from_call( aast::Expr_::ClassConst(boxed) => { let (class_id, rhs_expr) = (&boxed.0, &boxed.1); - match &class_id.2 { - aast::ClassId_::CIexpr(lhs_expr) => { - if let aast::Expr_::Id(id) = &lhs_expr.2 { - if let (Some(class_name), Some(method_name)) = ( - resolved_names.get(&(id.0.start_offset() as u32)), - interner.get(&rhs_expr.1), - ) { - Some(FunctionLikeIdentifier::Method(*class_name, method_name)) - } else { - None - } + if let aast::ClassId_::CIexpr(lhs_expr) = &class_id.2 { + if let aast::Expr_::Id(id) = &lhs_expr.2 { + if let (Some(class_name), Some(method_name)) = ( + resolved_names.get(&(id.0.start_offset() as u32)), + interner.get(&rhs_expr.1), + ) { + Some(FunctionLikeIdentifier::Method(*class_name, method_name)) } else { None } + } else { + None } - _ => None, + } else { + None } } _ => None, diff --git a/src/code_info_builder/functionlike_scanner.rs b/src/code_info_builder/functionlike_scanner.rs index ed606b95..ee1c1fbe 100644 --- a/src/code_info_builder/functionlike_scanner.rs +++ b/src/code_info_builder/functionlike_scanner.rs @@ -87,6 +87,10 @@ pub(crate) fn scan_method( functionlike_info.has_throw = true; } + if classlike_name == StrId::MESSAGE_FORMATTER && method_name == StrId::FORMAT_MESSAGE { + functionlike_info.effects = FnEffect::Pure; + } + let mut method_info = MethodInfo::new(); method_info.is_static = m.static_; diff --git a/src/str/build.rs b/src/str/build.rs index 6bf6b196..afb1cb57 100644 --- a/src/str/build.rs +++ b/src/str/build.rs @@ -253,6 +253,7 @@ fn main() -> Result<()> { "Hakana\\SecurityAnalysis\\SpecializeCall", "Hakana\\SpecialTypes\\LiteralString", "Hakana\\TestOnly", + "MessageFormatter", "NumberFormatter", "ReflectionClass", "ReflectionFunction", @@ -329,6 +330,7 @@ fn main() -> Result<()> { "floatval", "floor", "fmod", + "formatMessage", "fromItems", "function_exists", "get_class",