diff --git a/src/analyzer/expr/call/arguments_analyzer.rs b/src/analyzer/expr/call/arguments_analyzer.rs index e72c8c6a..cffae284 100644 --- a/src/analyzer/expr/call/arguments_analyzer.rs +++ b/src/analyzer/expr/call/arguments_analyzer.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::sync::Arc; use hakana_reflection_info::assertion::Assertion; -use hakana_reflection_info::EFFECT_WRITE_LOCAL; +use hakana_reflection_info::{GenericParent, EFFECT_WRITE_LOCAL}; use hakana_reflection_info::data_flow::node::DataFlowNode; use hakana_reflection_info::taint::SinkType; @@ -520,7 +520,7 @@ pub(crate) fn check_arguments_match( } fn adjust_param_type( - class_generic_params: &IndexMap)>>, + class_generic_params: &IndexMap)>>, param_type: &mut TUnion, codebase: &CodebaseInfo, mut arg_value_type: TUnion, @@ -833,7 +833,7 @@ fn handle_closure_arg( } fn map_class_generic_params( - class_generic_params: &IndexMap)>>, + class_generic_params: &IndexMap)>>, param_type: &mut TUnion, codebase: &CodebaseInfo, interner: &Interner, @@ -1083,7 +1083,7 @@ fn refine_template_result_for_functionlike( classlike_storage: Option<&ClassLikeInfo>, calling_classlike_storage: Option<&ClassLikeInfo>, functionlike_storage: &FunctionLikeInfo, - class_template_params: &IndexMap)>>, + class_template_params: &IndexMap)>>, ) { let template_types = get_template_types_for_call( codebase, @@ -1117,10 +1117,10 @@ pub(crate) fn get_template_types_for_call( declaring_classlike_storage: Option<&ClassLikeInfo>, appearing_class_name: Option<&StrId>, calling_classlike_storage: Option<&ClassLikeInfo>, - existing_template_types: &[(StrId, Vec<(StrId, Arc)>)], - class_template_params: &IndexMap)>>, -) -> IndexMap> { - let mut template_types: IndexMap)>> = + existing_template_types: &[(StrId, Vec<(GenericParent, Arc)>)], + class_template_params: &IndexMap)>>, +) -> IndexMap> { + let mut template_types: IndexMap)>> = IndexMap::from_iter(existing_template_types.to_owned()); if let Some(declaring_classlike_storage) = declaring_classlike_storage { @@ -1144,7 +1144,7 @@ pub(crate) fn get_template_types_for_call( let mut output_type = None; for atomic_type in &type_.types { let output_type_candidate = if let TAtomic::TGenericParam { - defining_entity, + defining_entity: GenericParent::ClassLike(defining_entity), param_name, .. } = &atomic_type @@ -1179,7 +1179,10 @@ pub(crate) fn get_template_types_for_call( template_types .entry(*template_name) .or_insert_with(Vec::new) - .push((declaring_classlike_storage.name, output_type)); + .push(( + GenericParent::ClassLike(declaring_classlike_storage.name), + output_type, + )); } } } diff --git a/src/analyzer/expr/call/class_template_param_collector.rs b/src/analyzer/expr/call/class_template_param_collector.rs index 99b1afc5..03d0f4ee 100644 --- a/src/analyzer/expr/call/class_template_param_collector.rs +++ b/src/analyzer/expr/call/class_template_param_collector.rs @@ -5,6 +5,7 @@ use rustc_hash::FxHashMap; use hakana_reflection_info::{ classlike_info::ClassLikeInfo, codebase_info::CodebaseInfo, t_atomic::TAtomic, t_union::TUnion, + GenericParent, }; use hakana_type::{add_optional_union_type, get_mixed_any, wrap_atomic}; use indexmap::IndexMap; @@ -14,7 +15,7 @@ pub(crate) fn collect( class_storage: &ClassLikeInfo, static_class_storage: &ClassLikeInfo, lhs_type_part: Option<&TAtomic>, // default None -) -> Option>> { +) -> Option>> { let template_types = &class_storage.template_types; if template_types.is_empty() { @@ -38,7 +39,10 @@ pub(crate) fn collect( class_template_params .entry(*type_name) .or_insert_with(FxHashMap::default) - .insert(class_storage.name, type_param.clone()); + .insert( + GenericParent::ClassLike(class_storage.name), + type_param.clone(), + ); } } } @@ -65,7 +69,7 @@ pub(crate) fn collect( .entry(*template_name) .or_insert_with(FxHashMap::default) .insert( - class_storage.name, + GenericParent::ClassLike(class_storage.name), output_type_extends.unwrap_or(get_mixed_any()), ); } @@ -74,7 +78,7 @@ pub(crate) fn collect( class_template_params .entry(*template_name) .or_insert_with(FxHashMap::default) - .entry(class_storage.name) + .entry(GenericParent::ClassLike(class_storage.name)) .or_insert(get_mixed_any()); } } @@ -90,7 +94,7 @@ pub(crate) fn collect( class_template_params .entry(*template_name) .or_insert_with(FxHashMap::default) - .entry(class_storage.name) + .entry(GenericParent::ClassLike(class_storage.name)) .or_insert(TUnion::new(expand_type( extended_type, e, @@ -106,7 +110,7 @@ pub(crate) fn collect( .. }) = lhs_type_part { - template_classname == self_class_name + template_classname == &GenericParent::ClassLike(*self_class_name) } else { false }; @@ -115,7 +119,7 @@ pub(crate) fn collect( class_template_params .entry(*template_name) .or_insert_with(FxHashMap::default) - .entry(class_storage.name) + .entry(GenericParent::ClassLike(class_storage.name)) .or_insert((**type_).clone()); } } @@ -135,7 +139,7 @@ pub(crate) fn resolve_template_param( for type_extends_atomic in &input_type_extends.types { if let TAtomic::TGenericParam { param_name, - defining_entity, + defining_entity: GenericParent::ClassLike(defining_entity), .. } = &type_extends_atomic { @@ -191,14 +195,14 @@ fn expand_type( input_type_extends: &Arc, e: &FxHashMap>>, static_classlike_name: &StrId, - static_template_types: &Vec<(StrId, Vec<(StrId, Arc)>)>, + static_template_types: &Vec<(StrId, Vec<(GenericParent, Arc)>)>, ) -> Vec { let mut output_type_extends = Vec::new(); for type_extends_atomic in &input_type_extends.types { if let Some(extended_type) = if let TAtomic::TGenericParam { param_name, - defining_entity, + defining_entity: GenericParent::ClassLike(defining_entity), .. } = type_extends_atomic { 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 849331a7..2c5b582d 100644 --- a/src/analyzer/expr/call/existing_atomic_method_call_analyzer.rs +++ b/src/analyzer/expr/call/existing_atomic_method_call_analyzer.rs @@ -9,7 +9,7 @@ use hakana_reflection_info::{ t_atomic::{DictKey, TAtomic}, t_union::TUnion, }; -use hakana_reflection_info::{EFFECT_WRITE_LOCAL, EFFECT_WRITE_PROPS}; +use hakana_reflection_info::{GenericParent, EFFECT_WRITE_LOCAL, EFFECT_WRITE_PROPS}; use hakana_str::StrId; use hakana_type::get_null; use hakana_type::template::standin_type_replacer; @@ -148,7 +148,7 @@ pub(crate) fn analyze( let template_type = class_template_params .get(template_name) .unwrap() - .get(&declaring_method_id.0) + .get(&GenericParent::ClassLike(declaring_method_id.0)) .unwrap(); standin_type_replacer::replace( 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 fa93faa3..0c2ad4f3 100644 --- a/src/analyzer/expr/call/function_call_return_type_fetcher.rs +++ b/src/analyzer/expr/call/function_call_return_type_fetcher.rs @@ -10,6 +10,7 @@ use hakana_reflection_info::functionlike_info::FunctionLikeInfo; use hakana_reflection_info::t_atomic::{DictKey, TAtomic}; use hakana_reflection_info::t_union::TUnion; use hakana_reflection_info::taint::SinkType; +use hakana_reflection_info::GenericParent; use hakana_str::{Interner, StrId}; use hakana_type::type_comparator::type_comparison_result::TypeComparisonResult; use hakana_type::type_comparator::union_type_comparator; @@ -76,28 +77,20 @@ pub(crate) fn fetch( if !function_storage.template_types.is_empty() && !function_storage.template_types.is_empty() { - let interner = statements_analyzer.get_interner(); - let fn_id = interner - .get( - format!( - "fn-{}", - match functionlike_id { - FunctionLikeIdentifier::Function(function_id) => function_id.0, - FunctionLikeIdentifier::Method(_, _) => panic!(), - _ => { - panic!() - } - } - ) - .as_str(), - ) - .unwrap(); + let fn_id = match functionlike_id { + FunctionLikeIdentifier::Function(function_id) => function_id, + FunctionLikeIdentifier::Method(_, _) => panic!(), + _ => { + panic!() + } + }; + for (template_name, _) in &function_storage.template_types { if template_result.lower_bounds.get(template_name).is_none() { template_result.lower_bounds.insert( *template_name, FxHashMap::from_iter([( - fn_id, + GenericParent::FunctionLike(*fn_id), vec![TemplateBound::new(get_nothing(), 1, None, None)], )]), ); 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 0a1b279c..725512a4 100644 --- a/src/analyzer/expr/call/method_call_return_type_fetcher.rs +++ b/src/analyzer/expr/call/method_call_return_type_fetcher.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use hakana_reflection_info::functionlike_identifier::FunctionLikeIdentifier; +use hakana_reflection_info::GenericParent; use hakana_str::{Interner, StrId}; use oxidized::{aast, ast_defs}; use rustc_hash::FxHashMap; @@ -72,20 +73,12 @@ pub(crate) fn fetch( let mut template_result = template_result.clone(); if !functionlike_storage.template_types.is_empty() { - let fn_id = format!( - "fn-{}::{}", - declaring_method_id.0 .0, declaring_method_id.1 .0, - ); - let fn_id = statements_analyzer - .get_interner() - .get(fn_id.as_str()) - .unwrap(); for (template_name, _) in &functionlike_storage.template_types { template_result .lower_bounds .entry(*template_name) .or_insert(FxHashMap::from_iter([( - fn_id, + GenericParent::FunctionLike(declaring_method_id.1), vec![TemplateBound::new(get_nothing(), 1, None, None)], )])); } diff --git a/src/analyzer/expr/call/new_analyzer.rs b/src/analyzer/expr/call/new_analyzer.rs index cdcbf46a..6dfa0151 100644 --- a/src/analyzer/expr/call/new_analyzer.rs +++ b/src/analyzer/expr/call/new_analyzer.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use hakana_reflection_info::classlike_info::Variance; -use hakana_reflection_info::EFFECT_WRITE_GLOBALS; +use hakana_reflection_info::{GenericParent, EFFECT_WRITE_GLOBALS}; use hakana_reflection_info::data_flow::node::DataFlowNode; use hakana_reflection_info::functionlike_info::FunctionLikeInfo; @@ -406,7 +406,9 @@ fn analyze_named_constructor( let mut placeholder_lower_bounds = vec![]; if let Some(bounds) = template_result.lower_bounds.get(template_name) { - if let Some(bounds) = bounds.get(&classlike_name) { + if let Some(bounds) = + bounds.get(&GenericParent::ClassLike(classlike_name)) + { for bound in bounds { placeholder_lower_bounds.push(bound.clone()); } @@ -476,7 +478,7 @@ fn analyze_named_constructor( let mut generic_param_type = if let Some(template_bounds) = if let Some(result_map) = template_result.lower_bounds.get(template_name) { - result_map.get(&classlike_name) + result_map.get(&GenericParent::ClassLike(classlike_name)) } else { None } { diff --git a/src/analyzer/expr/call_analyzer.rs b/src/analyzer/expr/call_analyzer.rs index e91d54bb..daad29ad 100644 --- a/src/analyzer/expr/call_analyzer.rs +++ b/src/analyzer/expr/call_analyzer.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use hakana_reflection_info::code_location::HPos; use hakana_reflection_info::issue::{Issue, IssueKind}; -use hakana_reflection_info::{EFFECT_IMPURE, EFFECT_WRITE_PROPS}; +use hakana_reflection_info::{GenericParent, EFFECT_IMPURE, EFFECT_WRITE_PROPS}; use hakana_str::StrId; use hakana_type::template::standin_type_replacer::get_relevant_bounds; use hakana_type::type_comparator::type_comparison_result::TypeComparisonResult; @@ -321,13 +321,13 @@ pub(crate) fn get_generic_param_for_offset( classlike_name: &StrId, template_name: &StrId, template_extended_params: &FxHashMap>>, - found_generic_params: &FxHashMap)>>, + found_generic_params: &FxHashMap)>>, ) -> Arc { if let Some(found_generic_param) = if let Some(result_map) = found_generic_params.get(template_name) { result_map .iter() - .filter(|(e, _)| e == classlike_name) + .filter(|(e, _)| e == &GenericParent::ClassLike(*classlike_name)) .map(|(_, v)| v) .next() } else { @@ -345,7 +345,8 @@ pub(crate) fn get_generic_param_for_offset( .. } = &extended_atomic_type { - if extended_param_name == template_name && defining_entity == classlike_name + if extended_param_name == template_name + && defining_entity == &GenericParent::ClassLike(*classlike_name) { return get_generic_param_for_offset( extended_class_name, diff --git a/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs b/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs index fbc806c2..b3af106b 100644 --- a/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs +++ b/src/analyzer/expr/fetch/atomic_property_fetch_analyzer.rs @@ -7,6 +7,7 @@ use crate::{ use crate::{scope_context::ScopeContext, statements_analyzer::StatementsAnalyzer}; use hakana_reflection_info::code_location::HPos; use hakana_reflection_info::issue::{Issue, IssueKind}; +use hakana_reflection_info::GenericParent; use hakana_reflection_info::{ classlike_info::ClassLikeInfo, codebase_info::CodebaseInfo, @@ -334,7 +335,10 @@ pub(crate) fn localize_property_type( template_types .entry(*calling_param_name) .or_insert_with(FxHashMap::default) - .insert(property_class_storage.name, lhs_param_type.clone()); + .insert( + GenericParent::ClassLike(property_class_storage.name), + lhs_param_type.clone(), + ); break; } } @@ -365,7 +369,9 @@ pub(crate) fn localize_property_type( .entry(type_name) .or_insert_with(FxHashMap::default) .insert( - property_declaring_class_storage.name, + GenericParent::ClassLike( + property_declaring_class_storage.name, + ), mapped_param.clone(), ); } diff --git a/src/analyzer/functionlike_analyzer.rs b/src/analyzer/functionlike_analyzer.rs index 1f7420ff..d10424db 100644 --- a/src/analyzer/functionlike_analyzer.rs +++ b/src/analyzer/functionlike_analyzer.rs @@ -292,7 +292,6 @@ impl<'a> FunctionLikeAnalyzer<'a> { param_name: *param_name, as_type: Box::new((*first_map_entry.1).clone()), defining_entity: first_map_entry.0, - from_class: false, extra_types: None, }) }) diff --git a/src/code_info/classlike_info.rs b/src/code_info/classlike_info.rs index dd0fadb1..85d25d0e 100644 --- a/src/code_info/classlike_info.rs +++ b/src/code_info/classlike_info.rs @@ -5,7 +5,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ code_location::HPos, codebase_info::symbols::SymbolKind, functionlike_info::MetaStart, - t_atomic::TAtomic, t_union::TUnion, + t_atomic::TAtomic, t_union::TUnion, GenericParent, }; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; @@ -131,7 +131,7 @@ pub struct ClassLikeInfo { * (i.e. the same as the class name). This allows operations with the same-named template defined * across multiple classes to not run into trouble. */ - pub template_types: Vec<(StrId, Vec<(StrId, Arc)>)>, + pub template_types: Vec<(StrId, Vec<(GenericParent, Arc)>)>, /* * A list of all the templates that are only written in the constructor. diff --git a/src/code_info/functionlike_info.rs b/src/code_info/functionlike_info.rs index 8567f8cf..37fcb331 100644 --- a/src/code_info/functionlike_info.rs +++ b/src/code_info/functionlike_info.rs @@ -15,6 +15,7 @@ use crate::{ t_union::TUnion, taint::{SinkType, SourceType}, type_resolution::TypeResolutionContext, + GenericParent, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -84,7 +85,7 @@ pub struct FunctionLikeInfo { * function identifier. This allows operations with the same-named template defined * across multiple classes and/or functions to not run into trouble. */ - pub template_types: Vec<(StrId, Vec<(StrId, Arc)>)>, + pub template_types: Vec<(StrId, Vec<(GenericParent, Arc)>)>, pub assertions: Option>, diff --git a/src/code_info/lib.rs b/src/code_info/lib.rs index 02022cf0..020a2678 100644 --- a/src/code_info/lib.rs +++ b/src/code_info/lib.rs @@ -32,7 +32,9 @@ pub mod type_resolution; use std::collections::BTreeMap; use code_location::FilePath; +use hakana_str::{Interner, StrId}; use oxidized::{prim_defs::Comment, tast::Pos}; +use serde::{Deserialize, Serialize}; #[derive(Clone)] pub struct FileSource<'a> { @@ -52,3 +54,38 @@ pub const EFFECT_WRITE_PROPS: u8 = 0b00001000; pub const EFFECT_WRITE_GLOBALS: u8 = 0b0010000; pub const EFFECT_IMPURE: u8 = EFFECT_READ_PROPS | EFFECT_READ_GLOBALS | EFFECT_WRITE_PROPS | EFFECT_WRITE_GLOBALS; + +#[derive(PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord, Debug)] +pub enum GenericParent { + ClassLike(StrId), + FunctionLike(StrId), + TypeDefinition(StrId), +} + +impl GenericParent { + pub fn to_string(&self, interner: Option<&Interner>) -> String { + match self { + GenericParent::ClassLike(id) => { + if let Some(interner) = interner { + interner.lookup(id).to_string() + } else { + id.0.to_string() + } + } + GenericParent::FunctionLike(id) => { + if let Some(interner) = interner { + format!("fn-{}", interner.lookup(id)) + } else { + format!("fn-{}", id.0) + } + } + GenericParent::TypeDefinition(id) => { + if let Some(interner) = interner { + format!("type-{}", interner.lookup(id)) + } else { + format!("type-{}", id.0) + } + } + } + } +} diff --git a/src/code_info/t_atomic.rs b/src/code_info/t_atomic.rs index 6ccd9901..a596e037 100644 --- a/src/code_info/t_atomic.rs +++ b/src/code_info/t_atomic.rs @@ -2,6 +2,7 @@ use crate::code_location::FilePath; use crate::functionlike_identifier::FunctionLikeIdentifier; use crate::functionlike_parameter::FnParameter; use crate::symbol_references::{ReferenceSource, SymbolReferences}; +use crate::GenericParent; use crate::{ codebase_info::{symbols::SymbolKind, Symbols}, t_union::{populate_union_type, HasTypeNodes, TUnion, TypeNode}, @@ -115,18 +116,17 @@ pub enum TAtomic { TGenericParam { param_name: StrId, as_type: Box, - defining_entity: StrId, - from_class: bool, + defining_entity: GenericParent, extra_types: Option>, }, TGenericClassname { param_name: StrId, - defining_entity: StrId, + defining_entity: GenericParent, as_type: Box, }, TGenericTypename { param_name: StrId, - defining_entity: StrId, + defining_entity: GenericParent, as_type: Box, }, TTypeVariable { @@ -533,11 +533,7 @@ impl TAtomic { str += param_name.0.to_string().as_str(); }; str += ":"; - if let Some(interner) = interner { - str += interner.lookup(defining_entity); - } else { - str += defining_entity.0.to_string().as_str(); - } + str += &defining_entity.to_string(interner); str } TAtomic::TGenericClassname { @@ -553,11 +549,7 @@ impl TAtomic { str += param_name.0.to_string().as_str(); } str += ":"; - if let Some(interner) = interner { - str += interner.lookup(defining_entity); - } else { - str += defining_entity.0.to_string().as_str(); - } + str += &defining_entity.to_string(interner); str += ">"; str } @@ -574,11 +566,7 @@ impl TAtomic { str += param_name.0.to_string().as_str(); } str += ":"; - if let Some(interner) = interner { - str += interner.lookup(defining_entity); - } else { - str += defining_entity.0.to_string().as_str(); - } + str += &defining_entity.to_string(interner); str += ">"; str } @@ -773,7 +761,7 @@ impl TAtomic { let mut str = String::new(); str += param_name.0.to_string().as_str(); str += ":"; - str += defining_entity.0.to_string().as_str(); + str += &defining_entity.to_string(None); str } TAtomic::TGenericClassname { @@ -785,7 +773,7 @@ impl TAtomic { str += "classname<"; str += param_name.0.to_string().as_str(); str += ":"; - str += defining_entity.0.to_string().as_str(); + str += &defining_entity.to_string(None); str += ">"; str } @@ -798,7 +786,7 @@ impl TAtomic { str += "typename<"; str += param_name.0.to_string().as_str(); str += ":"; - str += defining_entity.0.to_string().as_str(); + str += &defining_entity.to_string(None); str += ">"; str } @@ -1020,7 +1008,6 @@ impl TAtomic { param_name, defining_entity, extra_types, - from_class, .. } = self { @@ -1029,7 +1016,6 @@ impl TAtomic { param_name: *param_name, defining_entity: *defining_entity, extra_types: extra_types.clone(), - from_class: *from_class, }; } diff --git a/src/code_info/type_definition_info.rs b/src/code_info/type_definition_info.rs index 0177194e..981120bf 100644 --- a/src/code_info/type_definition_info.rs +++ b/src/code_info/type_definition_info.rs @@ -12,6 +12,7 @@ use crate::{ t_atomic::DictKey, t_union::TUnion, taint::SourceType, + GenericParent, }; #[derive(Clone, Serialize, Deserialize, Debug)] @@ -29,7 +30,7 @@ pub struct TypeDefinitionInfo { * function identifier. This allows operations with the same-named template defined * across multiple classes and/or functions to not run into trouble. */ - pub template_types: Vec<(StrId, Vec<(StrId, Arc)>)>, + pub template_types: Vec<(StrId, Vec<(GenericParent, Arc)>)>, pub generic_variance: FxHashMap, diff --git a/src/code_info/type_resolution.rs b/src/code_info/type_resolution.rs index 330f2a5b..0496cf67 100644 --- a/src/code_info/type_resolution.rs +++ b/src/code_info/type_resolution.rs @@ -5,11 +5,11 @@ use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; -use crate::t_union::TUnion; +use crate::{t_union::TUnion, GenericParent}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TypeResolutionContext { - pub template_type_map: Vec<(StrId, Vec<(StrId, Arc)>)>, + pub template_type_map: Vec<(StrId, Vec<(GenericParent, Arc)>)>, pub template_supers: FxHashMap, } diff --git a/src/code_info_builder/classlike_scanner.rs b/src/code_info_builder/classlike_scanner.rs index f0759f77..c103b411 100644 --- a/src/code_info_builder/classlike_scanner.rs +++ b/src/code_info_builder/classlike_scanner.rs @@ -17,7 +17,7 @@ use hakana_reflection_info::{ property_info::{PropertyInfo, PropertyKind}, t_atomic::TAtomic, type_resolution::TypeResolutionContext, - FileSource, + FileSource, GenericParent, }; use hakana_type::{get_mixed_any, get_named_object, wrap_atomic}; use oxidized::{ @@ -90,9 +90,13 @@ pub(crate) fn scan( let param_name = resolved_names .get(&(type_param_node.name.0.start_offset() as u32)) .unwrap(); - type_context - .template_type_map - .push((*param_name, vec![(*class_name, Arc::new(get_mixed_any()))])); + type_context.template_type_map.push(( + *param_name, + vec![( + GenericParent::ClassLike(*class_name), + Arc::new(get_mixed_any()), + )], + )); } for (i, type_param_node) in classlike_node.tparams.iter().enumerate() { @@ -128,9 +132,13 @@ pub(crate) fn scan( .get(&(type_param_node.name.0.start_offset() as u32)) .unwrap(); - storage - .template_types - .push((*param_name, vec![(*class_name, Arc::new(template_as_type))])); + storage.template_types.push(( + *param_name, + vec![( + GenericParent::ClassLike(*class_name), + Arc::new(template_as_type), + )], + )); match type_param_node.variance { ast_defs::Variance::Covariant => { diff --git a/src/code_info_builder/functionlike_scanner.rs b/src/code_info_builder/functionlike_scanner.rs index a06aca0d..fe930455 100644 --- a/src/code_info_builder/functionlike_scanner.rs +++ b/src/code_info_builder/functionlike_scanner.rs @@ -23,6 +23,7 @@ use hakana_reflection_info::taint::string_to_sink_types; use hakana_reflection_info::taint::string_to_source_types; use hakana_reflection_info::type_resolution::TypeResolutionContext; use hakana_reflection_info::FileSource; +use hakana_reflection_info::GenericParent; use hakana_reflection_info::EFFECT_IMPURE; use hakana_str::{StrId, ThreadedInterner}; use hakana_type::get_mixed_any; @@ -184,20 +185,17 @@ pub(crate) fn get_functionlike( let mut template_supers = FxHashMap::default(); if !tparams.is_empty() { - let fn_id = if let Some(this_name) = this_name { - format!("fn-{}::{}", this_name.0, name.unwrap().0) - } else { - format!("fn-{}", name.unwrap().0) - }; - let fn_id = interner.intern(fn_id); - for type_param_node in tparams.iter() { let param_name = resolved_names .get(&(type_param_node.name.0.start_offset() as u32)) .unwrap(); - type_context - .template_type_map - .push((*param_name, vec![(fn_id, Arc::new(get_mixed_any()))])); + type_context.template_type_map.push(( + *param_name, + vec![( + GenericParent::FunctionLike(name.unwrap()), + Arc::new(get_mixed_any()), + )], + )); } for type_param_node in tparams.iter() { @@ -241,8 +239,7 @@ pub(crate) fn get_functionlike( } else { get_mixed_any() }), - defining_entity: fn_id, - from_class: false, + defining_entity: GenericParent::FunctionLike(name.unwrap()), extra_types: None, }); @@ -252,7 +249,10 @@ pub(crate) fn get_functionlike( functionlike_info.template_types.push(( *param_name, - vec![(fn_id, Arc::new(template_as_type.unwrap_or(get_mixed_any())))], + vec![( + GenericParent::FunctionLike(name.unwrap()), + Arc::new(template_as_type.unwrap_or(get_mixed_any())), + )], )); } diff --git a/src/code_info_builder/lib.rs b/src/code_info_builder/lib.rs index d66ced59..e645b091 100644 --- a/src/code_info_builder/lib.rs +++ b/src/code_info_builder/lib.rs @@ -7,13 +7,13 @@ use hakana_reflection_info::attribute_info::AttributeInfo; use hakana_reflection_info::file_info::FileInfo; use hakana_reflection_info::functionlike_info::FunctionLikeInfo; use hakana_reflection_info::t_union::TUnion; -use hakana_reflection_info::FileSource; use hakana_reflection_info::{ ast_signature::DefSignatureNode, class_constant_info::ConstantInfo, classlike_info::Variance, code_location::HPos, codebase_info::CodebaseInfo, t_atomic::TAtomic, taint::string_to_source_types, type_definition_info::TypeDefinitionInfo, type_resolution::TypeResolutionContext, }; +use hakana_reflection_info::{FileSource, GenericParent}; use hakana_str::{StrId, ThreadedInterner}; use hakana_type::{get_bool, get_int, get_mixed_any, get_string}; use no_pos_hash::{position_insensitive_hash, Hasher}; @@ -213,9 +213,13 @@ impl<'ast> Visitor<'ast> for Scanner<'_> { .resolved_names .get(&(type_param_node.name.0.start_offset() as u32)) .unwrap(); - type_context - .template_type_map - .push((*param_name, vec![(type_name, Arc::new(get_mixed_any()))])); + type_context.template_type_map.push(( + *param_name, + vec![( + GenericParent::TypeDefinition(type_name), + Arc::new(get_mixed_any()), + )], + )); } for (i, param) in typedef.tparams.iter().enumerate() { @@ -236,8 +240,7 @@ impl<'ast> Visitor<'ast> for Scanner<'_> { }; let h = vec![( - self.interner - .intern("typedef-".to_string() + &type_name.0.to_string()), + GenericParent::TypeDefinition(type_name), Arc::new(constraint_type.clone()), )]; diff --git a/src/code_info_builder/typehint_resolver.rs b/src/code_info_builder/typehint_resolver.rs index e49a5298..389d8d26 100644 --- a/src/code_info_builder/typehint_resolver.rs +++ b/src/code_info_builder/typehint_resolver.rs @@ -4,6 +4,7 @@ use hakana_reflection_info::t_atomic::DictKey; use hakana_reflection_info::t_atomic::TAtomic; use hakana_reflection_info::t_union::TUnion; use hakana_reflection_info::type_resolution::TypeResolutionContext; +use hakana_reflection_info::GenericParent; use hakana_reflection_info::EFFECT_IMPURE; use hakana_reflection_info::EFFECT_PURE; use hakana_str::StrId; @@ -467,14 +468,16 @@ fn get_reference_type( } } -fn get_template_type(defining_entities: &[(StrId, Arc)], type_name: &StrId) -> TAtomic { +fn get_template_type( + defining_entities: &[(GenericParent, Arc)], + type_name: &StrId, +) -> TAtomic { let (defining_entity, as_type) = &defining_entities[0]; TAtomic::TGenericParam { param_name: *type_name, as_type: Box::new((**as_type).clone()), defining_entity: *defining_entity, - from_class: false, extra_types: None, } } diff --git a/src/file_scanner_analyzer/populator.rs b/src/file_scanner_analyzer/populator.rs index a691c545..287194c1 100644 --- a/src/file_scanner_analyzer/populator.rs +++ b/src/file_scanner_analyzer/populator.rs @@ -8,6 +8,7 @@ use hakana_reflection_info::member_visibility::MemberVisibility; use hakana_reflection_info::symbol_references::{ReferenceSource, SymbolReferences}; use hakana_reflection_info::t_atomic::{populate_atomic_type, TAtomic}; use hakana_reflection_info::t_union::{populate_union_type, TUnion}; +use hakana_reflection_info::GenericParent; use hakana_str::{Interner, StrId}; use indexmap::IndexMap; use rustc_hash::{FxHashMap, FxHashSet}; @@ -983,7 +984,7 @@ fn extend_type( while let Some(atomic_type) = cloned.pop() { if let TAtomic::TGenericParam { - defining_entity, + defining_entity: GenericParent::ClassLike(defining_entity), param_name, .. } = &atomic_type diff --git a/src/str/lib.rs b/src/str/lib.rs index 695dbea1..b9118b72 100644 --- a/src/str/lib.rs +++ b/src/str/lib.rs @@ -71,7 +71,7 @@ pub struct ThreadedInterner { impl ThreadedInterner { pub fn new(interner: Arc>) -> Self { ThreadedInterner { - map: IndexMap::new(), + map: IndexMap::default(), reverse_map: BTreeMap::new(), parent: interner.clone(), } diff --git a/src/ttype/lib.rs b/src/ttype/lib.rs index 07330ec1..df2f3414 100644 --- a/src/ttype/lib.rs +++ b/src/ttype/lib.rs @@ -670,7 +670,7 @@ pub fn get_atomic_syntax_type( } => format!( "classname<{}:{}>", interner.lookup(param_name), - interner.lookup(defining_entity) + defining_entity.to_string(Some(interner)) ), TAtomic::TGenericTypename { param_name, @@ -679,7 +679,7 @@ pub fn get_atomic_syntax_type( } => format!( "typename<{}:{}>", interner.lookup(param_name), - interner.lookup(defining_entity) + defining_entity.to_string(Some(interner)) ), TAtomic::TTrue { .. } => "bool".to_string(), TAtomic::TVec { diff --git a/src/ttype/template/inferred_type_replacer.rs b/src/ttype/template/inferred_type_replacer.rs index 4f97914d..5fddf139 100644 --- a/src/ttype/template/inferred_type_replacer.rs +++ b/src/ttype/template/inferred_type_replacer.rs @@ -1,6 +1,8 @@ use std::sync::Arc; -use hakana_reflection_info::{codebase_info::CodebaseInfo, t_atomic::TAtomic, t_union::TUnion}; +use hakana_reflection_info::{ + codebase_info::CodebaseInfo, t_atomic::TAtomic, t_union::TUnion, GenericParent, +}; use hakana_str::StrId; use indexmap::IndexMap; use rustc_hash::{FxHashMap, FxHashSet}; @@ -148,7 +150,7 @@ pub fn replace( param_name: *param_name, as_type: Box::new(first_atomic_type.clone()), defining_entity: *defining_entity, - }) + }); } } @@ -176,9 +178,9 @@ pub fn replace( } fn replace_template_param( - inferred_lower_bounds: &IndexMap>>, + inferred_lower_bounds: &IndexMap>>, param_name: &StrId, - defining_entity: &StrId, + defining_entity: &GenericParent, codebase: &CodebaseInfo, as_type: &TUnion, extra_types: &Option>, @@ -214,30 +216,34 @@ fn replace_template_param( } else { for (_, template_type_map) in inferred_lower_bounds { for map_defining_entity in template_type_map.keys() { - if !codebase.classlike_infos.contains_key(map_defining_entity) { - continue; - } - - let classlike_info = codebase.classlike_infos.get(map_defining_entity).unwrap(); - - if let Some(param_map) = - classlike_info.template_extended_params.get(defining_entity) - { - if let Some(param_inner) = param_map.get(key) { - let template_name = if let TAtomic::TGenericParam { param_name, .. } = - param_inner.get_single() - { - param_name - } else { - panic!() - }; - if let Some(bounds_map) = inferred_lower_bounds.get(template_name) { - if let Some(bounds) = bounds_map.get(map_defining_entity) { - template_type = Some( - standin_type_replacer::get_most_specific_type_from_bounds( - bounds, codebase, - ), - ); + let classlike_name = match map_defining_entity { + GenericParent::ClassLike(e) => e, + _ => { + continue; + } + }; + + if let Some(classlike_info) = codebase.classlike_infos.get(classlike_name) { + if let Some(param_map) = + classlike_info.template_extended_params.get(classlike_name) + { + if let Some(param_inner) = param_map.get(key) { + let template_name = + if let TAtomic::TGenericParam { param_name, .. } = + param_inner.get_single() + { + param_name + } else { + panic!() + }; + if let Some(bounds_map) = inferred_lower_bounds.get(template_name) { + if let Some(bounds) = bounds_map.get(map_defining_entity) { + template_type = Some( + standin_type_replacer::get_most_specific_type_from_bounds( + bounds, codebase, + ), + ); + } } } } diff --git a/src/ttype/template/mod.rs b/src/ttype/template/mod.rs index 92778bb8..86f2fa0b 100644 --- a/src/ttype/template/mod.rs +++ b/src/ttype/template/mod.rs @@ -3,14 +3,14 @@ use std::sync::Arc; use hakana_str::StrId; use rustc_hash::FxHashMap; -use hakana_reflection_info::{code_location::HPos, t_union::TUnion}; +use hakana_reflection_info::{code_location::HPos, t_union::TUnion, GenericParent}; use indexmap::IndexMap; pub mod inferred_type_replacer; pub mod standin_type_replacer; /** - * This struct captures the result of running AHA's argument analysis with + * This struct captures the result of running Hakana's argument analysis with * regard to generic parameters. * * It captures upper and lower bounds for parameters. Mostly we just care about @@ -28,9 +28,9 @@ pub mod standin_type_replacer; */ #[derive(Clone, Debug)] pub struct TemplateResult { - pub template_types: IndexMap)>>, - pub lower_bounds: IndexMap>>, - pub upper_bounds: IndexMap>, + pub template_types: IndexMap)>>, + pub lower_bounds: IndexMap>>, + pub upper_bounds: IndexMap>, /** * If set to true then we shouldn't update the template bounds */ @@ -40,8 +40,8 @@ pub struct TemplateResult { impl TemplateResult { pub fn new( - template_types: IndexMap)>>, - lower_bounds: IndexMap>, + template_types: IndexMap)>>, + lower_bounds: IndexMap>, ) -> TemplateResult { let mut new_lower_bounds = IndexMap::new(); diff --git a/src/ttype/template/standin_type_replacer.rs b/src/ttype/template/standin_type_replacer.rs index b15c57d8..ae34c37d 100644 --- a/src/ttype/template/standin_type_replacer.rs +++ b/src/ttype/template/standin_type_replacer.rs @@ -5,13 +5,13 @@ use crate::{ type_expander::{self, StaticClassType, TypeExpansionOptions}, wrap_atomic, }; -use hakana_reflection_info::function_context::FunctionLikeIdentifier; use hakana_reflection_info::{ codebase_info::CodebaseInfo, data_flow::graph::{DataFlowGraph, GraphKind}, t_atomic::TAtomic, t_union::TUnion, }; +use hakana_reflection_info::{function_context::FunctionLikeIdentifier, GenericParent}; use hakana_str::{Interner, StrId}; use indexmap::IndexMap; use rustc_hash::{FxHashMap, FxHashSet}; @@ -750,7 +750,7 @@ fn handle_template_param_standin( }; if let Some(calling_class) = calling_class { - if defining_entity == calling_class { + if defining_entity == &GenericParent::ClassLike(*calling_class) { return vec![atomic_type.clone()]; } } @@ -850,11 +850,13 @@ fn handle_template_param_standin( } = replacement_atomic_type { if (calling_class.is_none() - || replacement_defining_entity != calling_class.unwrap()) + || replacement_defining_entity + != &GenericParent::ClassLike(*calling_class.unwrap())) && (calling_function.is_none() || match calling_function.unwrap() { FunctionLikeIdentifier::Function(calling_function) => { - calling_function != replacement_defining_entity + replacement_defining_entity + != &GenericParent::FunctionLike(*calling_function) } FunctionLikeIdentifier::Method(_, _) => true, _ => { @@ -1138,7 +1140,7 @@ fn handle_template_param_class_standin( { let mut atomic_type_as = *as_type.clone(); if let Some(calling_class) = calling_class { - if defining_entity == calling_class { + if defining_entity == &GenericParent::ClassLike(*calling_class) { return vec![atomic_type.clone()]; } } @@ -1176,7 +1178,6 @@ fn handle_template_param_class_standin( param_name: *param_name, as_type: Box::new(wrap_atomic(*as_type.clone())), defining_entity: *defining_entity, - from_class: false, extra_types: None, }); } else if let TAtomic::TClassname { @@ -1322,7 +1323,7 @@ fn handle_template_param_type_standin( { let mut atomic_type_as = *as_type.clone(); if let Some(calling_class) = calling_class { - if defining_entity == calling_class { + if defining_entity == &GenericParent::ClassLike(*calling_class) { return vec![atomic_type.clone()]; } } @@ -1354,7 +1355,6 @@ fn handle_template_param_type_standin( param_name: *param_name, as_type: Box::new(wrap_atomic(*as_type.clone())), defining_entity: *defining_entity, - from_class: false, extra_types: None, }); } else if let TAtomic::TTypename { .. } = input_atomic_type { @@ -1515,9 +1515,9 @@ pub fn get_actual_type_from_literal(name: &StrId, codebase: &CodebaseInfo) -> Ve } fn template_types_contains<'a>( - template_types: &'a IndexMap)>>, + template_types: &'a IndexMap)>>, param_name: &StrId, - defining_entity: &StrId, + defining_entity: &GenericParent, ) -> Option<&'a Arc> { if let Some(mapped_classes) = template_types.get(param_name) { return mapped_classes @@ -1804,7 +1804,7 @@ pub fn get_mapped_generic_type_params( replacement_templates .entry(*template_name) .or_insert_with(FxHashMap::default) - .insert(*input_name, input_type.clone().1); + .insert(GenericParent::ClassLike(*input_name), input_type.clone().1); i += 1; } else { @@ -1840,7 +1840,7 @@ pub fn get_mapped_generic_type_params( .enumerate() .find(|(_, (n, _))| n == param_name) { - if defining_classes.iter().any(|(e, _)| e == defining_entity) { + if defining_classes.iter().any(|(e, _)| defining_entity == e) { let candidate_param_type_inner = input_type_params .get(old_params_offset) .unwrap_or(&(None, get_mixed_any())) @@ -1908,7 +1908,7 @@ pub fn get_extended_templated_types<'a>( let mut extra_added_types = Vec::new(); if let TAtomic::TGenericParam { - defining_entity, + defining_entity: GenericParent::ClassLike(defining_entity), param_name, .. } = atomic_type @@ -1935,10 +1935,10 @@ pub fn get_extended_templated_types<'a>( } pub(crate) fn get_root_template_type( - lower_bounds: &IndexMap>>, + lower_bounds: &IndexMap>>, param_name: &StrId, - defining_entity: &StrId, - mut visited_entities: FxHashSet, + defining_entity: &GenericParent, + mut visited_entities: FxHashSet, codebase: &CodebaseInfo, ) -> Option { if visited_entities.contains(defining_entity) { diff --git a/src/ttype/type_comparator/object_type_comparator.rs b/src/ttype/type_comparator/object_type_comparator.rs index 9a780234..37c752f2 100644 --- a/src/ttype/type_comparator/object_type_comparator.rs +++ b/src/ttype/type_comparator/object_type_comparator.rs @@ -1,5 +1,5 @@ use crate::wrap_atomic; -use hakana_reflection_info::{codebase_info::CodebaseInfo, t_atomic::TAtomic}; +use hakana_reflection_info::{codebase_info::CodebaseInfo, t_atomic::TAtomic, GenericParent}; use super::{type_comparison_result::TypeComparisonResult, union_type_comparator}; @@ -49,62 +49,59 @@ fn is_intersection_shallowly_contained_by( if let TAtomic::TGenericParam { defining_entity: container_defining_entity, param_name: container_param_name, - from_class: container_param_from_class, .. } = intersection_container_type { if let TAtomic::TGenericParam { defining_entity: input_defining_entity, - from_class: input_param_from_class, param_name: input_param_name, as_type: input_extends, .. } = intersection_input_type { - if !input_param_from_class || !container_param_from_class { - if !input_param_from_class - && !container_param_from_class - && input_defining_entity != container_defining_entity - { - return true; - } - - for input_as_atomic in &input_extends.types { - // todo use type equality - if input_as_atomic == intersection_container_type { - return true; - } - } - } - if input_param_name == container_param_name && input_defining_entity == container_defining_entity { return true; } - if input_param_name != container_param_name - || (input_defining_entity != container_defining_entity - && *input_param_from_class - && *container_param_from_class) - { - if !input_param_from_class && !container_param_from_class { - return false; + match (input_defining_entity, container_defining_entity) { + ( + GenericParent::ClassLike(input_defining_class), + GenericParent::ClassLike(container_defining_class), + ) => { + if input_defining_class != container_defining_class { + if let Some(input_class_storage) = + codebase.classlike_infos.get(input_defining_class) + { + if let Some(defining_entity_params) = &input_class_storage + .template_extended_params + .get(container_defining_class) + { + if defining_entity_params.get(container_param_name).is_some() { + return true; + } + } + } + } } - - if let Some(input_class_storage) = - codebase.classlike_infos.get(input_defining_entity) - { - if let Some(defining_entity_params) = &input_class_storage - .template_extended_params - .get(container_defining_entity) - { - if defining_entity_params.get(container_param_name).is_some() { + (GenericParent::ClassLike(_), _) | (_, GenericParent::ClassLike(_)) => { + for input_as_atomic in &input_extends.types { + // todo use type equality + if input_as_atomic == intersection_container_type { return true; } } } - } + _ => { + if input_param_name != container_param_name { + return false; + } + if input_defining_entity != container_defining_entity { + return true; + } + } + }; return false; } diff --git a/src/ttype/type_expander.rs b/src/ttype/type_expander.rs index 57d2b42f..4d6e9967 100644 --- a/src/ttype/type_expander.rs +++ b/src/ttype/type_expander.rs @@ -221,13 +221,9 @@ fn expand_atomic( } } } else if let TAtomic::TGenericParam { - ref mut from_class, - ref defining_entity, - ref mut as_type, - .. + ref mut as_type, .. } = return_type_part { - *from_class = codebase.classlike_infos.contains_key(defining_entity); expand_union(codebase, interner, as_type, options, data_flow_graph); return;