diff --git a/src/analyzer/expr/assignment/array_assignment_analyzer.rs b/src/analyzer/expr/assignment/array_assignment_analyzer.rs index c95bca0e..9e89c534 100644 --- a/src/analyzer/expr/assignment/array_assignment_analyzer.rs +++ b/src/analyzer/expr/assignment/array_assignment_analyzer.rs @@ -19,7 +19,6 @@ use oxidized::{ aast::{self, Expr}, ast_defs::Pos, }; -use rustc_hash::FxHashSet; use crate::{ expr::{expression_identifier, fetch::array_fetch_analyzer}, @@ -422,7 +421,7 @@ fn add_array_assignment_dataflow( let old_parent_nodes = parent_expr_type.parent_nodes.clone(); - parent_expr_type.parent_nodes = FxHashSet::from_iter([parent_node.clone()]); + parent_expr_type.parent_nodes = vec![parent_node.clone()]; for old_parent_node in old_parent_nodes { analysis_data.data_flow_graph.add_path( diff --git a/src/analyzer/expr/assignment/instance_property_assignment_analyzer.rs b/src/analyzer/expr/assignment/instance_property_assignment_analyzer.rs index 09ece863..88fd3656 100644 --- a/src/analyzer/expr/assignment/instance_property_assignment_analyzer.rs +++ b/src/analyzer/expr/assignment/instance_property_assignment_analyzer.rs @@ -682,7 +682,13 @@ fn add_instance_property_assignment_dataflow( if let Some(stmt_var_type) = stmt_var_type { let mut stmt_type_inner = (**stmt_var_type).clone(); - stmt_type_inner.parent_nodes.insert(var_node.clone()); + if !stmt_type_inner + .parent_nodes + .iter() + .any(|n| &n.id == &var_node.id) + { + stmt_type_inner.parent_nodes.push(var_node.clone()); + } *stmt_var_type = Rc::new(stmt_type_inner); } diff --git a/src/analyzer/expr/binop/arithmetic_analyzer.rs b/src/analyzer/expr/binop/arithmetic_analyzer.rs index 8b10bac7..30ad7c82 100644 --- a/src/analyzer/expr/binop/arithmetic_analyzer.rs +++ b/src/analyzer/expr/binop/arithmetic_analyzer.rs @@ -246,7 +246,7 @@ pub(crate) fn assign_arithmetic_type( lhs_expr.1.start_offset() as u32, lhs_expr.1.end_offset() as u32, )) { - cond_type.parent_nodes.insert(decision_node.clone()); + cond_type.parent_nodes.push(decision_node.clone()); for old_parent_node in &lhs_type.parent_nodes { analysis_data.data_flow_graph.add_path( @@ -263,7 +263,7 @@ pub(crate) fn assign_arithmetic_type( rhs_expr.1.start_offset() as u32, rhs_expr.1.end_offset() as u32, )) { - cond_type.parent_nodes.insert(decision_node.clone()); + cond_type.parent_nodes.push(decision_node.clone()); for old_parent_node in &rhs_type.parent_nodes { analysis_data.data_flow_graph.add_path( diff --git a/src/analyzer/expr/binop/assignment_analyzer.rs b/src/analyzer/expr/binop/assignment_analyzer.rs index a4b619ec..1a350f2b 100644 --- a/src/analyzer/expr/binop/assignment_analyzer.rs +++ b/src/analyzer/expr/binop/assignment_analyzer.rs @@ -195,7 +195,7 @@ pub(crate) fn analyze( .data_flow_graph .add_node(assignment_node.clone()); - assign_value_type.parent_nodes.insert(assignment_node); + assign_value_type.parent_nodes.push(assignment_node); if !context.inside_assignment_op && !var_id.starts_with("$_") { if let Some((start_offset, end_offset)) = context.for_loop_init_bounds { @@ -210,7 +210,7 @@ pub(crate) fn analyze( analysis_data.data_flow_graph.add_node(for_node.clone()); - assign_value_type.parent_nodes.insert(for_node); + assign_value_type.parent_nodes.push(for_node); } } }; @@ -551,12 +551,11 @@ pub(crate) fn add_dataflow_to_assignment( } let parent_nodes = &assignment_type.parent_nodes; - let mut new_parent_nodes = FxHashSet::default(); let new_parent_node = DataFlowNode::get_for_assignment(var_id.to_string(), statements_analyzer.get_hpos(var_pos)); data_flow_graph.add_node(new_parent_node.clone()); - new_parent_nodes.insert(new_parent_node.clone()); + let new_parent_nodes = vec![new_parent_node.clone()]; for parent_node in parent_nodes { data_flow_graph.add_path( diff --git a/src/analyzer/expr/binop/concat_analyzer.rs b/src/analyzer/expr/binop/concat_analyzer.rs index 3c0cd1d5..519123a6 100644 --- a/src/analyzer/expr/binop/concat_analyzer.rs +++ b/src/analyzer/expr/binop/concat_analyzer.rs @@ -139,7 +139,7 @@ pub(crate) fn analyze_concat_nodes( get_string() }; - result_type.parent_nodes.insert(decision_node.clone()); + result_type.parent_nodes.push(decision_node.clone()); analysis_data.data_flow_graph.add_node(decision_node); diff --git a/src/analyzer/expr/call/arguments_analyzer.rs b/src/analyzer/expr/call/arguments_analyzer.rs index c4cd2926..4a0abef4 100644 --- a/src/analyzer/expr/call/arguments_analyzer.rs +++ b/src/analyzer/expr/call/arguments_analyzer.rs @@ -7,7 +7,7 @@ use hakana_reflection_info::EFFECT_WRITE_LOCAL; use hakana_reflection_info::data_flow::node::DataFlowNode; use hakana_reflection_info::taint::SinkType; use hakana_str::{Interner, StrId}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; use crate::expr::binop::assignment_analyzer; use crate::expr::call_analyzer::get_generic_param_for_offset; @@ -33,7 +33,8 @@ use hakana_type::template::{ }; use hakana_type::type_expander::{self, StaticClassType, TypeExpansionOptions}; use hakana_type::{ - add_optional_union_type, combine_optional_union_types, get_arraykey, get_mixed_any, wrap_atomic, + add_optional_union_type, combine_optional_union_types, extend_dataflow_uniquely, get_arraykey, + get_mixed_any, wrap_atomic, }; use indexmap::IndexMap; use oxidized::ast_defs::ParamKind; @@ -1055,13 +1056,11 @@ fn handle_possibly_matching_inout_param( Some(statements_analyzer.get_hpos(function_call_pos)), ); - inout_type.parent_nodes = FxHashSet::from_iter([out_node.clone()]); + inout_type.parent_nodes = vec![out_node.clone()]; analysis_data.data_flow_graph.add_node(out_node); } else { - inout_type - .parent_nodes - .extend(arg_type.parent_nodes.clone()); + extend_dataflow_uniquely(&mut inout_type.parent_nodes, arg_type.parent_nodes.clone()); } assignment_analyzer::analyze_inout_param( diff --git a/src/analyzer/expr/call/existing_atomic_method_call_analyzer.rs b/src/analyzer/expr/call/existing_atomic_method_call_analyzer.rs index 1b93cb0f..e80fa1d4 100644 --- a/src/analyzer/expr/call/existing_atomic_method_call_analyzer.rs +++ b/src/analyzer/expr/call/existing_atomic_method_call_analyzer.rs @@ -21,7 +21,7 @@ use oxidized::{ aast, ast_defs::{self, Pos}, }; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; use crate::expr::fetch::array_fetch_analyzer::add_array_fetch_dataflow; use crate::stmt_analyzer::AnalysisError; @@ -350,7 +350,7 @@ fn handle_shapes_static_method( ); } - new_type.parent_nodes = FxHashSet::from_iter([assignment_node.clone()]); + new_type.parent_nodes = vec![assignment_node.clone()]; analysis_data.data_flow_graph.add_node(assignment_node); 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 25f1231c..d0a693ca 100644 --- a/src/analyzer/expr/call/function_call_return_type_fetcher.rs +++ b/src/analyzer/expr/call/function_call_return_type_fetcher.rs @@ -851,7 +851,7 @@ fn add_dataflow( } } - stmt_type.parent_nodes.insert(function_call_node); + stmt_type.parent_nodes.push(function_call_node); stmt_type } 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 07901786..6bf224a7 100644 --- a/src/analyzer/expr/call/method_call_return_type_fetcher.rs +++ b/src/analyzer/expr/call/method_call_return_type_fetcher.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use hakana_reflection_info::functionlike_identifier::FunctionLikeIdentifier; use hakana_str::{Interner, StrId}; use oxidized::{aast, ast_defs}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; use hakana_reflection_info::classlike_info::ClassLikeInfo; use hakana_reflection_info::data_flow::graph::GraphKind; @@ -343,7 +343,7 @@ fn add_dataflow( let mut var_type_inner = (**var_type).clone(); - var_type_inner.parent_nodes = FxHashSet::from_iter([after_construct_node.clone()]); + var_type_inner.parent_nodes = vec![after_construct_node.clone()]; data_flow_graph.add_node(after_construct_node); @@ -401,7 +401,7 @@ fn add_dataflow( let mut context_type_inner = (**context_type).clone(); - context_type_inner.parent_nodes = FxHashSet::from_iter([var_node.clone()]); + context_type_inner.parent_nodes = vec![var_node.clone()]; *context_type = Rc::new(context_type_inner); @@ -452,7 +452,7 @@ fn add_dataflow( data_flow_graph.add_node(method_call_node.clone()); - return_type_candidate.parent_nodes = FxHashSet::from_iter([method_call_node.clone()]); + return_type_candidate.parent_nodes = vec![method_call_node.clone()]; return_type_candidate } diff --git a/src/analyzer/expr/call/new_analyzer.rs b/src/analyzer/expr/call/new_analyzer.rs index f3d7d0b7..d12189fd 100644 --- a/src/analyzer/expr/call/new_analyzer.rs +++ b/src/analyzer/expr/call/new_analyzer.rs @@ -7,7 +7,7 @@ use hakana_reflection_info::data_flow::node::DataFlowNode; use hakana_reflection_info::functionlike_info::FunctionLikeInfo; use hakana_str::StrId; use hakana_type::template::standin_type_replacer::get_most_specific_type_from_bounds; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; use crate::expr::call_analyzer::{check_method_args, get_generic_param_for_offset}; use crate::expression_analyzer; @@ -660,7 +660,7 @@ fn add_dataflow<'a>( data_flow_graph.add_node(new_call_node.clone()); - return_type_candidate.parent_nodes = FxHashSet::from_iter([new_call_node.clone()]); + return_type_candidate.parent_nodes = vec![new_call_node.clone()]; if from_classname { let descendants = codebase.get_all_descendants(&method_id.0); @@ -683,7 +683,7 @@ fn add_dataflow<'a>( data_flow_graph.add_node(new_call_node.clone()); - return_type_candidate.parent_nodes.insert(new_call_node); + return_type_candidate.parent_nodes.push(new_call_node); } } } else { @@ -695,7 +695,7 @@ fn add_dataflow<'a>( data_flow_graph.add_node(new_call_node.clone()); - return_type_candidate.parent_nodes = FxHashSet::from_iter([new_call_node.clone()]); + return_type_candidate.parent_nodes = vec![new_call_node.clone()]; } return_type_candidate diff --git a/src/analyzer/expr/closure_analyzer.rs b/src/analyzer/expr/closure_analyzer.rs index 6a0a8d20..050009f7 100644 --- a/src/analyzer/expr/closure_analyzer.rs +++ b/src/analyzer/expr/closure_analyzer.rs @@ -16,7 +16,6 @@ use hakana_type::type_expander; use hakana_type::type_expander::TypeExpansionOptions; use hakana_type::wrap_atomic; use oxidized::aast; -use rustc_hash::FxHashSet; pub(crate) fn analyze( statements_analyzer: &StatementsAnalyzer, @@ -123,7 +122,7 @@ pub(crate) fn analyze( .data_flow_graph .add_node(application_node.clone()); - closure_type.parent_nodes = FxHashSet::from_iter([application_node]); + closure_type.parent_nodes = vec![application_node]; } analysis_data.expr_types.insert( diff --git a/src/analyzer/expr/collection_analyzer.rs b/src/analyzer/expr/collection_analyzer.rs index 58e806e0..73ee9208 100644 --- a/src/analyzer/expr/collection_analyzer.rs +++ b/src/analyzer/expr/collection_analyzer.rs @@ -18,7 +18,6 @@ use oxidized::{ ast_defs::Pos, tast::{KvcKind, VcKind}, }; -use rustc_hash::FxHashSet; use crate::{expression_analyzer, scope_analyzer::ScopeAnalyzer}; use crate::{function_analysis_data::FunctionAnalysisData, stmt_analyzer::AnalysisError}; @@ -29,7 +28,7 @@ pub(crate) struct ArrayCreationInfo { item_key_atomic_types: Vec, item_value_atomic_types: Vec, known_items: Vec<(TAtomic, TUnion)>, - parent_nodes: FxHashSet, + parent_nodes: Vec, effects: u8, } @@ -38,7 +37,7 @@ impl ArrayCreationInfo { Self { item_key_atomic_types: Vec::new(), item_value_atomic_types: Vec::new(), - parent_nodes: FxHashSet::default(), + parent_nodes: Vec::new(), known_items: Vec::new(), effects: 0, } @@ -529,7 +528,7 @@ fn add_array_value_dataflow( ); } - array_creation_info.parent_nodes.insert(new_parent_node); + array_creation_info.parent_nodes.push(new_parent_node); } fn add_array_key_dataflow( @@ -590,5 +589,5 @@ fn add_array_key_dataflow( ); } - array_creation_info.parent_nodes.insert(new_parent_node); + array_creation_info.parent_nodes.push(new_parent_node); } diff --git a/src/analyzer/expr/fetch/array_fetch_analyzer.rs b/src/analyzer/expr/fetch/array_fetch_analyzer.rs index 88fac95c..9869563a 100644 --- a/src/analyzer/expr/fetch/array_fetch_analyzer.rs +++ b/src/analyzer/expr/fetch/array_fetch_analyzer.rs @@ -17,7 +17,6 @@ use hakana_type::{ type_comparator::{type_comparison_result::TypeComparisonResult, union_type_comparator}, }; use oxidized::{aast, ast_defs::Pos}; -use rustc_hash::FxHashSet; use crate::{ expr::expression_identifier, function_analysis_data::FunctionAnalysisData, @@ -258,10 +257,10 @@ pub(crate) fn add_array_fetch_dataflow( } } - value_type.parent_nodes.insert(new_parent_node.clone()); + value_type.parent_nodes.push(new_parent_node.clone()); if let Some(array_key_node) = &array_key_node { - key_type.parent_nodes.insert(array_key_node.clone()); + key_type.parent_nodes.push(array_key_node.clone()); } } } @@ -999,7 +998,7 @@ pub(crate) fn handle_array_access_on_mixed( } if let Some(stmt_type) = stmt_type { let mut stmt_type_new = stmt_type.clone(); - stmt_type_new.parent_nodes = FxHashSet::from_iter([new_parent_node.clone()]); + stmt_type_new.parent_nodes = vec![new_parent_node.clone()]; } } } diff --git a/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs b/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs index c82354ec..8b56eb31 100644 --- a/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs +++ b/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs @@ -23,7 +23,7 @@ use hakana_type::{ }; use indexmap::IndexMap; use oxidized::{aast::Expr, ast_defs::Pos}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; pub(crate) fn analyze( statements_analyzer: &StatementsAnalyzer, @@ -437,7 +437,7 @@ fn add_property_dataflow( ); } - stmt_type.parent_nodes.insert(property_node.clone()); + stmt_type.parent_nodes.push(property_node.clone()); } } } else { @@ -467,9 +467,7 @@ fn add_property_dataflow( .data_flow_graph .add_node(localized_property_node.clone()); - stmt_type - .parent_nodes - .insert(localized_property_node.clone()); + stmt_type.parent_nodes.push(localized_property_node.clone()); stmt_type } @@ -528,7 +526,7 @@ pub(crate) fn add_unspecialized_property_fetch_dataflow( let mut stmt_type = stmt_type.clone(); - stmt_type.parent_nodes = FxHashSet::from_iter([localized_property_node.clone()]); + stmt_type.parent_nodes = vec![localized_property_node.clone()]; stmt_type } diff --git a/src/analyzer/expr/pipe_analyzer.rs b/src/analyzer/expr/pipe_analyzer.rs index 548a9aea..1cd8906f 100644 --- a/src/analyzer/expr/pipe_analyzer.rs +++ b/src/analyzer/expr/pipe_analyzer.rs @@ -39,7 +39,7 @@ pub(crate) fn analyze( false, ); - pipe_expr_type.parent_nodes.insert(parent_node.clone()); + pipe_expr_type.parent_nodes.push(parent_node.clone()); analysis_data.data_flow_graph.add_node(parent_node); } diff --git a/src/analyzer/expr/shape_analyzer.rs b/src/analyzer/expr/shape_analyzer.rs index 13f5074c..d4cb7b88 100644 --- a/src/analyzer/expr/shape_analyzer.rs +++ b/src/analyzer/expr/shape_analyzer.rs @@ -30,7 +30,7 @@ pub(crate) fn analyze( ) -> Result<(), AnalysisError> { let codebase = statements_analyzer.get_codebase(); - let mut parent_nodes = FxHashSet::default(); + let mut parent_nodes = vec![]; let mut effects = 0; @@ -151,7 +151,7 @@ pub(crate) fn analyze( }, value_expr, ) { - parent_nodes.insert(new_parent_node); + parent_nodes.push(new_parent_node); } known_items.insert(name, (false, Arc::new(value_item_type))); diff --git a/src/analyzer/expr/tuple_analyzer.rs b/src/analyzer/expr/tuple_analyzer.rs index 2153d95d..d2c8499a 100644 --- a/src/analyzer/expr/tuple_analyzer.rs +++ b/src/analyzer/expr/tuple_analyzer.rs @@ -14,7 +14,6 @@ use hakana_reflection_info::{ }; use hakana_type::{get_mixed_any, get_nothing, wrap_atomic}; use oxidized::{aast, ast_defs::Pos}; -use rustc_hash::FxHashSet; use std::collections::BTreeMap; @@ -25,7 +24,7 @@ pub(crate) fn analyze( analysis_data: &mut FunctionAnalysisData, context: &mut ScopeContext, ) -> Result<(), AnalysisError> { - let mut parent_nodes = FxHashSet::default(); + let mut parent_nodes = vec![]; let mut known_items = BTreeMap::new(); for (i, value_expr) in tuple_fields.iter().enumerate() { @@ -50,7 +49,7 @@ pub(crate) fn analyze( i, value_expr, ) { - parent_nodes.insert(new_parent_node); + parent_nodes.push(new_parent_node); } known_items.insert(i, (false, value_item_type)); diff --git a/src/analyzer/expr/variable_fetch_analyzer.rs b/src/analyzer/expr/variable_fetch_analyzer.rs index 8ed23a1d..05b75ca8 100644 --- a/src/analyzer/expr/variable_fetch_analyzer.rs +++ b/src/analyzer/expr/variable_fetch_analyzer.rs @@ -119,7 +119,7 @@ pub(crate) fn get_type_for_superglobal( analysis_data.data_flow_graph.add_node(taint_source.clone()); - var_type.parent_nodes.insert(taint_source); + var_type.parent_nodes.push(taint_source); var_type } @@ -160,7 +160,7 @@ fn add_dataflow_to_variable( let mut parent_nodes = stmt_type.parent_nodes.clone(); if parent_nodes.is_empty() { - parent_nodes.insert(assignment_node); + parent_nodes.push(assignment_node); } else { for parent_node in &parent_nodes { data_flow_graph.add_path( diff --git a/src/analyzer/expression_analyzer.rs b/src/analyzer/expression_analyzer.rs index 20d3ff23..be8bd0ca 100644 --- a/src/analyzer/expression_analyzer.rs +++ b/src/analyzer/expression_analyzer.rs @@ -37,8 +37,8 @@ use hakana_reflector::simple_type_inferer::int_from_string; use hakana_str::StrId; use hakana_type::type_expander::get_closure_from_id; use hakana_type::{ - get_bool, get_false, get_float, get_int, get_literal_int, get_literal_string, get_mixed_any, - get_null, get_true, wrap_atomic, + extend_dataflow_uniquely, get_bool, get_false, get_float, get_int, get_literal_int, + get_literal_string, get_mixed_any, get_null, get_true, wrap_atomic, }; use oxidized::pos::Pos; use oxidized::{aast, ast_defs}; @@ -426,9 +426,10 @@ pub(crate) fn analyze( { if type_params.len() == 1 { let inside_type = type_params.first().unwrap().clone(); - awaited_stmt_type - .parent_nodes - .extend(inside_type.parent_nodes); + extend_dataflow_uniquely( + &mut awaited_stmt_type.parent_nodes, + inside_type.parent_nodes, + ); new_types.extend(inside_type.types); } else { new_types.push(atomic_type); @@ -889,7 +890,7 @@ pub(crate) fn add_decision_dataflow( lhs_expr.1.start_offset() as u32, lhs_expr.1.end_offset() as u32, )) { - cond_type.parent_nodes.insert(decision_node.clone()); + cond_type.parent_nodes.push(decision_node.clone()); for old_parent_node in &lhs_type.parent_nodes { analysis_data.data_flow_graph.add_path( @@ -907,7 +908,7 @@ pub(crate) fn add_decision_dataflow( rhs_expr.1.start_offset() as u32, rhs_expr.1.end_offset() as u32, )) { - cond_type.parent_nodes.insert(decision_node.clone()); + cond_type.parent_nodes.push(decision_node.clone()); for old_parent_node in &rhs_type.parent_nodes { analysis_data.data_flow_graph.add_path( diff --git a/src/analyzer/functionlike_analyzer.rs b/src/analyzer/functionlike_analyzer.rs index 548721d6..4a23ca0d 100644 --- a/src/analyzer/functionlike_analyzer.rs +++ b/src/analyzer/functionlike_analyzer.rs @@ -36,7 +36,6 @@ use hakana_type::{ use itertools::Itertools; use oxidized::aast; use oxidized::ast_defs::Pos; -use rustc_hash::FxHashSet; use std::rc::Rc; @@ -316,7 +315,7 @@ impl<'a> FunctionLikeAnalyzer<'a> { statements_analyzer.get_interner(), ); - this_type.parent_nodes = FxHashSet::from_iter([new_call_node]); + this_type.parent_nodes = vec![new_call_node]; } } @@ -1143,7 +1142,7 @@ impl<'a> FunctionLikeAnalyzer<'a> { analysis_data.data_flow_graph.add_node(argument_node); } - param_type.parent_nodes.insert(new_parent_node); + param_type.parent_nodes.push(new_parent_node); let config = statements_analyzer.get_config(); diff --git a/src/analyzer/reconciler/mod.rs b/src/analyzer/reconciler/mod.rs index 43d56605..2d09f52d 100644 --- a/src/analyzer/reconciler/mod.rs +++ b/src/analyzer/reconciler/mod.rs @@ -103,7 +103,7 @@ pub(crate) fn reconcile_keyed_types( let mut existing_var_type_inner = (**existing_var_type).clone(); existing_var_type_inner.parent_nodes = - FxHashSet::from_iter([new_parent_node.clone()]); + vec![new_parent_node.clone()]; *existing_var_type = Rc::new(existing_var_type_inner); @@ -258,7 +258,7 @@ pub(crate) fn reconcile_keyed_types( ); } - result_type.parent_nodes = FxHashSet::from_iter([scalar_check_node.clone()]); + result_type.parent_nodes = vec![scalar_check_node.clone()]; analysis_data.data_flow_graph.add_node(scalar_check_node); } else { @@ -293,7 +293,7 @@ pub(crate) fn reconcile_keyed_types( ); } - result_type.parent_nodes = FxHashSet::from_iter([narrowing_node.clone()]); + result_type.parent_nodes = vec![narrowing_node.clone()]; analysis_data.data_flow_graph.add_node(narrowing_node); } else { diff --git a/src/analyzer/stmt/ifelse_analyzer.rs b/src/analyzer/stmt/ifelse_analyzer.rs index ce41b30a..55b133c9 100644 --- a/src/analyzer/stmt/ifelse_analyzer.rs +++ b/src/analyzer/stmt/ifelse_analyzer.rs @@ -10,7 +10,7 @@ use hakana_reflection_info::{ analysis_result::Replacement, issue::IssueKind, EFFECT_PURE, EFFECT_READ_GLOBALS, EFFECT_READ_PROPS, }; -use hakana_type::combine_union_types; +use hakana_type::{combine_union_types, extend_dataflow_uniquely}; use oxidized::{aast, ast::Uop, ast_defs::Pos}; use rustc_hash::{FxHashMap, FxHashSet}; use std::{collections::BTreeMap, rc::Rc}; @@ -362,7 +362,10 @@ pub(crate) fn analyze( context.vars_in_scope.insert(var_id, Rc::new(combined_type)); } else { let mut existing_var_type = (**existing_var_type).clone(); - existing_var_type.parent_nodes.extend(var_type.parent_nodes); + extend_dataflow_uniquely( + &mut existing_var_type.parent_nodes, + var_type.parent_nodes, + ); context .vars_in_scope .insert(var_id, Rc::new(existing_var_type)); diff --git a/src/analyzer/stmt/loop_analyzer.rs b/src/analyzer/stmt/loop_analyzer.rs index d7b4c16f..bc0eaa36 100644 --- a/src/analyzer/stmt/loop_analyzer.rs +++ b/src/analyzer/stmt/loop_analyzer.rs @@ -3,7 +3,7 @@ use std::{collections::BTreeMap, rc::Rc}; use hakana_algebra::Clause; use hakana_reflection_info::t_union::TUnion; -use hakana_type::combine_union_types; +use hakana_type::{combine_union_types, extend_dataflow_uniquely}; use oxidized::aast; use rustc_hash::{FxHashMap, FxHashSet}; @@ -503,10 +503,14 @@ pub(crate) fn analyze<'a>( loop_parent_context.vars_in_scope.get_mut(var_id) { if loop_parent_context_type != loop_context_type { - *loop_parent_context_type = Rc::new(combine_parent_nodes( - loop_context_type, - loop_parent_context_type, - )); + *loop_parent_context_type = Rc::new({ + let mut first = (**loop_context_type).clone(); + extend_dataflow_uniquely( + &mut first.parent_nodes, + loop_parent_context_type.parent_nodes.clone(), + ); + first + }); } } } @@ -516,8 +520,15 @@ pub(crate) fn analyze<'a>( for (var_id, var_type) in loop_parent_context.vars_in_scope.clone() { if let Some(continue_context_type) = continue_context.vars_in_scope.get_mut(&var_id) { if continue_context_type.is_mixed() { - *continue_context_type = - Rc::new(combine_parent_nodes(continue_context_type, &var_type)); + *continue_context_type = Rc::new({ + let second: &TUnion = &var_type; + let mut first = (**continue_context_type).clone(); + extend_dataflow_uniquely( + &mut first.parent_nodes, + second.parent_nodes.clone(), + ); + first + }); loop_parent_context .vars_in_scope @@ -547,10 +558,14 @@ pub(crate) fn analyze<'a>( } else if let Some(loop_parent_context_type) = loop_parent_context.vars_in_scope.get_mut(&var_id) { - *loop_parent_context_type = Rc::new(combine_parent_nodes( - continue_context_type, - loop_parent_context_type, - )); + *loop_parent_context_type = Rc::new({ + let mut first = (**continue_context_type).clone(); + extend_dataflow_uniquely( + &mut first.parent_nodes, + loop_parent_context_type.parent_nodes.clone(), + ); + first + }); } } else { loop_parent_context.vars_in_scope.remove(&var_id); @@ -675,12 +690,6 @@ fn get_assignment_map_depth( max_depth } -fn combine_parent_nodes(first: &TUnion, second: &TUnion) -> TUnion { - let mut first = first.clone(); - first.parent_nodes.extend(second.parent_nodes.clone()); - first -} - fn apply_pre_condition_to_loop_context( statements_analyzer: &StatementsAnalyzer, pre_condition: &aast::Expr<(), ()>, diff --git a/src/analyzer/stmt/return_analyzer.rs b/src/analyzer/stmt/return_analyzer.rs index 15126e02..15403330 100644 --- a/src/analyzer/stmt/return_analyzer.rs +++ b/src/analyzer/stmt/return_analyzer.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use crate::scope_context::ScopeContext; use crate::stmt_analyzer::AnalysisError; use hakana_reflection_info::function_context::FunctionLikeIdentifier; -use hakana_str::StrId; use hakana_reflection_info::{ data_flow::{ graph::{DataFlowGraph, GraphKind}, @@ -15,7 +14,8 @@ use hakana_reflection_info::{ t_atomic::TAtomic, t_union::TUnion, }; -use hakana_type::combine_union_types; +use hakana_str::StrId; +use hakana_type::{combine_union_types, extend_dataflow_uniquely}; use hakana_type::{ get_mixed_any, get_null, get_void, type_comparator::type_comparison_result::TypeComparisonResult, @@ -146,7 +146,7 @@ pub(crate) fn analyze( extra_types: None, remapped_params: false, }); - inferred_return_type.parent_nodes.extend(parent_nodes); + extend_dataflow_uniquely(&mut inferred_return_type.parent_nodes, parent_nodes); } if return_expr.is_some() { diff --git a/src/analyzer/stmt/try_analyzer.rs b/src/analyzer/stmt/try_analyzer.rs index f257073d..157301fa 100644 --- a/src/analyzer/stmt/try_analyzer.rs +++ b/src/analyzer/stmt/try_analyzer.rs @@ -182,7 +182,7 @@ pub(crate) fn analyze( statements_analyzer.get_hpos(&catch.1 .0), ); - catch_type.parent_nodes.insert(new_parent_node); + catch_type.parent_nodes.push(new_parent_node); catch_context .vars_in_scope diff --git a/src/code_info/t_union.rs b/src/code_info/t_union.rs index 66523c85..c346c7ee 100644 --- a/src/code_info/t_union.rs +++ b/src/code_info/t_union.rs @@ -9,13 +9,12 @@ use hakana_str::{Interner, StrId}; use itertools::Itertools; use std::hash::{Hash, Hasher}; -use rustc_hash::FxHashSet; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, Derivative)] pub struct TUnion { pub types: Vec, - pub parent_nodes: FxHashSet, + pub parent_nodes: Vec, pub had_template: bool, // Whether or not the data in this type could have references to it. @@ -66,7 +65,7 @@ impl TUnion { pub fn new(types: Vec) -> TUnion { TUnion { types, - parent_nodes: FxHashSet::default(), + parent_nodes: vec![], had_template: false, reference_free: false, possibly_undefined_from_try: false, diff --git a/src/ttype/lib.rs b/src/ttype/lib.rs index ac6f3da7..07330ec1 100644 --- a/src/ttype/lib.rs +++ b/src/ttype/lib.rs @@ -3,6 +3,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use hakana_reflection_info::{ codebase_info::CodebaseInfo, + data_flow::node::DataFlowNode, t_atomic::{DictKey, TAtomic}, t_union::TUnion, }; @@ -190,6 +191,15 @@ pub fn combine_optional_union_types( } } +pub fn extend_dataflow_uniquely( + type_1_nodes: &mut Vec, + type_2_nodes: Vec, +) { + type_1_nodes.extend(type_2_nodes); + type_1_nodes.sort_by(|a, b| a.id.cmp(&b.id)); + type_1_nodes.dedup_by(|a, b| a.id.eq(&b.id)); +} + pub fn combine_union_types( type_1: &TUnion, type_2: &TUnion, @@ -241,9 +251,7 @@ pub fn combine_union_types( combined_type.parent_nodes.clone_from(&type_1.parent_nodes); } else { combined_type.parent_nodes.clone_from(&type_1.parent_nodes); - combined_type - .parent_nodes - .extend(type_2.parent_nodes.clone()); + extend_dataflow_uniquely(&mut combined_type.parent_nodes, type_2.parent_nodes.clone()); } } @@ -286,9 +294,7 @@ pub fn add_union_type( } if !other_type.parent_nodes.is_empty() { - base_type - .parent_nodes - .extend(other_type.parent_nodes.clone()); + extend_dataflow_uniquely(&mut base_type.parent_nodes, other_type.parent_nodes.clone()); } base_type diff --git a/src/ttype/type_expander.rs b/src/ttype/type_expander.rs index 43923990..e4ee3314 100644 --- a/src/ttype/type_expander.rs +++ b/src/ttype/type_expander.rs @@ -22,7 +22,7 @@ use indexmap::IndexMap; use itertools::Itertools; use rustc_hash::FxHashMap; -use crate::{get_nothing, template, type_combiner, wrap_atomic}; +use crate::{extend_dataflow_uniquely, get_nothing, template, type_combiner, wrap_atomic}; #[derive(Debug)] pub enum StaticClassType<'a, 'b> { @@ -113,7 +113,7 @@ pub fn expand_union( } } - return_type.parent_nodes.extend(extra_data_flow_nodes); + extend_dataflow_uniquely(&mut return_type.parent_nodes, extra_data_flow_nodes); } fn expand_atomic(