php_lsp/db/
method_returns.rs1use std::sync::Arc;
11
12use salsa::{Database, Update};
13
14use crate::ast::MethodReturnsMap;
15use crate::db::input::SourceFile;
16use crate::db::parse::parsed_doc;
17use crate::type_map::build_method_returns;
18
19#[derive(Clone)]
20pub struct MethodReturnsArc(pub Arc<MethodReturnsMap>);
21
22impl MethodReturnsArc {
23 pub fn get(&self) -> &MethodReturnsMap {
24 &self.0
25 }
26}
27
28unsafe impl Update for MethodReturnsArc {
30 unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
31 let old_ref = unsafe { &mut *old_pointer };
32 if Arc::ptr_eq(&old_ref.0, &new_value.0) {
33 false
34 } else {
35 *old_ref = new_value;
36 true
37 }
38 }
39}
40
41#[salsa::tracked(no_eq)]
42pub fn method_returns(db: &dyn Database, file: SourceFile) -> MethodReturnsArc {
43 let doc = parsed_doc(db, file);
44 MethodReturnsArc(Arc::new(build_method_returns(doc.get())))
45}
46
47#[cfg(test)]
48mod tests {
49 use std::sync::Arc;
50
51 use super::*;
52 use crate::db::analysis::AnalysisHost;
53 use crate::db::input::{FileId, SourceFile};
54 use salsa::Setter;
55
56 #[test]
57 fn method_returns_captures_factory_return() {
58 let host = AnalysisHost::new();
59 let file = SourceFile::new(
60 host.db(),
61 FileId(0),
62 Arc::<str>::from("file:///t.php"),
63 Arc::<str>::from(
64 "<?php\nclass Foo {\n public function make(): Bar { return new Bar(); }\n}\nclass Bar {}",
65 ),
66 None,
67 );
68 let m = method_returns(host.db(), file);
69 let foo = m.get().get("Foo").expect("class Foo in map");
70 assert_eq!(foo.get("make").map(String::as_str), Some("Bar"));
71 }
72
73 #[test]
74 fn method_returns_reruns_after_edit() {
75 let mut host = AnalysisHost::new();
76 let file = SourceFile::new(
77 host.db(),
78 FileId(1),
79 Arc::<str>::from("file:///t.php"),
80 Arc::<str>::from(
81 "<?php\nclass F {\n public function m(): A { return new A(); }\n}\nclass A {}\nclass B {}",
82 ),
83 None,
84 );
85 let a1 = method_returns(host.db(), file);
86 let first = Arc::as_ptr(&a1.0);
87
88 file.set_text(host.db_mut()).to(Arc::<str>::from(
89 "<?php\nclass F {\n public function m(): B { return new B(); }\n}\nclass A {}\nclass B {}",
90 ));
91 let a2 = method_returns(host.db(), file);
92 assert_ne!(
93 first,
94 Arc::as_ptr(&a2.0),
95 "editing the source should produce a new map"
96 );
97 assert_eq!(
98 a2.get()
99 .get("F")
100 .and_then(|m| m.get("m"))
101 .map(String::as_str),
102 Some("B")
103 );
104 }
105}