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 col_start: 0,
73 col_end: 0,
74 },
75 ));
76 }
77 }
78
79 for (prop_name, prop) in &cls.own_properties {
80 if prop.visibility != Visibility::Private {
81 continue;
82 }
83 let name = prop_name.as_ref();
84 if !self.codebase.is_property_referenced(fqcn, name) {
85 let (file, line) = location_from_storage(&prop.location);
86 issues.push(Issue::new(
87 IssueKind::UnusedProperty {
88 class: fqcn.to_string(),
89 property: name.to_string(),
90 },
91 Location {
92 file,
93 line,
94 col_start: 0,
95 col_end: 0,
96 },
97 ));
98 }
99 }
100 }
101
102 for issue in &mut issues {
104 issue.severity = Severity::Info;
105 }
106
107 issues
108 }
109}
110
111fn location_from_storage(
112 loc: &Option<mir_codebase::storage::Location>,
113) -> (std::sync::Arc<str>, u32) {
114 match loc {
115 Some(l) => (l.file.clone(), 1), None => (std::sync::Arc::from("<unknown>"), 1),
117 }
118}