mir_analyzer/
dead_code.rs1use mir_codebase::storage::Visibility;
13use mir_codebase::Codebase;
14use mir_issues::{Issue, IssueKind, Location, Severity};
15
16const MAGIC_METHODS: &[&str] = &[
18 "__construct",
19 "__destruct",
20 "__call",
21 "__callstatic",
22 "__get",
23 "__set",
24 "__isset",
25 "__unset",
26 "__sleep",
27 "__wakeup",
28 "__serialize",
29 "__unserialize",
30 "__tostring",
31 "__invoke",
32 "__set_state",
33 "__clone",
34 "__debuginfo",
35];
36
37pub struct DeadCodeAnalyzer<'a> {
38 codebase: &'a Codebase,
39}
40
41impl<'a> DeadCodeAnalyzer<'a> {
42 pub fn new(codebase: &'a Codebase) -> Self {
43 Self { codebase }
44 }
45
46 pub fn analyze(&self) -> Vec<Issue> {
47 let mut issues = Vec::new();
48
49 for entry in self.codebase.classes.iter() {
51 let cls = entry.value();
52 let fqcn = cls.fqcn.as_ref();
53
54 for (method_name, method) in &cls.own_methods {
55 if method.visibility != Visibility::Private {
56 continue;
57 }
58 let name = method_name.as_ref();
59 if MAGIC_METHODS.contains(&name) {
60 continue;
61 }
62 if !self.codebase.is_method_referenced(fqcn, name) {
63 let (file, line) = location_from_storage(&method.location);
64 issues.push(Issue::new(
65 IssueKind::UnusedMethod {
66 class: fqcn.to_string(),
67 method: name.to_string(),
68 },
69 Location {
70 file,
71 line,
72 line_end: line,
73 col_start: 0,
74 col_end: 0,
75 },
76 ));
77 }
78 }
79
80 for (prop_name, prop) in &cls.own_properties {
81 if prop.visibility != Visibility::Private {
82 continue;
83 }
84 let name = prop_name.as_ref();
85 if !self.codebase.is_property_referenced(fqcn, name) {
86 let (file, line) = location_from_storage(&prop.location);
87 issues.push(Issue::new(
88 IssueKind::UnusedProperty {
89 class: fqcn.to_string(),
90 property: name.to_string(),
91 },
92 Location {
93 file,
94 line,
95 line_end: line,
96 col_start: 0,
97 col_end: 0,
98 },
99 ));
100 }
101 }
102 }
103
104 for issue in &mut issues {
106 issue.severity = Severity::Info;
107 }
108
109 issues
110 }
111}
112
113fn location_from_storage(
114 loc: &Option<mir_codebase::storage::Location>,
115) -> (std::sync::Arc<str>, u32) {
116 match loc {
117 Some(l) => (l.file.clone(), 1), None => (std::sync::Arc::from("<unknown>"), 1),
119 }
120}