gather_all_code_from_crates/
parse_impl_block_item.rs1crate::ix!();
2
3pub fn parse_impl_block_item(imp: ast::Impl, remove_doc_comments: bool) -> ItemInfo {
4 let (attributes, _is_test) = extract_attributes(imp.attrs());
5 let is_public = false;
6
7 let mut signature_parts = Vec::new();
9 signature_parts.push("impl".to_string());
10
11 if let Some(generics) = imp.generic_param_list() {
12 signature_parts.push(generics.syntax().text().to_string());
13 }
14
15 if let Some(tr) = imp.trait_() {
16 signature_parts.push(tr.syntax().text().to_string());
17 signature_parts.push("for".to_string());
18 }
19
20 let self_ty_str = imp.self_ty().map(|t| t.syntax().text().to_string());
21 if let Some(ref s) = self_ty_str {
22 signature_parts.push(s.clone());
23 }
24
25 if let Some(where_clause) = imp.where_clause() {
26 signature_parts.push(where_clause.syntax().text().to_string());
27 }
28
29 let clean_signature = signature_parts.join(" ");
30
31 let mut methods = Vec::new();
32 if let Some(list) = imp.assoc_item_list() {
33 for item in list.assoc_items() {
34 if let Some(m_fn) = ast::Fn::cast(item.syntax().clone()) {
35 let (m_attrs, m_is_test) = extract_attributes(m_fn.attrs());
36 let m_is_public = m_fn.visibility().map_or(false, |v|
37 v.syntax().children_with_tokens().any(|child| child.kind() == ra_ap_syntax::SyntaxKind::PUB_KW)
38 );
39
40 let m_name = m_fn.name().map(|n| n.text().to_string()).unwrap_or_default();
41 let m_signature = extract_signature(&m_fn, remove_doc_comments);
43 let m_body = m_fn.body().map(|b| b.syntax().text().to_string());
44
45 let fi = FunctionInfoBuilder::default()
46 .name(m_name)
47 .is_public(m_is_public)
48 .is_test(m_is_test)
49 .attributes(m_attrs)
50 .signature(m_signature)
51 .body(m_body)
52 .build()
53 .expect("expected to build FunctionInfo");
54
55 methods.push(fi);
56 }
57 }
58 }
59
60 ItemInfo::ImplBlock {
61 name: self_ty_str,
62 attributes,
63 is_public,
64 signature: clean_signature,
65 methods,
66 }
67}
68
69
70#[cfg(test)]
71mod parse_impl_block_item_tests {
72 use super::*;
73
74 #[test]
75 fn test_parse_impl_block_item() {
76 let code = r#"
77#[some_attr]
78impl MyStruct {
79 #[inline]
80 fn method(&self) {}
81}
82"#;
83 let syntax = parse_source(code);
84 let imp = syntax.descendants().find_map(ast::Impl::cast).unwrap();
85 let item = parse_impl_block_item(imp, false);
86 if let ItemInfo::ImplBlock { name, attributes, is_public, signature, methods } = item {
87 assert!(name.as_ref().unwrap() == "MyStruct");
88 assert!(!is_public);
89 assert!(attributes.iter().any(|a| a.contains("#[some_attr]")));
90 assert!(signature.contains("impl MyStruct {"));
91 assert_eq!(methods.len(), 1);
92 let method = &methods[0];
93 println!("method: {:#?}", method);
94 assert!(method.attributes().iter().any(|a| a.contains("#[inline]")));
95 assert!(method.signature().contains("fn method(&self) {}"));
96 } else {
97 panic!("Expected an impl block item");
98 }
99 }
100
101 #[test]
102 fn test_parse_impl_block_item_basic() {
103 let code = r#"
104#[some_attr]
105impl MyStruct {
106 #[inline]
107 fn method(&self) {}
108}
109"#;
110 let syntax = parse_source(code);
111 let imp = syntax.descendants().find_map(ast::Impl::cast).unwrap();
112 let item = parse_impl_block_item(imp, false);
113
114 if let ItemInfo::ImplBlock { name, attributes, is_public, signature, methods } = item {
115 assert_eq!(name.as_ref().unwrap(), "MyStruct");
116 assert!(!is_public);
117 assert!(attributes.iter().any(|a| a.contains("#[some_attr]")));
118 assert!(signature.contains("impl MyStruct {"));
119 assert_eq!(methods.len(), 1);
120
121 let method = &methods[0];
122 println!("method: {:#?}", method);
123 assert!(method.attributes().iter().any(|a| a.contains("#[inline]")));
124 assert!(method.signature().contains("fn method(&self) {}"));
125 assert_eq!(method.name(), "method");
126 assert!(!method.is_public());
127 assert!(!method.is_test());
128 } else {
129 panic!("Expected an impl block item");
130 }
131 }
132
133 #[test]
134 fn test_parse_impl_block_item_multiple_methods() {
135 let code = r#"
136impl Foo {
137 fn one() {}
138 pub fn two() {}
139 #[test]
140 fn three() {}
141}
142"#;
143 let syntax = parse_source(code);
144 let imp = syntax.descendants().find_map(ast::Impl::cast).unwrap();
145 let item = parse_impl_block_item(imp, false);
146
147 if let ItemInfo::ImplBlock { name, attributes, is_public, signature, methods } = item {
148 assert_eq!(name.as_ref().unwrap(), "Foo");
149 assert!(!is_public);
150 assert!(attributes.is_empty());
151 assert!(signature.contains("impl Foo {"));
152 assert_eq!(methods.len(), 3);
153
154 let one = methods.iter().find(|m| m.name() == "one").unwrap();
155 println!("one: {:#?}", one);
156 assert!(!one.is_public());
157 assert!(!one.is_test());
158
159 let two = methods.iter().find(|m| m.name() == "two").unwrap();
160 println!("two: {:#?}", two);
161 assert!(two.is_public());
162 assert!(!two.is_test());
163
164 let three = methods.iter().find(|m| m.name() == "three").unwrap();
165 println!("three: {:#?}", three);
166 assert!(!three.is_public());
167 assert!(three.is_test());
168 } else {
169 panic!("Expected an impl block item");
170 }
171 }
172
173 #[test]
174 fn test_parse_impl_block_item_no_methods() {
175 let code = r#"
176#[doc = "Some docs"]
177impl Empty {}
178"#;
179 let syntax = parse_source(code);
180 let imp = syntax.descendants().find_map(ast::Impl::cast).unwrap();
181 let item = parse_impl_block_item(imp, false);
182
183 if let ItemInfo::ImplBlock { name, attributes, is_public, signature, methods } = item {
184 assert_eq!(name.as_ref().unwrap(), "Empty");
185 assert!(attributes.iter().any(|a| a.contains("#[doc = \"Some docs\"]")));
187 assert!(!is_public);
188 assert!(signature.contains("impl Empty {"));
189 assert!(methods.is_empty());
191 } else {
192 panic!("Expected an impl block item");
193 }
194 }
195
196 #[test]
197 fn test_parse_impl_block_item_remove_doc_comments() {
198 let code = r#"
199/// Doc comment
200impl WithDocs {
201 /// doc on method
202 fn documented(&self) {}
203}
204"#;
205 let syntax = parse_source(code);
206 let imp = syntax.descendants().find_map(ast::Impl::cast).unwrap();
207
208 let item = parse_impl_block_item(imp.clone(), true);
210 if let ItemInfo::ImplBlock { signature, methods, .. } = item {
211 println!("signature: {:#?}", signature);
212 println!("methods: {:#?}", methods);
213 assert!(!signature.contains("/// Doc comment"));
215 let method = &methods[0];
216 assert!(!method.signature().contains("/// doc on method"));
217 } else {
218 panic!("Expected an impl block item");
219 }
220
221 let item = parse_impl_block_item(imp.clone(), false);
223 if let ItemInfo::ImplBlock { signature, methods, .. } = item {
224 assert!(signature.contains("/// Doc comment"));
225 let method = &methods[0];
226 assert!(method.signature().contains("/// doc on method"));
227 } else {
228 panic!("Expected an impl block item");
229 }
230 }
231
232 #[test]
233 fn test_parse_impl_block_item_trait_impl() {
234 let code = r#"
235impl SomeTrait for MyStruct {
236 fn trait_method(&self) {}
237}
238"#;
239 let syntax = parse_source(code);
240 let imp = syntax.descendants().find_map(ast::Impl::cast).unwrap();
241 let item = parse_impl_block_item(imp.clone(), false);
242
243 if let ItemInfo::ImplBlock { name, attributes, is_public, signature, methods } = item {
244 assert_eq!(name.as_ref().unwrap(), "MyStruct");
248 assert!(attributes.is_empty());
249 assert!(!is_public);
250 println!("signature: {:#?}", signature);
251 assert!(signature.contains("impl SomeTrait for MyStruct {"));
252 assert_eq!(methods.len(), 1);
253
254 let tm = &methods[0];
255 assert_eq!(tm.name(), "trait_method");
256 } else {
257 panic!("Expected an impl block item");
258 }
259 }
260}