use std::sync::Arc;
use mir_issues::Issue;
use php_ast::ast::Program;
use php_rs_parser::source_map::SourceMap;
use rayon::prelude::*;
use crate::db::MirDatabase;
use crate::pass2::Pass2Driver;
use crate::session::AnalysisSession;
use crate::symbol::ResolvedSymbol;
pub struct FileAnalysis {
pub issues: Vec<Issue>,
pub symbols: Vec<ResolvedSymbol>,
}
impl FileAnalysis {
pub fn symbol_at(&self, byte_offset: u32) -> Option<&ResolvedSymbol> {
self.symbols
.iter()
.filter(|s| s.span.start <= byte_offset && byte_offset < s.span.end)
.min_by_key(|s| s.span.end - s.span.start)
}
}
pub struct FileAnalyzer<'a> {
session: &'a AnalysisSession,
}
impl<'a> FileAnalyzer<'a> {
pub fn new(session: &'a AnalysisSession) -> Self {
Self { session }
}
pub fn analyze(
&self,
file: Arc<str>,
source: &str,
program: &Program<'_, '_>,
source_map: &SourceMap,
) -> FileAnalysis {
self.session.ensure_essential_stubs_loaded();
self.session.ensure_stubs_for_ast(program);
let db = self.session.snapshot_db();
let driver = Pass2Driver::new(&db, self.session.php_version());
let (issues, symbols) = driver.analyze_bodies(program, file, source, source_map);
FileAnalysis { issues, symbols }
}
}
pub struct BatchFileAnalyzer<'a> {
session: &'a AnalysisSession,
}
pub struct ParsedFile {
pub file: Arc<str>,
pub source: Arc<str>,
pub program: *const Program<'static, 'static>,
pub source_map: *const SourceMap,
}
unsafe impl Send for ParsedFile {}
unsafe impl Sync for ParsedFile {}
impl<'a> BatchFileAnalyzer<'a> {
pub fn new(session: &'a AnalysisSession) -> Self {
Self { session }
}
pub fn analyze_batch(&self, files: Vec<ParsedFile>) -> Vec<(Arc<str>, FileAnalysis)> {
self.session.ensure_essential_stubs_loaded();
files.iter().for_each(|file| {
let program = unsafe { &*file.program };
self.session.ensure_stubs_for_ast(program);
});
let db = self.session.snapshot_db();
files
.into_par_iter()
.map_with(db, |db, file| {
let program = unsafe { &*file.program };
let source_map = unsafe { &*file.source_map };
let driver = Pass2Driver::new(db as &dyn MirDatabase, self.session.php_version());
let (issues, symbols) =
driver.analyze_bodies(program, file.file.clone(), &file.source, source_map);
let analysis = FileAnalysis { issues, symbols };
(file.file, analysis)
})
.collect()
}
}