use std::sync::Arc;
use mir_issues::Issue;
use mir_types::Type;
use super::*;
#[derive(Clone, Debug)]
pub struct FunctionInferenceResult {
pub issues: Vec<Issue>,
pub ref_locs: Vec<RefLoc>,
pub return_type: Option<Type>,
}
impl PartialEq for FunctionInferenceResult {
fn eq(&self, other: &Self) -> bool {
self.issues == other.issues
&& self.ref_locs == other.ref_locs
&& self.return_type == other.return_type
}
}
impl Eq for FunctionInferenceResult {}
unsafe impl salsa::Update for FunctionInferenceResult {
unsafe fn maybe_update(old_ptr: *mut Self, new_val: Self) -> bool {
let old = unsafe { &mut *old_ptr };
if *old == new_val {
return false;
}
*old = new_val;
true
}
}
fn find_function_decl<'a>(
program: &'a php_ast::owned::Program,
db: &dyn MirDatabase,
file: &str,
target_fqn: &str,
) -> Option<&'a php_ast::owned::FunctionDecl> {
use php_ast::owned::StmtKind;
let mut found: Option<&'a php_ast::owned::FunctionDecl> = None;
crate::body_analysis::for_each_file_scope_decl(&program.stmts, &mut |stmt| {
if found.is_some() {
return;
}
if let StmtKind::Function(decl) = &stmt.kind {
let name = decl.name.as_deref().unwrap_or("");
if !name.is_empty() && crate::db::resolve_name(db, file, name) == target_fqn {
found = Some(decl);
}
}
});
found
}
#[salsa::tracked]
pub fn infer_function(
db: &dyn MirDatabase,
file: SourceFile,
fn_fqn: Arc<str>,
input: crate::db::AnalyzeFileInput,
) -> Option<Arc<FunctionInferenceResult>> {
use std::str::FromStr as _;
let path = file.path(db);
let text = file.text(db);
let php_version = crate::php_version::PhpVersion::from_str(input.php_version(db).as_ref())
.unwrap_or(crate::php_version::PhpVersion::LATEST);
let parsed_file = crate::db::parse_file(db, file);
let parsed = &*parsed_file.0;
if parsed.errors.iter().any(crate::parser::is_hard_parse_error) {
return None;
}
let decl = find_function_decl(&parsed.program, db, path.as_ref(), fn_fqn.as_ref())?;
let driver = crate::body_analysis::BodyAnalyzer::new(db, php_version);
let result = driver.analyze_fn_decl_pure(decl, &path, text.as_ref(), &parsed.source_map);
Some(Arc::new(result))
}