diff options
Diffstat (limited to 'src/parser')
-rw-r--r-- | src/parser/clang/entities.rs | 1477 | ||||
-rw-r--r-- | src/parser/clang/parsing.rs | 636 |
2 files changed, 1135 insertions, 978 deletions
diff --git a/src/parser/clang/entities.rs b/src/parser/clang/entities.rs index 0e9305b..b1689aa 100644 --- a/src/parser/clang/entities.rs +++ b/src/parser/clang/entities.rs | |||
@@ -1,541 +1,1276 @@ | |||
1 | use crate::types::{self, *}; | 1 | use crate::types; |
2 | 2 | ||
3 | use clang::{EntityKind, Usr}; | 3 | use anyhow::{anyhow, Error, Result}; |
4 | use serde_json::{Map, Value as JSONValue}; | 4 | use clang::Usr; |
5 | use serde_json::{json, Map as JSONMap, Value as JSONValue}; | ||
5 | use thiserror::Error; | 6 | use thiserror::Error; |
6 | 7 | ||
7 | use std::collections::BTreeMap; | 8 | use std::collections::BTreeMap; |
8 | use std::convert::TryFrom; | 9 | use std::convert::{TryFrom, TryInto}; |
9 | |||
10 | // TODO: factor out hardcoded strings | ||
11 | 10 | ||
12 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 11 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
13 | pub(super) enum ClangEntityKind { | 12 | pub(super) enum EntityKind { |
14 | Namespace, | 13 | Namespace, |
15 | Variable(VariableKind), | ||
16 | Struct(StructKind), | ||
17 | Function(FunctionKind), | ||
18 | Typedef, | ||
19 | Enum, | ||
20 | EnumConstant, | ||
21 | } | ||
22 | |||
23 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
24 | pub(super) enum VariableKind { | ||
25 | Variable, | 14 | Variable, |
26 | Field, | ||
27 | } | ||
28 | |||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
30 | pub(super) enum StructKind { | ||
31 | Struct, | 15 | Struct, |
32 | Class, | ||
33 | } | ||
34 | |||
35 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
36 | pub(super) enum FunctionKind { | ||
37 | Function, | 16 | Function, |
38 | Method, | 17 | Enum, |
39 | } | 18 | EnumConstant, |
40 | 19 | TypeAlias, | |
41 | impl ClangEntityKind { | ||
42 | fn to_str_singular(self) -> &'static str { | ||
43 | match self { | ||
44 | ClangEntityKind::Namespace => "namespace", | ||
45 | ClangEntityKind::Variable(VariableKind::Variable) => "variable", | ||
46 | ClangEntityKind::Variable(VariableKind::Field) => "field", | ||
47 | ClangEntityKind::Struct(StructKind::Struct) => "struct", | ||
48 | ClangEntityKind::Struct(StructKind::Class) => "class", | ||
49 | ClangEntityKind::Function(FunctionKind::Function) => "function", | ||
50 | ClangEntityKind::Function(FunctionKind::Method) => "method", | ||
51 | ClangEntityKind::Typedef => "typedef", | ||
52 | ClangEntityKind::Enum => "enum", | ||
53 | ClangEntityKind::EnumConstant => "enum-constant", | ||
54 | } | ||
55 | } | ||
56 | |||
57 | fn to_str_plural(self) -> &'static str { | ||
58 | match self { | ||
59 | ClangEntityKind::Namespace => "namespaces", | ||
60 | ClangEntityKind::Variable(VariableKind::Variable) => "variables", | ||
61 | ClangEntityKind::Variable(VariableKind::Field) => "fields", | ||
62 | ClangEntityKind::Struct(StructKind::Struct) => "structs", | ||
63 | ClangEntityKind::Struct(StructKind::Class) => "classes", | ||
64 | ClangEntityKind::Function(FunctionKind::Function) => "functions", | ||
65 | ClangEntityKind::Function(FunctionKind::Method) => "methods", | ||
66 | ClangEntityKind::Typedef => "typedefs", | ||
67 | ClangEntityKind::Enum => "enums", | ||
68 | ClangEntityKind::EnumConstant => "enum-constants", | ||
69 | } | ||
70 | } | ||
71 | } | 20 | } |
72 | 21 | ||
73 | #[derive(Debug, Error)] | 22 | #[derive(Debug, Error, PartialEq, Eq)] |
74 | #[error("Unsupported Clang entity kind: {:?}", _0)] | 23 | #[error("Unsupported Clang entity kind: {:?}", _0)] |
75 | pub(super) struct TryFromEntityKindError(String); | 24 | pub(super) struct TryFromEntityKindError(String); |
76 | 25 | ||
77 | impl TryFrom<EntityKind> for ClangEntityKind { | 26 | impl TryFrom<clang::EntityKind> for EntityKind { |
78 | type Error = TryFromEntityKindError; | 27 | type Error = TryFromEntityKindError; |
79 | 28 | ||
80 | fn try_from(kind: EntityKind) -> Result<ClangEntityKind, TryFromEntityKindError> { | 29 | fn try_from(kind: clang::EntityKind) -> Result<EntityKind, TryFromEntityKindError> { |
81 | Ok(match kind { | 30 | Ok(match kind { |
82 | EntityKind::Namespace => ClangEntityKind::Namespace, | 31 | clang::EntityKind::Namespace | clang::EntityKind::TranslationUnit => { |
83 | EntityKind::VarDecl => ClangEntityKind::Variable(VariableKind::Variable), | 32 | EntityKind::Namespace |
84 | EntityKind::FieldDecl => ClangEntityKind::Variable(VariableKind::Field), | ||
85 | EntityKind::FunctionDecl | EntityKind::FunctionTemplate => { | ||
86 | ClangEntityKind::Function(FunctionKind::Function) | ||
87 | } | ||
88 | EntityKind::Method | EntityKind::Constructor | EntityKind::Destructor => { | ||
89 | ClangEntityKind::Function(FunctionKind::Method) | ||
90 | } | 33 | } |
91 | EntityKind::StructDecl => ClangEntityKind::Struct(StructKind::Struct), | 34 | clang::EntityKind::VarDecl | clang::EntityKind::FieldDecl => EntityKind::Variable, |
92 | EntityKind::ClassDecl | EntityKind::ClassTemplate => { | 35 | clang::EntityKind::StructDecl |
93 | ClangEntityKind::Struct(StructKind::Class) | 36 | | clang::EntityKind::ClassDecl |
94 | } | 37 | | clang::EntityKind::ClassTemplate => EntityKind::Struct, |
95 | EntityKind::TypedefDecl | 38 | clang::EntityKind::FunctionDecl |
96 | | EntityKind::TypeAliasDecl | 39 | | clang::EntityKind::FunctionTemplate |
97 | | EntityKind::TypeAliasTemplateDecl => ClangEntityKind::Typedef, | 40 | | clang::EntityKind::Method |
98 | EntityKind::EnumDecl => ClangEntityKind::Enum, | 41 | | clang::EntityKind::Constructor |
99 | EntityKind::EnumConstantDecl => ClangEntityKind::EnumConstant, | 42 | | clang::EntityKind::Destructor => EntityKind::Function, |
43 | clang::EntityKind::TypedefDecl | ||
44 | | clang::EntityKind::TypeAliasDecl | ||
45 | | clang::EntityKind::TypeAliasTemplateDecl => EntityKind::TypeAlias, | ||
46 | clang::EntityKind::EnumDecl => EntityKind::Enum, | ||
47 | clang::EntityKind::EnumConstantDecl => EntityKind::EnumConstant, | ||
100 | kind => return Err(TryFromEntityKindError(format!("{:?}", kind))), | 48 | kind => return Err(TryFromEntityKindError(format!("{:?}", kind))), |
101 | }) | 49 | }) |
102 | } | 50 | } |
103 | } | 51 | } |
104 | 52 | ||
105 | #[derive(Debug)] | 53 | #[derive(Debug, Clone, PartialEq, Eq)] |
106 | pub(super) struct PartialEntity { | 54 | pub(super) struct Description { |
107 | properties: Map<String, JSONValue>, | 55 | name: String, |
108 | children: Children, | 56 | brief: String, |
57 | detailed: String, | ||
109 | } | 58 | } |
110 | 59 | ||
111 | pub(super) trait ClangEntity { | 60 | impl<'a> TryFrom<clang::Entity<'a>> for Description { |
112 | fn kind(&self) -> ClangEntityKind; | 61 | type Error = Error; |
113 | 62 | ||
114 | fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> { | 63 | fn try_from(entity: clang::Entity) -> Result<Self> { |
115 | None | 64 | let name = entity |
65 | .get_display_name() | ||
66 | .ok_or_else(|| anyhow!("Entity has no name: {:?}", entity))?; | ||
67 | |||
68 | // TODO: is that the best? | ||
69 | if let (Some(brief), Some(comment)) = (entity.get_comment_brief(), entity.get_comment()) { | ||
70 | Ok(Description { | ||
71 | name, | ||
72 | brief, | ||
73 | detailed: super::parsing::parse_comment(comment), | ||
74 | }) | ||
75 | } else { | ||
76 | Ok(Description { | ||
77 | name, | ||
78 | brief: String::new(), | ||
79 | detailed: String::new(), | ||
80 | }) | ||
81 | } | ||
116 | } | 82 | } |
117 | fn get_member_variables(&mut self) -> Option<&mut BTreeMap<Usr, Described<Variable>>> { | 83 | } |
118 | None | 84 | |
85 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
86 | pub(super) struct Described<T> { | ||
87 | pub description: Description, | ||
88 | pub entity: T, | ||
89 | } | ||
90 | |||
91 | type DescribedDynEntity = Described<DynEntity>; | ||
92 | |||
93 | impl<T: Entity> Described<T> { | ||
94 | /* | ||
95 | fn into_dyn(self) -> Described<DynEntity> { | ||
96 | Described { | ||
97 | description: self.description, | ||
98 | entity: self.entity.into_dyn(), | ||
99 | } | ||
119 | } | 100 | } |
120 | fn get_member_structs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Struct>>> { | 101 | */ |
121 | None | 102 | |
103 | fn to_dyn(&self) -> DescribedRef<DynEntityRef> { | ||
104 | DescribedRef { | ||
105 | description: &self.description, | ||
106 | entity: self.entity.to_dyn(), | ||
107 | } | ||
122 | } | 108 | } |
123 | fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { | 109 | |
124 | None | 110 | #[allow(clippy::wrong_self_convention)] |
111 | fn to_dyn_mut(&mut self) -> DescribedRefMut<DynEntityRefMut> { | ||
112 | DescribedRefMut { | ||
113 | description: &mut self.description, | ||
114 | entity: self.entity.to_dyn_mut(), | ||
115 | } | ||
125 | } | 116 | } |
126 | fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> { | 117 | } |
127 | None | 118 | |
119 | impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T> | ||
120 | where | ||
121 | T: TryFrom<clang::Entity<'a>, Error = Error>, | ||
122 | { | ||
123 | type Error = Error; | ||
124 | |||
125 | fn try_from(entity: clang::Entity<'a>) -> Result<Self, Error> { | ||
126 | Ok(Described::<T> { | ||
127 | description: entity.try_into()?, | ||
128 | entity: T::try_from(entity)?, | ||
129 | }) | ||
128 | } | 130 | } |
129 | fn get_member_enums(&mut self) -> Option<&mut BTreeMap<Usr, Described<Enum>>> { | 131 | } |
130 | None | 132 | |
133 | impl<T: Entity + Into<PartialEntity>> From<Described<T>> for types::Entity { | ||
134 | fn from(entity: Described<T>) -> Self { | ||
135 | let kind = types::EntityKind(entity.entity.kind_name_singular().to_owned()); | ||
136 | let partial_entity: PartialEntity = entity.entity.into(); | ||
137 | |||
138 | types::Entity { | ||
139 | name: entity.description.name, | ||
140 | language: types::Language::Clang, | ||
141 | kind, | ||
142 | brief_description: entity.description.brief, | ||
143 | documentation: entity.description.detailed, | ||
144 | properties: partial_entity.properties, | ||
145 | children: partial_entity.children, | ||
146 | } | ||
131 | } | 147 | } |
132 | } | 148 | } |
133 | 149 | ||
150 | #[derive(Debug, Clone)] | ||
151 | pub(super) struct DescribedRef<'a, T> { | ||
152 | pub description: &'a Description, | ||
153 | pub entity: T, | ||
154 | } | ||
155 | |||
156 | type DescribedDynEntityRef<'d, 'e> = DescribedRef<'d, DynEntityRef<'e>>; | ||
157 | |||
134 | /* | 158 | /* |
135 | pub(super) trait FromNamespaceParent: ClangEntity + Sized { | 159 | impl<'d, 'e, T: Entity> DescribedRef<'d, &'e T> { |
136 | fn from_namespace_parent<'a>( | 160 | fn from_dyn_ref(dyn_entity: DescribedDynEntityRef<'d, 'e>) -> Option<Self> { |
137 | parent: &'a mut Described<Namespace>, | 161 | Some(DescribedRef { |
138 | name: &Usr, | 162 | description: dyn_entity.description, |
139 | ) -> Option<&'a mut Described<Self>>; | 163 | entity: Entity::from_dyn_ref(dyn_entity.entity)?, |
164 | }) | ||
165 | } | ||
140 | } | 166 | } |
141 | */ | 167 | */ |
142 | 168 | ||
143 | pub(super) trait NamespaceParentManipulation<T: ClangEntity + Sized> { | 169 | #[derive(Debug, Clone)] |
144 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<T>>>; | 170 | pub(super) struct DescribedRefMut<'a, T> { |
171 | pub description: &'a Description, | ||
172 | pub entity: T, | ||
145 | } | 173 | } |
146 | 174 | ||
147 | impl<U> NamespaceParentManipulation<Namespace> for U | 175 | type DescribedDynEntityRefMut<'a, 'b> = DescribedRefMut<'a, DynEntityRefMut<'b>>; |
148 | where | 176 | |
149 | U: ClangEntity, | 177 | impl<'d, 'e, T: Entity> DescribedRefMut<'d, &'e mut T> { |
150 | { | 178 | fn from_dyn_mut(dyn_entity: DescribedDynEntityRefMut<'d, 'e>) -> Option<Self> { |
151 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> { | 179 | Some(DescribedRefMut { |
152 | self.get_member_namespaces() | 180 | description: dyn_entity.description, |
181 | entity: Entity::from_dyn_mut(dyn_entity.entity)?, | ||
182 | }) | ||
153 | } | 183 | } |
154 | } | 184 | } |
155 | 185 | ||
156 | impl<U> NamespaceParentManipulation<Variable> for U | 186 | pub(super) trait Entity: Traversable + KindName { |
157 | where | 187 | const KIND: EntityKind; |
158 | U: ClangEntity, | 188 | |
159 | { | 189 | /* |
160 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Variable>>> { | 190 | /// Transform a generic entity to a specific entity |
161 | self.get_member_variables() | 191 | fn try_into_specific<T: Entity>(self) -> Option<T> |
192 | where | ||
193 | Self: Sized, | ||
194 | { | ||
195 | T::from_dyn(self.into_dyn()) | ||
162 | } | 196 | } |
163 | } | ||
164 | 197 | ||
165 | impl<U> NamespaceParentManipulation<Function> for U | 198 | /// Transform a generic entity to a specific entity |
166 | where | 199 | /// |
167 | U: ClangEntity, | 200 | /// Panics if not the right entity kind |
168 | { | 201 | fn into_specific<T: Entity>(self) -> T |
169 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { | 202 | where |
170 | self.get_member_functions() | 203 | Self: Sized, |
204 | { | ||
205 | self.try_into_specific().unwrap() | ||
171 | } | 206 | } |
207 | */ | ||
208 | |||
209 | fn from_dyn(dyn_entity: DynEntity) -> Option<Self> | ||
210 | where | ||
211 | Self: Sized; | ||
212 | fn from_dyn_ref(dyn_entity: DynEntityRef) -> Option<&Self>; | ||
213 | fn from_dyn_mut(dyn_entity: DynEntityRefMut) -> Option<&mut Self>; | ||
214 | fn into_dyn(self) -> DynEntity; | ||
215 | fn to_dyn(&self) -> DynEntityRef; | ||
216 | fn to_dyn_mut(&mut self) -> DynEntityRefMut; | ||
172 | } | 217 | } |
173 | 218 | ||
174 | impl<U> NamespaceParentManipulation<Struct> for U | 219 | pub(super) trait Traversable { |
175 | where | 220 | fn has_child_from_kind(&self, usr: &Usr, kind: EntityKind) -> bool; |
176 | U: ClangEntity, | 221 | fn get_child_from_kind(&self, usr: &Usr, kind: EntityKind) -> Option<DescribedDynEntityRef>; |
177 | { | 222 | fn get_mut_child_from_kind( |
178 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Struct>>> { | 223 | &mut self, |
179 | self.get_member_structs() | 224 | usr: &Usr, |
180 | } | 225 | kind: EntityKind, |
226 | ) -> Option<DescribedDynEntityRefMut>; | ||
227 | fn insert(&mut self, usr: Usr, child: DescribedDynEntity) -> Result<()>; | ||
181 | } | 228 | } |
182 | 229 | ||
183 | impl<U> NamespaceParentManipulation<Typedef> for U | 230 | pub(super) trait KindName { |
184 | where | 231 | fn kind_name_singular(&self) -> &'static str; |
185 | U: ClangEntity, | 232 | fn kind_name_plural(&self) -> &'static str; |
186 | { | ||
187 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> { | ||
188 | self.get_member_typedefs() | ||
189 | } | ||
190 | } | 233 | } |
191 | 234 | ||
192 | impl<U> NamespaceParentManipulation<Enum> for U | 235 | #[derive(Debug)] |
193 | where | 236 | pub(super) struct PartialEntity { |
194 | U: ClangEntity, | 237 | properties: JSONMap<String, JSONValue>, |
195 | { | 238 | children: types::Children, |
196 | fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Enum>>> { | ||
197 | self.get_member_enums() | ||
198 | } | ||
199 | } | 239 | } |
200 | 240 | ||
201 | fn entity_id(usr: Usr) -> EntityId { | 241 | fn entity_id(usr: Usr) -> types::EntityId { |
242 | fn is_identifier_char(c: char) -> bool { | ||
243 | c.is_ascii() || c == '-' || c == '_' || c == ':' || c == '.' | ||
244 | } | ||
202 | // This is a somewhat ugly workaround, because Pandoc parses markdown identifiers as alphanum | 245 | // This is a somewhat ugly workaround, because Pandoc parses markdown identifiers as alphanum |
203 | // or one of "-_:.", which means Pandoc can't parse libclang's USRs in title ids and related. | 246 | // or one of "-_:.", which means Pandoc can't parse libclang's USRs in title ids and related. |
204 | // | 247 | // |
205 | // <https://github.com/jgm/pandoc/blob/2.9/src/Text/Pandoc/Readers/Markdown.hs#L581> | 248 | // <https://github.com/jgm/pandoc/blob/2.9/src/Text/Pandoc/Readers/Markdown.hs#L581> |
206 | EntityId(usr.0.replace("@", "::").replace("#", ".").replace("$", "-")) | 249 | types::EntityId( |
250 | usr.0 | ||
251 | .replace("@", "::") | ||
252 | .replace("#", ".") | ||
253 | .replace("$", "-") | ||
254 | .replace(|c| !is_identifier_char(c), ""), | ||
255 | ) | ||
207 | } | 256 | } |
208 | 257 | ||
209 | fn append_children<T: ClangEntity + Into<PartialEntity>>( | 258 | macro_rules! entity { |
210 | acc: &mut types::Children, | 259 | ( |
211 | to_insert: BTreeMap<Usr, Described<T>>, | 260 | $(#[$meta: meta])* |
212 | ) { | 261 | $struct_vis: vis struct $name: ident { |
213 | for (usr, child) in to_insert { | 262 | $($( |
214 | acc.entry(ChildrenKind(String::from( | 263 | $(#[$field_meta: meta])* |
215 | child.entity.kind().to_str_plural(), | 264 | $field_vis: vis $field: ident : $type: ty, |
216 | ))) | 265 | )+)? |
217 | .or_default() | 266 | $(#children => [ |
218 | .insert(entity_id(usr), child.into()); | 267 | $($child_name: ident: $child_type: ident),* $(,)? |
219 | } | 268 | ],)? |
220 | } | 269 | $(#properties($properties_var: ident) => $properties: expr,)? |
270 | } | ||
271 | ) => { | ||
272 | |||
273 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
274 | $(#[$meta])* | ||
275 | $struct_vis struct $name { | ||
276 | $($( | ||
277 | $(#[$field_meta])* | ||
278 | $field_vis $field: $type, | ||
279 | )+)? | ||
280 | $($($child_name: BTreeMap<Usr, Described<$child_type>>),*)? | ||
281 | } | ||
221 | 282 | ||
222 | impl<T: ClangEntity + Into<PartialEntity>> From<Described<T>> for Entity { | 283 | impl Entity for $name { |
223 | fn from(entity: Described<T>) -> Self { | 284 | const KIND: EntityKind = EntityKind::$name; |
224 | let kind = EntityKind(String::from(entity.entity.kind().to_str_singular())); | ||
225 | let partial_entity: PartialEntity = entity.entity.into(); | ||
226 | 285 | ||
227 | Entity { | 286 | fn from_dyn(dyn_entity: DynEntity) -> Option<Self> { |
228 | name: entity.description.name, | 287 | match dyn_entity { |
229 | language: Language::Clang, | 288 | DynEntity::$name(me) => Some(me), |
230 | kind, | 289 | _ => None, |
231 | brief_description: entity.description.brief, | 290 | } |
232 | documentation: entity.description.detailed, | 291 | } |
233 | properties: partial_entity.properties, | 292 | |
234 | children: partial_entity.children, | 293 | fn from_dyn_ref(dyn_entity: DynEntityRef) -> Option<&Self> { |
294 | match dyn_entity { | ||
295 | DynEntityRef::$name(me) => Some(me), | ||
296 | _ => None, | ||
297 | } | ||
298 | } | ||
299 | |||
300 | fn from_dyn_mut(dyn_entity: DynEntityRefMut) -> Option<&mut Self> { | ||
301 | match dyn_entity { | ||
302 | DynEntityRefMut::$name(me) => Some(me), | ||
303 | _ => None, | ||
304 | } | ||
305 | } | ||
306 | |||
307 | fn into_dyn(self) -> DynEntity { | ||
308 | DynEntity::$name(self) | ||
309 | } | ||
310 | |||
311 | fn to_dyn(&self) -> DynEntityRef { | ||
312 | DynEntityRef::$name(self) | ||
313 | } | ||
314 | |||
315 | fn to_dyn_mut(&mut self) -> DynEntityRefMut { | ||
316 | DynEntityRefMut::$name(self) | ||
317 | } | ||
318 | } | ||
319 | |||
320 | impl Traversable for $name { | ||
321 | #[allow(unused_variables, unreachable_patterns)] | ||
322 | fn has_child_from_kind(&self, usr: &Usr, kind: EntityKind) -> bool { | ||
323 | match kind { | ||
324 | $($( | ||
325 | EntityKind::$child_type => self.$child_name.contains_key(usr), | ||
326 | )*)? | ||
327 | _ => false, | ||
328 | } | ||
329 | } | ||
330 | |||
331 | #[allow(unused_variables, unreachable_patterns)] | ||
332 | fn get_child_from_kind( | ||
333 | &self, | ||
334 | usr: &Usr, | ||
335 | kind: EntityKind | ||
336 | ) -> Option<DescribedDynEntityRef> { | ||
337 | match kind { | ||
338 | $($( | ||
339 | EntityKind::$child_type => { | ||
340 | self.$child_name.get(usr).map(Described::to_dyn) | ||
341 | } | ||
342 | )*)? | ||
343 | _ => None, | ||
344 | } | ||
345 | } | ||
346 | |||
347 | #[allow(unused_variables, unreachable_patterns)] | ||
348 | fn get_mut_child_from_kind( | ||
349 | &mut self, | ||
350 | usr: &Usr, | ||
351 | kind: EntityKind | ||
352 | ) -> Option<DescribedDynEntityRefMut> { | ||
353 | match kind { | ||
354 | $($( | ||
355 | EntityKind::$child_type => { | ||
356 | self.$child_name.get_mut(usr).map(Described::to_dyn_mut) | ||
357 | } | ||
358 | )*)? | ||
359 | _ => None, | ||
360 | } | ||
361 | } | ||
362 | |||
363 | #[allow(unused_variables, unreachable_patterns)] | ||
364 | fn insert(&mut self, usr: Usr, child: DescribedDynEntity) -> Result<()> { | ||
365 | match child.entity { | ||
366 | $($( | ||
367 | DynEntity::$child_type(entity) => { | ||
368 | self.$child_name.insert( | ||
369 | usr, | ||
370 | Described { description: child.description, entity } | ||
371 | ); | ||
372 | Ok(()) | ||
373 | } | ||
374 | )*)? | ||
375 | // TODO: Properly define an error | ||
376 | other => Err(anyhow!("Impossible to insert {:?} into {:?}", other, Self::KIND)), | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | // TODO: explain why we do this (hygienic) | ||
382 | entity!{@partial_entity $name, $($properties_var,)? $($($child_name)*)?, $($properties)?} | ||
383 | |||
384 | }; | ||
385 | |||
386 | (@partial_entity $name: ident, $entity_var: ident, $($child_name: ident)*, $($properties: expr)?) => { | ||
387 | impl<'a> From<$name> for PartialEntity { | ||
388 | #[allow(unused_variables, unused_mut)] | ||
389 | fn from($entity_var: $name) -> Self { | ||
390 | let mut children = types::Children::default(); | ||
391 | $( | ||
392 | for (usr, child) in $entity_var.$child_name { | ||
393 | children.entry(types::ChildrenKind(String::from( | ||
394 | child.entity.kind_name_plural(), | ||
395 | ))) | ||
396 | .or_default() | ||
397 | .insert(entity_id(usr), child.into()); | ||
398 | } | ||
399 | )* | ||
400 | |||
401 | let properties = entity!(@properties $($properties)?); | ||
402 | |||
403 | Self { properties, children } | ||
404 | } | ||
405 | } | ||
406 | }; | ||
407 | |||
408 | (@partial_entity $name: ident, $($child_name: ident)*, $($properties: expr)?) => { | ||
409 | entity!{@partial_entity $name, entity, $($child_name)*, $($properties)?} | ||
410 | }; | ||
411 | |||
412 | (@properties $properties: expr) => {{ | ||
413 | match $properties { | ||
414 | JSONValue::Object(map) => map, | ||
415 | _ => panic!("Entity properties not given in JSON object form"), | ||
235 | } | 416 | } |
417 | }}; | ||
418 | |||
419 | (@properties) => { | ||
420 | Default::default() | ||
236 | } | 421 | } |
237 | } | 422 | } |
238 | 423 | ||
239 | #[derive(Debug, Clone, Default)] | 424 | #[derive(Debug, Clone, PartialEq, Eq)] |
240 | pub(super) struct Description { | 425 | pub(super) struct TopLevel(Described<Namespace>); |
241 | pub(super) name: String, | 426 | |
242 | pub(super) brief: String, | 427 | impl Default for TopLevel { |
243 | pub(super) detailed: String, | 428 | fn default() -> Self { |
429 | TopLevel(Described::<Namespace> { | ||
430 | description: Description { | ||
431 | name: String::new(), | ||
432 | brief: String::new(), | ||
433 | detailed: String::new(), | ||
434 | }, | ||
435 | entity: Namespace::new_global(), | ||
436 | }) | ||
437 | } | ||
244 | } | 438 | } |
245 | 439 | ||
246 | #[derive(Debug, Clone)] | 440 | impl From<TopLevel> for types::Entity { |
247 | pub(super) struct Described<T> { | 441 | fn from(toplevel: TopLevel) -> Self { |
248 | pub(super) description: Description, | 442 | toplevel.0.into() |
249 | pub(super) entity: T, | 443 | } |
250 | } | 444 | } |
251 | 445 | ||
252 | #[derive(Debug, Clone)] | 446 | // TODO: Probably remove NoParent in favor of the Error variant of Result |
253 | pub(super) struct Namespace { | 447 | #[derive(Debug)] |
254 | pub(super) member_namespaces: BTreeMap<Usr, Described<Namespace>>, | 448 | pub(super) enum EntityEntry<'d, 'e, T> { |
255 | pub(super) member_variables: BTreeMap<Usr, Described<Variable>>, | 449 | Vacant { |
256 | pub(super) member_structs: BTreeMap<Usr, Described<Struct>>, | 450 | parent: DescribedRefMut<'d, &'e mut Namespace>, |
257 | pub(super) member_functions: BTreeMap<Usr, Described<Function>>, | 451 | }, |
258 | pub(super) member_typedefs: BTreeMap<Usr, Described<Typedef>>, | 452 | Occupied { |
259 | pub(super) member_enums: BTreeMap<Usr, Described<Enum>>, | 453 | entity: DescribedRefMut<'d, T>, |
454 | }, | ||
455 | } | ||
456 | |||
457 | #[derive(Debug, Error, PartialEq, Eq)] | ||
458 | pub(super) enum TopLevelEntryError { | ||
459 | #[error("Entity has no parent")] | ||
460 | NoParent, | ||
461 | #[error("Entity has no USR")] | ||
462 | NoUsr, | ||
463 | #[error("Entity kind is not supported")] | ||
464 | UnknownKind, | ||
260 | } | 465 | } |
261 | 466 | ||
262 | impl ClangEntity for Namespace { | 467 | impl TopLevel { |
263 | fn kind(&self) -> ClangEntityKind { | 468 | /* |
264 | ClangEntityKind::Namespace | 469 | pub(super) fn get_dyn(&self, path: clang::Entity) -> Option<DescribedDynEntityRef> { |
470 | if path.get_kind() == clang::EntityKind::TranslationUnit { | ||
471 | return Some(self.0.to_dyn()); | ||
472 | } | ||
473 | let usr = path.get_usr()?; | ||
474 | let parent_path = path | ||
475 | .get_semantic_parent() | ||
476 | .expect("get_semantic_parent() returned None"); | ||
477 | |||
478 | let kind = path.get_kind().try_into().ok()?; | ||
479 | self.get_dyn(parent_path).and_then(|parent| { | ||
480 | parent | ||
481 | .entity | ||
482 | .map(|parent| parent.get_child_from_kind(&usr, kind)) | ||
483 | }) | ||
484 | } | ||
485 | */ | ||
486 | |||
487 | pub(super) fn get_dyn_mut(&mut self, path: clang::Entity) -> Option<DescribedDynEntityRefMut> { | ||
488 | if path.get_kind() == clang::EntityKind::TranslationUnit { | ||
489 | return Some(self.0.to_dyn_mut()); | ||
490 | } | ||
491 | let usr = path.get_usr()?; | ||
492 | let parent_path = path | ||
493 | .get_semantic_parent() | ||
494 | .expect("get_semantic_parent() returned None"); | ||
495 | |||
496 | let kind = path.get_kind().try_into().ok()?; | ||
497 | self.get_dyn_mut(parent_path).and_then(|parent| { | ||
498 | parent | ||
499 | .entity | ||
500 | .map(|parent| parent.get_mut_child_from_kind(&usr, kind)) | ||
501 | }) | ||
265 | } | 502 | } |
266 | 503 | ||
267 | fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> { | 504 | /* |
268 | Some(&mut self.member_namespaces) | 505 | pub(super) fn get<T>(&self, path: clang::Entity) -> Option<DescribedRef<&T>> |
506 | where | ||
507 | T: Entity, | ||
508 | { | ||
509 | assert_eq!(path.get_kind().try_into(), Ok(T::KIND),); | ||
510 | self.get_dyn(path).and_then(DescribedRef::from_dyn_ref) | ||
269 | } | 511 | } |
270 | fn get_member_variables(&mut self) -> Option<&mut BTreeMap<Usr, Described<Variable>>> { | 512 | |
271 | Some(&mut self.member_variables) | 513 | pub(super) fn get_mut<T>(&mut self, path: clang::Entity) -> Option<DescribedRefMut<&mut T>> |
514 | where | ||
515 | T: Entity, | ||
516 | { | ||
517 | assert_eq!(path.get_kind().try_into(), Ok(T::KIND),); | ||
518 | self.get_dyn_mut(path) | ||
519 | .and_then(DescribedRefMut::from_dyn_mut) | ||
272 | } | 520 | } |
273 | fn get_member_structs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Struct>>> { | 521 | |
274 | Some(&mut self.member_structs) | 522 | pub(super) fn insert_dyn( |
523 | &mut self, | ||
524 | path: clang::Entity, | ||
525 | entity: DescribedDynEntity, | ||
526 | ) -> Result<()> { | ||
527 | let usr = path.get_usr().ok_or_else(|| anyhow!("no usr"))?; | ||
528 | let parent_path = path | ||
529 | .get_semantic_parent() | ||
530 | .ok_or_else(|| anyhow!("Trying to insert the global namespace"))?; | ||
531 | |||
532 | self.get_dyn_mut(parent_path) | ||
533 | .map(|described_entity| described_entity.entity) | ||
534 | // TODO: Properly define an error | ||
535 | .ok_or_else(|| anyhow!("has parent: {:?} but no parent in tree", parent_path))? | ||
536 | .map(|parent| parent.insert(usr, entity)) | ||
275 | } | 537 | } |
276 | fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { | 538 | |
277 | Some(&mut self.member_functions) | 539 | pub(super) fn insert<T>(&mut self, path: clang::Entity, entity: Described<T>) -> Result<()> |
540 | where | ||
541 | T: Entity, | ||
542 | { | ||
543 | self.insert_dyn(path, entity.into_dyn()) | ||
278 | } | 544 | } |
279 | fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> { | 545 | */ |
280 | Some(&mut self.member_typedefs) | 546 | |
547 | // TODO: does not check whether a vacant entry is allowed to be in parent. | ||
548 | // For example, it can return a vacant EnumConstant inside a Struct. | ||
549 | pub(super) fn entry_dyn( | ||
550 | &mut self, | ||
551 | path: clang::Entity, | ||
552 | ) -> Result<EntityEntry<DynEntityRefMut>, TopLevelEntryError> { | ||
553 | let kind = path | ||
554 | .get_kind() | ||
555 | .try_into() | ||
556 | .map_err(|_err| TopLevelEntryError::UnknownKind)?; | ||
557 | let usr = path.get_usr().ok_or(TopLevelEntryError::NoUsr)?; | ||
558 | let parent_path = match path.get_semantic_parent() { | ||
559 | Some(parent) => parent, | ||
560 | // No parent? It must be the TranslationUnit / Global Namespace | ||
561 | None => { | ||
562 | return Ok(EntityEntry::Vacant { | ||
563 | parent: DescribedRefMut { | ||
564 | description: &mut self.0.description, | ||
565 | entity: &mut self.0.entity, | ||
566 | }, | ||
567 | }) | ||
568 | } | ||
569 | }; | ||
570 | |||
571 | let dyn_parent = self | ||
572 | .get_dyn_mut(parent_path) | ||
573 | .ok_or(TopLevelEntryError::NoParent)?; | ||
574 | |||
575 | if dyn_parent | ||
576 | .entity | ||
577 | .map_ref(|parent| !parent.has_child_from_kind(&usr, kind)) | ||
578 | { | ||
579 | return Ok(EntityEntry::Vacant { | ||
580 | parent: DescribedRefMut::from_dyn_mut(dyn_parent).unwrap(), | ||
581 | }); | ||
582 | } | ||
583 | |||
584 | match dyn_parent | ||
585 | .entity | ||
586 | .map(|parent| parent.get_mut_child_from_kind(&usr, kind)) | ||
587 | { | ||
588 | Some(entity) => Ok(EntityEntry::Occupied { entity }), | ||
589 | None => unreachable!(), | ||
590 | } | ||
281 | } | 591 | } |
282 | fn get_member_enums(&mut self) -> Option<&mut BTreeMap<Usr, Described<Enum>>> { | 592 | |
283 | Some(&mut self.member_enums) | 593 | /* |
594 | pub(super) fn entry<T>( | ||
595 | &mut self, | ||
596 | path: clang::Entity, | ||
597 | ) -> Result<EntityEntry<&mut T>, TopLevelEntryError> | ||
598 | where | ||
599 | T: Entity, | ||
600 | { | ||
601 | Ok(match self.entry_dyn(path)? { | ||
602 | EntityEntry::Occupied { entity } => EntityEntry::Occupied { | ||
603 | entity: DescribedRefMut::from_dyn_mut(entity).unwrap(), | ||
604 | }, | ||
605 | EntityEntry::Vacant { parent } => EntityEntry::Vacant { parent }, | ||
606 | }) | ||
284 | } | 607 | } |
608 | */ | ||
609 | } | ||
610 | |||
611 | // TODO: all of the DynEntity business can probably be macro generated too | ||
612 | |||
613 | #[derive(Debug)] | ||
614 | pub(super) enum DynEntity { | ||
615 | Namespace(Namespace), | ||
616 | Variable(Variable), | ||
617 | Struct(Struct), | ||
618 | Function(Function), | ||
619 | Enum(Enum), | ||
620 | EnumConstant(EnumConstant), | ||
621 | TypeAlias(TypeAlias), | ||
622 | } | ||
623 | |||
624 | #[derive(Debug, Clone, Copy)] | ||
625 | pub(super) enum DynEntityRef<'a> { | ||
626 | Namespace(&'a Namespace), | ||
627 | Variable(&'a Variable), | ||
628 | Struct(&'a Struct), | ||
629 | Function(&'a Function), | ||
630 | Enum(&'a Enum), | ||
631 | EnumConstant(&'a EnumConstant), | ||
632 | TypeAlias(&'a TypeAlias), | ||
285 | } | 633 | } |
286 | 634 | ||
287 | /* | 635 | /* |
288 | impl FromNamespaceParent for Namespace { | 636 | impl<'a> DynEntityRef<'a> { |
289 | fn from_namespace_parent<'a>( | 637 | fn map<U, F>(&self, f: F) -> U |
290 | parent: &'a mut Described<Namespace>, | 638 | where |
291 | name: &Usr, | 639 | F: FnOnce(&'a dyn Traversable) -> U, |
292 | ) -> Option<&'a mut Described<Self>> { | 640 | { |
293 | parent.entity.member_namespaces.get_mut(name) | 641 | match self { |
642 | DynEntityRef::Namespace(namespace) => f(*namespace), | ||
643 | DynEntityRef::Variable(variable) => f(*variable), | ||
644 | DynEntityRef::Struct(r#struct) => f(*r#struct), | ||
645 | DynEntityRef::Function(function) => f(*function), | ||
646 | DynEntityRef::Enum(Enum) => f(*Enum), | ||
647 | DynEntityRef::EnumConstant(enum_constant) => f(*enum_constant), | ||
648 | DynEntityRef::TypeAlias(type_alias) => f(*type_alias), | ||
649 | } | ||
294 | } | 650 | } |
295 | } | 651 | } |
296 | */ | 652 | */ |
297 | 653 | ||
298 | impl From<Namespace> for PartialEntity { | 654 | #[derive(Debug)] |
299 | fn from(entity: Namespace) -> Self { | 655 | pub(super) enum DynEntityRefMut<'a> { |
300 | let mut children = Default::default(); | 656 | Namespace(&'a mut Namespace), |
301 | append_children(&mut children, entity.member_namespaces); | 657 | Variable(&'a mut Variable), |
302 | append_children(&mut children, entity.member_variables); | 658 | Struct(&'a mut Struct), |
303 | append_children(&mut children, entity.member_structs); | 659 | Function(&'a mut Function), |
304 | append_children(&mut children, entity.member_functions); | 660 | Enum(&'a mut Enum), |
305 | append_children(&mut children, entity.member_typedefs); | 661 | EnumConstant(&'a mut EnumConstant), |
306 | append_children(&mut children, entity.member_enums); | 662 | TypeAlias(&'a mut TypeAlias), |
307 | 663 | } | |
308 | PartialEntity { | 664 | |
309 | properties: Default::default(), | 665 | impl<'a> DynEntityRefMut<'a> { |
310 | children, | 666 | fn map<U, F>(self, f: F) -> U |
667 | where | ||
668 | F: FnOnce(&'a mut dyn Traversable) -> U, | ||
669 | { | ||
670 | match self { | ||
671 | DynEntityRefMut::Namespace(namespace) => f(namespace), | ||
672 | DynEntityRefMut::Variable(variable) => f(variable), | ||
673 | DynEntityRefMut::Struct(r#struct) => f(r#struct), | ||
674 | DynEntityRefMut::Function(function) => f(function), | ||
675 | DynEntityRefMut::Enum(r#enum) => f(r#enum), | ||
676 | DynEntityRefMut::EnumConstant(enum_constant) => f(enum_constant), | ||
677 | DynEntityRefMut::TypeAlias(type_alias) => f(type_alias), | ||
311 | } | 678 | } |
312 | } | 679 | } |
313 | } | ||
314 | 680 | ||
315 | #[derive(Debug, Clone)] | 681 | fn map_ref<U, F>(&self, f: F) -> U |
316 | pub(super) struct Variable { | 682 | where |
317 | pub(super) kind: VariableKind, | 683 | F: FnOnce(&dyn Traversable) -> U, |
318 | pub(super) r#type: String, | 684 | { |
685 | match self { | ||
686 | DynEntityRefMut::Namespace(namespace) => f(*namespace), | ||
687 | DynEntityRefMut::Variable(variable) => f(*variable), | ||
688 | DynEntityRefMut::Struct(r#struct) => f(*r#struct), | ||
689 | DynEntityRefMut::Function(function) => f(*function), | ||
690 | DynEntityRefMut::Enum(r#enum) => f(*r#enum), | ||
691 | DynEntityRefMut::EnumConstant(enum_constant) => f(*enum_constant), | ||
692 | DynEntityRefMut::TypeAlias(type_alias) => f(*type_alias), | ||
693 | } | ||
694 | } | ||
319 | } | 695 | } |
320 | 696 | ||
321 | impl ClangEntity for Variable { | 697 | impl<'a> TryFrom<clang::Entity<'a>> for DynEntity { |
322 | fn kind(&self) -> ClangEntityKind { | 698 | type Error = Error; |
323 | ClangEntityKind::Variable(self.kind) | 699 | |
700 | fn try_from(entity: clang::Entity) -> Result<Self> { | ||
701 | Ok(match entity.get_kind().try_into()? { | ||
702 | EntityKind::Namespace => Namespace::try_from(entity)?.into_dyn(), | ||
703 | EntityKind::Variable => Variable::try_from(entity)?.into_dyn(), | ||
704 | EntityKind::Struct => Struct::try_from(entity)?.into_dyn(), | ||
705 | EntityKind::Function => Function::try_from(entity)?.into_dyn(), | ||
706 | EntityKind::Enum => Enum::try_from(entity)?.into_dyn(), | ||
707 | EntityKind::EnumConstant => EnumConstant::try_from(entity)?.into_dyn(), | ||
708 | EntityKind::TypeAlias => TypeAlias::try_from(entity)?.into_dyn(), | ||
709 | }) | ||
324 | } | 710 | } |
325 | } | 711 | } |
326 | 712 | ||
327 | impl From<Variable> for PartialEntity { | 713 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
328 | fn from(entity: Variable) -> Self { | 714 | struct ClassMemberProperties { |
329 | let mut properties = Map::new(); | 715 | accessibility: clang::Accessibility, |
330 | properties.insert(String::from("type"), JSONValue::String(entity.r#type)); | 716 | } |
331 | PartialEntity { | 717 | |
332 | properties, | 718 | #[derive(Debug, Error, PartialEq, Eq)] |
333 | children: Default::default(), | 719 | pub(super) enum TryFromClassMemberPropsError { |
334 | } | 720 | #[error("Failed to get accessibility status")] |
721 | Accessibility, | ||
722 | } | ||
723 | |||
724 | impl ClassMemberProperties { | ||
725 | fn try_from_clang(entity: clang::Entity) -> Result<Self> { | ||
726 | Ok(ClassMemberProperties { | ||
727 | accessibility: entity | ||
728 | .get_accessibility() | ||
729 | .ok_or(TryFromClassMemberPropsError::Accessibility)?, | ||
730 | }) | ||
335 | } | 731 | } |
336 | } | 732 | } |
337 | 733 | ||
338 | /* | 734 | impl From<ClassMemberProperties> for JSONMap<String, JSONValue> { |
339 | impl FromNamespaceParent for Variable { | 735 | fn from(member_properties: ClassMemberProperties) -> JSONMap<String, JSONValue> { |
340 | fn from_namespace_parent<'a>( | 736 | let mut properties = JSONMap::new(); |
341 | parent: &'a mut Described<Namespace>, | 737 | properties.insert( |
342 | name: &Usr, | 738 | String::from("accessibility"), |
343 | ) -> Option<&'a mut Described<Self>> { | 739 | match member_properties.accessibility { |
344 | parent.entity.member_variables.get_mut(name) | 740 | clang::Accessibility::Private => JSONValue::String(String::from("private")), |
741 | clang::Accessibility::Protected => JSONValue::String(String::from("protected")), | ||
742 | clang::Accessibility::Public => JSONValue::String(String::from("public")), | ||
743 | }, | ||
744 | ); | ||
745 | properties | ||
345 | } | 746 | } |
346 | } | 747 | } |
347 | */ | ||
348 | 748 | ||
349 | #[derive(Debug, Clone)] | 749 | // ================= |
350 | pub(super) struct Struct { | 750 | // === Namespace === |
351 | //pub(super) member_types: Vec<Usr>, | 751 | // ================= |
352 | pub(super) kind: StructKind, | 752 | |
353 | pub(super) member_variables: BTreeMap<Usr, Described<Variable>>, | 753 | entity! { |
354 | pub(super) member_structs: BTreeMap<Usr, Described<Struct>>, | 754 | pub(super) struct Namespace { |
355 | pub(super) member_functions: BTreeMap<Usr, Described<Function>>, | 755 | /// Whether this is the global namespace |
356 | pub(super) member_typedefs: BTreeMap<Usr, Described<Typedef>>, | 756 | global: bool, |
357 | pub(super) member_enums: BTreeMap<Usr, Described<Enum>>, | 757 | #children => [ |
758 | member_namespaces: Namespace, | ||
759 | member_variables: Variable, | ||
760 | member_structs: Struct, | ||
761 | member_functions: Function, | ||
762 | member_type_aliases: TypeAlias, | ||
763 | member_enums: Enum, | ||
764 | ], | ||
765 | #properties(entity) => json!({"global": entity.global}), | ||
766 | } | ||
358 | } | 767 | } |
359 | 768 | ||
360 | impl ClangEntity for Struct { | 769 | impl Namespace { |
361 | fn kind(&self) -> ClangEntityKind { | 770 | fn new_global() -> Self { |
362 | ClangEntityKind::Struct(self.kind) | 771 | Namespace { |
772 | global: true, | ||
773 | ..Default::default() | ||
774 | } | ||
363 | } | 775 | } |
776 | } | ||
364 | 777 | ||
365 | fn get_member_variables(&mut self) -> Option<&mut BTreeMap<Usr, Described<Variable>>> { | 778 | impl KindName for Namespace { |
366 | Some(&mut self.member_variables) | 779 | fn kind_name_singular(&self) -> &'static str { |
780 | if self.global { | ||
781 | "global namespace" | ||
782 | } else { | ||
783 | "namespace" | ||
784 | } | ||
367 | } | 785 | } |
368 | fn get_member_structs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Struct>>> { | 786 | |
369 | Some(&mut self.member_structs) | 787 | fn kind_name_plural(&self) -> &'static str { |
788 | if self.global { | ||
789 | // TODO: probably panic here, branch should not happen | ||
790 | "global namespaces" | ||
791 | } else { | ||
792 | "namespaces" | ||
793 | } | ||
370 | } | 794 | } |
371 | fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { | 795 | } |
372 | Some(&mut self.member_functions) | 796 | |
797 | impl Default for Namespace { | ||
798 | fn default() -> Self { | ||
799 | Namespace { | ||
800 | global: false, | ||
801 | member_variables: Default::default(), | ||
802 | member_structs: Default::default(), | ||
803 | member_namespaces: Default::default(), | ||
804 | member_functions: Default::default(), | ||
805 | member_type_aliases: Default::default(), | ||
806 | member_enums: Default::default(), | ||
807 | } | ||
373 | } | 808 | } |
374 | fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> { | 809 | } |
375 | Some(&mut self.member_typedefs) | 810 | |
811 | impl<'a> TryFrom<clang::Entity<'a>> for Namespace { | ||
812 | type Error = Error; | ||
813 | |||
814 | fn try_from(entity: clang::Entity) -> Result<Self> { | ||
815 | assert_eq!( | ||
816 | entity.get_kind().try_into(), | ||
817 | Ok(EntityKind::Namespace), | ||
818 | "Trying to parse a non-variable into a variable" | ||
819 | ); | ||
820 | debug!("Parsing Namespace: {:?}", entity); | ||
821 | |||
822 | // Do not recurse here, but recurse in the main loop, since namespace | ||
823 | // definitions is allowed to change between translation units | ||
824 | |||
825 | Ok(Namespace::default()) | ||
376 | } | 826 | } |
377 | fn get_member_enums(&mut self) -> Option<&mut BTreeMap<Usr, Described<Enum>>> { | 827 | } |
378 | Some(&mut self.member_enums) | 828 | |
829 | // ================ | ||
830 | // === Variable === | ||
831 | // ================ | ||
832 | |||
833 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
834 | enum VariableKind { | ||
835 | Variable, | ||
836 | Field { | ||
837 | member_properties: ClassMemberProperties, | ||
838 | }, | ||
839 | } | ||
840 | |||
841 | entity! { | ||
842 | pub(super) struct Variable { | ||
843 | kind: VariableKind, | ||
844 | r#type: String, | ||
845 | #properties(entity) => { | ||
846 | let mut properties = json!({"type": entity.r#type}); | ||
847 | if let VariableKind::Field { member_properties } = entity.kind { | ||
848 | properties.as_object_mut().unwrap().extend(JSONMap::from(member_properties)); | ||
849 | } | ||
850 | properties | ||
851 | }, | ||
379 | } | 852 | } |
380 | } | 853 | } |
381 | 854 | ||
382 | impl From<Struct> for PartialEntity { | 855 | impl KindName for Variable { |
383 | fn from(entity: Struct) -> Self { | 856 | fn kind_name_singular(&self) -> &'static str { |
384 | let mut children = Default::default(); | 857 | match self.kind { |
385 | append_children(&mut children, entity.member_variables); | 858 | VariableKind::Variable => "variable", |
386 | append_children(&mut children, entity.member_structs); | 859 | VariableKind::Field { .. } => "field", |
387 | append_children(&mut children, entity.member_functions); | 860 | } |
388 | append_children(&mut children, entity.member_typedefs); | 861 | } |
389 | append_children(&mut children, entity.member_enums); | ||
390 | 862 | ||
391 | PartialEntity { | 863 | fn kind_name_plural(&self) -> &'static str { |
392 | properties: Default::default(), | 864 | match self.kind { |
393 | children, | 865 | VariableKind::Variable => "variables", |
866 | VariableKind::Field { .. } => "fields", | ||
394 | } | 867 | } |
395 | } | 868 | } |
396 | } | 869 | } |
397 | 870 | ||
398 | /* | 871 | impl<'a> TryFrom<clang::Entity<'a>> for Variable { |
399 | impl FromNamespaceParent for Struct { | 872 | type Error = Error; |
400 | fn from_namespace_parent<'a>( | 873 | |
401 | parent: &'a mut Described<Namespace>, | 874 | fn try_from(entity: clang::Entity) -> Result<Self> { |
402 | name: &Usr, | 875 | let clang_kind = entity.get_kind(); |
403 | ) -> Option<&'a mut Described<Self>> { | 876 | assert_eq!( |
404 | parent.entity.member_structs.get_mut(name) | 877 | clang_kind.try_into(), |
878 | Ok(EntityKind::Variable), | ||
879 | "Trying to parse a non-variable into a variable" | ||
880 | ); | ||
881 | debug!("Parsing Variable: {:?}", entity); | ||
882 | |||
883 | let kind = match clang_kind { | ||
884 | clang::EntityKind::VarDecl => VariableKind::Variable, | ||
885 | clang::EntityKind::FieldDecl => VariableKind::Field { | ||
886 | // TODO: should probably not return on error | ||
887 | member_properties: ClassMemberProperties::try_from_clang(entity)?, | ||
888 | }, | ||
889 | // We panic here because we've asserted the type in the beginning | ||
890 | other => panic!("Trying to parse {:?} as a variable", other), | ||
891 | }; | ||
892 | |||
893 | let r#type = entity.get_type().unwrap().get_display_name(); | ||
894 | trace!("Variable has type: {:?}", r#type); | ||
895 | |||
896 | Ok(Variable { kind, r#type }) | ||
405 | } | 897 | } |
406 | } | 898 | } |
407 | */ | ||
408 | 899 | ||
409 | #[derive(Debug, Clone)] | 900 | // ============== |
410 | pub(super) struct Function { | 901 | // === Struct === |
411 | pub(super) kind: FunctionKind, | 902 | // ============== |
412 | pub(super) arguments: Vec<FunctionArgument>, | 903 | |
413 | pub(super) return_type: String, | 904 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
905 | pub(super) enum StructKind { | ||
906 | Struct, | ||
907 | Class, | ||
414 | } | 908 | } |
415 | 909 | ||
416 | impl ClangEntity for Function { | 910 | entity! { |
417 | fn kind(&self) -> ClangEntityKind { | 911 | pub(super) struct Struct { |
418 | ClangEntityKind::Function(self.kind) | 912 | kind: StructKind, |
913 | #children => [ | ||
914 | member_variables: Variable, | ||
915 | member_structs: Struct, | ||
916 | member_functions: Function, | ||
917 | member_enums: Enum, | ||
918 | member_type_aliases: TypeAlias, | ||
919 | ], | ||
419 | } | 920 | } |
420 | } | 921 | } |
421 | 922 | ||
422 | impl From<Function> for PartialEntity { | 923 | impl KindName for Struct { |
423 | fn from(entity: Function) -> Self { | 924 | fn kind_name_singular(&self) -> &'static str { |
424 | let mut properties = Map::with_capacity(2); | 925 | match self.kind { |
425 | properties.insert( | 926 | StructKind::Struct => "struct", |
426 | String::from("return-type"), | 927 | StructKind::Class => "class", |
427 | JSONValue::String(entity.return_type), | 928 | } |
428 | ); | 929 | } |
429 | properties.insert( | 930 | |
430 | String::from("arguments"), | 931 | fn kind_name_plural(&self) -> &'static str { |
431 | JSONValue::Array(entity.arguments.into_iter().map(Into::into).collect()), | 932 | match self.kind { |
933 | StructKind::Struct => "structs", | ||
934 | StructKind::Class => "classes", | ||
935 | } | ||
936 | } | ||
937 | } | ||
938 | |||
939 | impl<'a> TryFrom<clang::Entity<'a>> for Struct { | ||
940 | type Error = Error; | ||
941 | |||
942 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
943 | let clang_kind = entity.get_kind(); | ||
944 | assert_eq!( | ||
945 | clang_kind.try_into(), | ||
946 | Ok(EntityKind::Struct), | ||
947 | "Trying to parse a non-struct into a struct" | ||
432 | ); | 948 | ); |
949 | debug!("Parsing Struct: {:?}", entity); | ||
433 | 950 | ||
434 | PartialEntity { | 951 | let mut member_variables = BTreeMap::new(); |
435 | properties, | 952 | let mut member_structs = BTreeMap::new(); |
436 | children: Default::default(), | 953 | let mut member_functions = BTreeMap::new(); |
954 | let mut member_enums = BTreeMap::new(); | ||
955 | let mut member_type_aliases = BTreeMap::new(); | ||
956 | |||
957 | for child in entity.get_children() { | ||
958 | trace!("Struct has child: {:?}", child); | ||
959 | |||
960 | let kind = child.get_kind(); | ||
961 | |||
962 | match kind { | ||
963 | ::clang::EntityKind::AccessSpecifier | ::clang::EntityKind::BaseSpecifier => { | ||
964 | continue | ||
965 | } | ||
966 | _ => {} | ||
967 | } | ||
968 | |||
969 | let mut parse_child = || -> Result<()> { | ||
970 | match kind.try_into() { | ||
971 | Ok(EntityKind::Variable) => { | ||
972 | let child_usr = child | ||
973 | .get_usr() | ||
974 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
975 | member_variables.insert(child_usr, Described::<Variable>::try_from(child)?); | ||
976 | } | ||
977 | Ok(EntityKind::Struct) => { | ||
978 | let child_usr: Usr = child | ||
979 | .get_usr() | ||
980 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
981 | member_structs.insert(child_usr, Described::<Struct>::try_from(child)?); | ||
982 | } | ||
983 | Ok(EntityKind::Function) => { | ||
984 | let child_usr = child | ||
985 | .get_usr() | ||
986 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
987 | member_functions.insert(child_usr, Described::<Function>::try_from(child)?); | ||
988 | } | ||
989 | Ok(EntityKind::Enum) => { | ||
990 | let child_usr = child | ||
991 | .get_usr() | ||
992 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
993 | member_enums.insert(child_usr, Described::<Enum>::try_from(child)?); | ||
994 | } | ||
995 | Ok(EntityKind::TypeAlias) => { | ||
996 | let child_usr = child | ||
997 | .get_usr() | ||
998 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
999 | member_type_aliases | ||
1000 | .insert(child_usr, Described::<TypeAlias>::try_from(child)?); | ||
1001 | } | ||
1002 | Ok(other) => warn!("Unsupported child of struct {:?}: {:?}", other, child), | ||
1003 | Err(err) => info!("Error while parsing entity {:?}: {}", child, err), | ||
1004 | } | ||
1005 | |||
1006 | Ok(()) | ||
1007 | }; | ||
1008 | |||
1009 | match parse_child() { | ||
1010 | Ok(()) => {} | ||
1011 | Err(err) => { | ||
1012 | warn!("Error while parsing child {:?}: {}", child, err); | ||
1013 | } | ||
1014 | } | ||
437 | } | 1015 | } |
1016 | |||
1017 | let kind = match clang_kind { | ||
1018 | clang::EntityKind::StructDecl => StructKind::Struct, | ||
1019 | clang::EntityKind::ClassDecl => StructKind::Class, | ||
1020 | // We panic here because we've asserted the type in the beginning | ||
1021 | other => panic!("Trying to parse {:?} as a variable", other), | ||
1022 | }; | ||
1023 | |||
1024 | Ok(Struct { | ||
1025 | kind, | ||
1026 | member_variables, | ||
1027 | member_structs, | ||
1028 | member_functions, | ||
1029 | member_enums, | ||
1030 | member_type_aliases, | ||
1031 | }) | ||
438 | } | 1032 | } |
439 | } | 1033 | } |
440 | 1034 | ||
441 | /* | 1035 | // ================ |
442 | impl FromNamespaceParent for Function { | 1036 | // === Function === |
443 | fn from_namespace_parent<'a>( | 1037 | // ================ |
444 | parent: &'a mut Described<Namespace>, | 1038 | |
445 | name: &Usr, | 1039 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
446 | ) -> Option<&'a mut Described<Self>> { | 1040 | pub(super) enum FunctionKind { |
447 | parent.entity.member_functions.get_mut(name) | 1041 | Function, |
1042 | Method, | ||
1043 | } | ||
1044 | |||
1045 | entity! { | ||
1046 | pub(super) struct Function { | ||
1047 | kind: FunctionKind, | ||
1048 | arguments: Vec<FunctionArgument>, | ||
1049 | return_type: String, | ||
448 | } | 1050 | } |
449 | } | 1051 | } |
450 | */ | ||
451 | 1052 | ||
452 | #[derive(Debug, Clone)] | 1053 | #[derive(Debug, Clone, PartialEq, Eq)] |
453 | pub(super) struct FunctionArgument { | 1054 | pub(super) struct FunctionArgument { |
454 | pub(super) name: String, | 1055 | pub(super) name: String, |
455 | pub(super) r#type: String, | 1056 | pub(super) r#type: String, |
456 | } | 1057 | } |
457 | 1058 | ||
458 | impl From<FunctionArgument> for JSONValue { | 1059 | impl KindName for Function { |
459 | fn from(argument: FunctionArgument) -> JSONValue { | 1060 | fn kind_name_singular(&self) -> &'static str { |
460 | let mut object = Map::new(); | 1061 | match self.kind { |
461 | object.insert(String::from("type"), JSONValue::String(argument.r#type)); | 1062 | FunctionKind::Function => "function", |
462 | object.insert(String::from("name"), JSONValue::String(argument.name)); | 1063 | FunctionKind::Method => "method", |
463 | JSONValue::Object(object) | 1064 | } |
1065 | } | ||
1066 | |||
1067 | fn kind_name_plural(&self) -> &'static str { | ||
1068 | match self.kind { | ||
1069 | FunctionKind::Function => "functions", | ||
1070 | FunctionKind::Method => "methods", | ||
1071 | } | ||
464 | } | 1072 | } |
465 | } | 1073 | } |
466 | 1074 | ||
467 | #[derive(Debug, Clone)] | 1075 | impl<'a> TryFrom<clang::Entity<'a>> for Function { |
468 | pub(super) struct Typedef { | 1076 | type Error = Error; |
469 | pub(super) referee: String, | 1077 | |
1078 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
1079 | let clang_kind = entity.get_kind(); | ||
1080 | assert_eq!( | ||
1081 | clang_kind.try_into(), | ||
1082 | Ok(EntityKind::Function), | ||
1083 | "Trying to parse a non-function into a function" | ||
1084 | ); | ||
1085 | debug!("Parsing Function: {:?}", entity); | ||
1086 | |||
1087 | let return_type = entity.get_result_type().unwrap().get_display_name(); | ||
1088 | trace!("Function has return type: {:?}", return_type); | ||
1089 | let arguments = entity | ||
1090 | .get_arguments() | ||
1091 | // TODO: this seems weird, but it fixes a None for a function that takes only a | ||
1092 | // variadic argument from its own template declaration. | ||
1093 | .unwrap_or_else(|| vec![]) | ||
1094 | .into_iter() | ||
1095 | .map(|arg| { | ||
1096 | let name = arg | ||
1097 | .get_display_name() | ||
1098 | .unwrap_or_else(|| String::from("unnamed")); | ||
1099 | let r#type = arg.get_type().unwrap().get_display_name(); | ||
1100 | trace!("Function has argument {:?} of type {:?}", name, r#type); | ||
1101 | FunctionArgument { name, r#type } | ||
1102 | }) | ||
1103 | .collect(); | ||
1104 | |||
1105 | let kind = match clang_kind { | ||
1106 | clang::EntityKind::FunctionDecl | clang::EntityKind::FunctionTemplate => { | ||
1107 | FunctionKind::Function | ||
1108 | } | ||
1109 | clang::EntityKind::Method | ||
1110 | | clang::EntityKind::Constructor | ||
1111 | | clang::EntityKind::Destructor => FunctionKind::Method, | ||
1112 | // We panic here because we've asserted the type in the beginning | ||
1113 | other => panic!("Trying to parse {:?} as a function", other), | ||
1114 | }; | ||
1115 | |||
1116 | Ok(Function { | ||
1117 | kind, | ||
1118 | arguments, | ||
1119 | return_type, | ||
1120 | }) | ||
1121 | } | ||
470 | } | 1122 | } |
471 | 1123 | ||
472 | impl ClangEntity for Typedef { | 1124 | // ============ |
473 | fn kind(&self) -> ClangEntityKind { | 1125 | // === Enum === |
474 | ClangEntityKind::Typedef | 1126 | // ============ |
1127 | |||
1128 | entity! { | ||
1129 | pub(super) struct Enum { | ||
1130 | underlying_type: String, | ||
1131 | #children => [ | ||
1132 | constants: EnumConstant, | ||
1133 | ], | ||
475 | } | 1134 | } |
476 | } | 1135 | } |
477 | 1136 | ||
478 | impl From<Typedef> for PartialEntity { | 1137 | impl KindName for Enum { |
479 | fn from(entity: Typedef) -> Self { | 1138 | fn kind_name_singular(&self) -> &'static str { |
480 | let mut properties = Map::with_capacity(1); | 1139 | "enum" |
481 | properties.insert(String::from("referee"), JSONValue::String(entity.referee)); | 1140 | } |
1141 | |||
1142 | fn kind_name_plural(&self) -> &'static str { | ||
1143 | "enums" | ||
1144 | } | ||
1145 | } | ||
482 | 1146 | ||
483 | PartialEntity { | 1147 | impl<'a> TryFrom<clang::Entity<'a>> for Enum { |
484 | properties, | 1148 | type Error = Error; |
485 | children: Default::default(), | 1149 | |
1150 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
1151 | assert_eq!( | ||
1152 | entity.get_kind().try_into(), | ||
1153 | Ok(EntityKind::Enum), | ||
1154 | "Trying to parse a non-type alias into a type alias" | ||
1155 | ); | ||
1156 | debug!("Parsing enum: {:?}", entity); | ||
1157 | |||
1158 | let underlying_type = entity | ||
1159 | .get_enum_underlying_type() | ||
1160 | .ok_or_else(|| anyhow!("No enum underlying type"))? | ||
1161 | .get_display_name(); | ||
1162 | |||
1163 | let mut constants = BTreeMap::new(); | ||
1164 | for child in entity.get_children() { | ||
1165 | trace!("Enum has child: {:?}", child); | ||
1166 | match child.get_kind().try_into() { | ||
1167 | Ok(EntityKind::EnumConstant) => { | ||
1168 | let child_usr = child | ||
1169 | .get_usr() | ||
1170 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
1171 | constants.insert(child_usr, Described::<EnumConstant>::try_from(child)?); | ||
1172 | } | ||
1173 | Ok(other) => warn!("Unsupported child of enum {:?}: {:?}", other, child), | ||
1174 | Err(err) => info!("Error while parsing entity {:?}: {}", child, err), | ||
1175 | } | ||
486 | } | 1176 | } |
1177 | |||
1178 | Ok(Enum { | ||
1179 | underlying_type, | ||
1180 | constants, | ||
1181 | }) | ||
487 | } | 1182 | } |
488 | } | 1183 | } |
489 | 1184 | ||
490 | #[derive(Debug, Clone)] | 1185 | // ====================== |
491 | pub(super) struct Enum { | 1186 | // === Enum Constants === |
492 | pub(super) underlying_type: String, | 1187 | // ====================== |
493 | pub(super) constants: BTreeMap<Usr, Described<EnumConstant>>, | 1188 | |
1189 | entity! { | ||
1190 | pub(super) struct EnumConstant { | ||
1191 | value: String, | ||
1192 | } | ||
494 | } | 1193 | } |
495 | 1194 | ||
496 | impl ClangEntity for Enum { | 1195 | impl KindName for EnumConstant { |
497 | fn kind(&self) -> ClangEntityKind { | 1196 | fn kind_name_singular(&self) -> &'static str { |
498 | ClangEntityKind::Enum | 1197 | "enum variant" |
1198 | } | ||
1199 | |||
1200 | fn kind_name_plural(&self) -> &'static str { | ||
1201 | "enum variants" | ||
499 | } | 1202 | } |
500 | } | 1203 | } |
501 | 1204 | ||
502 | impl From<Enum> for PartialEntity { | 1205 | impl<'a> TryFrom<clang::Entity<'a>> for EnumConstant { |
503 | fn from(entity: Enum) -> Self { | 1206 | type Error = Error; |
504 | let mut properties = Map::with_capacity(1); | 1207 | |
505 | properties.insert( | 1208 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { |
506 | String::from("underlying-type"), | 1209 | assert_eq!( |
507 | JSONValue::String(entity.underlying_type), | 1210 | entity.get_kind().try_into(), |
1211 | Ok(EntityKind::EnumConstant), | ||
1212 | "Trying to parse a non-type alias into a type alias" | ||
508 | ); | 1213 | ); |
1214 | debug!("Parsing enum: {:?}", entity); | ||
1215 | |||
1216 | let (signed_value, unsigned_value) = entity | ||
1217 | .get_enum_constant_value() | ||
1218 | .ok_or_else(|| anyhow!("No enum constant value"))?; | ||
1219 | |||
1220 | let is_signed = entity | ||
1221 | .get_semantic_parent() | ||
1222 | .ok_or_else(|| anyhow!("Enum constant not attached to an enum"))? | ||
1223 | .get_enum_underlying_type() | ||
1224 | .ok_or_else(|| anyhow!("Enum doesn't have an underlying type"))? | ||
1225 | .get_canonical_type() | ||
1226 | .is_signed_integer(); | ||
1227 | |||
1228 | let value = if is_signed { | ||
1229 | format!("{}", signed_value) | ||
1230 | } else { | ||
1231 | format!("{}", unsigned_value) | ||
1232 | }; | ||
1233 | |||
1234 | Ok(EnumConstant { value }) | ||
1235 | } | ||
1236 | } | ||
509 | 1237 | ||
510 | let mut children = Default::default(); | 1238 | // ================== |
511 | append_children(&mut children, entity.constants); | 1239 | // === Type Alias === |
1240 | // ================== | ||
512 | 1241 | ||
513 | PartialEntity { | 1242 | entity! { |
514 | properties, | 1243 | pub(super) struct TypeAlias { |
515 | children, | 1244 | referee: String, |
516 | } | ||
517 | } | 1245 | } |
518 | } | 1246 | } |
519 | 1247 | ||
520 | #[derive(Debug, Clone)] | 1248 | impl KindName for TypeAlias { |
521 | pub(super) struct EnumConstant { | 1249 | fn kind_name_singular(&self) -> &'static str { |
522 | pub(super) value: String, | 1250 | "type alias" |
523 | } | 1251 | } |
524 | 1252 | ||
525 | impl ClangEntity for EnumConstant { | 1253 | fn kind_name_plural(&self) -> &'static str { |
526 | fn kind(&self) -> ClangEntityKind { | 1254 | "type aliases" |
527 | ClangEntityKind::EnumConstant | ||
528 | } | 1255 | } |
529 | } | 1256 | } |
530 | 1257 | ||
531 | impl From<EnumConstant> for PartialEntity { | 1258 | impl<'a> TryFrom<clang::Entity<'a>> for TypeAlias { |
532 | fn from(entity: EnumConstant) -> Self { | 1259 | type Error = Error; |
533 | let mut properties = Map::with_capacity(1); | ||
534 | properties.insert(String::from("value"), JSONValue::String(entity.value)); | ||
535 | 1260 | ||
536 | PartialEntity { | 1261 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { |
537 | properties, | 1262 | assert_eq!( |
538 | children: Default::default(), | 1263 | entity.get_kind().try_into(), |
539 | } | 1264 | Ok(EntityKind::TypeAlias), |
1265 | "Trying to parse a non-type alias into a type alias" | ||
1266 | ); | ||
1267 | debug!("Parsing typedef: {:?}", entity); | ||
1268 | |||
1269 | let referee = entity | ||
1270 | .get_typedef_underlying_type() | ||
1271 | .ok_or_else(|| anyhow!("No underlying type"))? | ||
1272 | .get_display_name(); | ||
1273 | |||
1274 | Ok(TypeAlias { referee }) | ||
540 | } | 1275 | } |
541 | } | 1276 | } |
diff --git a/src/parser/clang/parsing.rs b/src/parser/clang/parsing.rs index 50ec5d9..82f0a94 100644 --- a/src/parser/clang/parsing.rs +++ b/src/parser/clang/parsing.rs | |||
@@ -1,240 +1,18 @@ | |||
1 | use super::config::Config; | 1 | use super::config::Config; |
2 | use super::diagnostics; | 2 | use super::diagnostics; |
3 | use super::entities::*; | 3 | use super::entities::*; |
4 | use crate::types::*; | 4 | use crate::types; |
5 | 5 | ||
6 | use anyhow::{anyhow, Context, Error, Result}; | 6 | use anyhow::{Context, Result}; |
7 | use clang::{Clang, CompilationDatabase, Index, TranslationUnit, Usr}; | 7 | use clang::{Clang, CompilationDatabase, Index, TranslationUnit}; |
8 | use thiserror::Error; | 8 | use thiserror::Error; |
9 | 9 | ||
10 | use std::collections::BTreeMap; | ||
11 | use std::convert::{TryFrom, TryInto}; | 10 | use std::convert::{TryFrom, TryInto}; |
12 | use std::path::{Path, PathBuf}; | 11 | use std::path::{Path, PathBuf}; |
13 | 12 | ||
14 | // TODO: check for use of Extend instead of loop+insert | 13 | // TODO: check for use of Extend instead of loop+insert |
15 | 14 | ||
16 | #[derive(Debug, Default)] | 15 | pub(crate) fn parse_compile_commands(config: &Config) -> Result<types::Entity> { |
17 | struct TopLevel { | ||
18 | namespaces: BTreeMap<Usr, Described<Namespace>>, | ||
19 | variables: BTreeMap<Usr, Described<Variable>>, | ||
20 | structs: BTreeMap<Usr, Described<Struct>>, | ||
21 | functions: BTreeMap<Usr, Described<Function>>, | ||
22 | typedefs: BTreeMap<Usr, Described<Typedef>>, | ||
23 | enums: BTreeMap<Usr, Described<Enum>>, | ||
24 | } | ||
25 | |||
26 | /* | ||
27 | enum TopLevelEntry<'a, T> { | ||
28 | Vacant { | ||
29 | parent: &'a mut Described<Namespace>, | ||
30 | }, | ||
31 | /// Vacant, but no semantic parent | ||
32 | TopLevel, | ||
33 | Occupied { | ||
34 | entity: &'a mut Described<T>, | ||
35 | }, | ||
36 | Error, | ||
37 | } | ||
38 | */ | ||
39 | |||
40 | impl TopLevel { | ||
41 | // Somehow has a lifetime issue I can't get my head around | ||
42 | /* | ||
43 | fn entry<'a, T>(&'a mut self, path: &::clang::Entity) -> Result<TopLevelEntry<'a, T>> | ||
44 | where | ||
45 | T: ClangEntity + FromNamespaceParent + FromTopLevel, | ||
46 | { | ||
47 | let usr = path.get_usr().ok_or_else(|| anyhow!("no usr"))?; | ||
48 | if let Some(parent_path) = parent(&path) { | ||
49 | let parent_entry = self.entry::<Namespace>(&parent_path)?; | ||
50 | if let TopLevelEntry::Occupied { | ||
51 | entity: namespace_parent, | ||
52 | } = parent_entry | ||
53 | { | ||
54 | Ok(match T::from_namespace_parent(namespace_parent, &usr) { | ||
55 | None => TopLevelEntry::Vacant { | ||
56 | parent: namespace_parent, | ||
57 | }, | ||
58 | Some(entity) => TopLevelEntry::Occupied { entity }, | ||
59 | }) | ||
60 | } else { | ||
61 | panic!("Wut"); | ||
62 | } | ||
63 | } else { | ||
64 | Ok(match T::from_toplevel(self, &usr) { | ||
65 | Some(entity) => TopLevelEntry::Occupied { entity }, | ||
66 | None => TopLevelEntry::TopLevel, | ||
67 | }) | ||
68 | } | ||
69 | } | ||
70 | */ | ||
71 | |||
72 | fn get_entity_mut(&mut self, path: clang::Entity) -> Option<&mut dyn ClangEntity> { | ||
73 | let usr = path.get_usr()?; | ||
74 | if let Some(parent_path) = parent(path) { | ||
75 | let parent = self.get_entity_mut(parent_path)?; | ||
76 | Some(match path.get_kind().try_into().ok()? { | ||
77 | ClangEntityKind::Namespace => { | ||
78 | &mut parent.get_member_namespaces()?.get_mut(&usr)?.entity | ||
79 | } | ||
80 | ClangEntityKind::Variable(_) => { | ||
81 | &mut parent.get_member_variables()?.get_mut(&usr)?.entity | ||
82 | } | ||
83 | ClangEntityKind::Function(_) => { | ||
84 | &mut parent.get_member_functions()?.get_mut(&usr)?.entity | ||
85 | } | ||
86 | ClangEntityKind::Struct(_) => { | ||
87 | &mut parent.get_member_structs()?.get_mut(&usr)?.entity | ||
88 | } | ||
89 | ClangEntityKind::Typedef => { | ||
90 | &mut parent.get_member_typedefs()?.get_mut(&usr)?.entity | ||
91 | } | ||
92 | ClangEntityKind::Enum => &mut parent.get_member_enums()?.get_mut(&usr)?.entity, | ||
93 | ClangEntityKind::EnumConstant => { | ||
94 | panic!("enum variant getting"); | ||
95 | } | ||
96 | }) | ||
97 | } else { | ||
98 | Some(match path.get_kind().try_into().ok()? { | ||
99 | ClangEntityKind::Namespace => &mut self.namespaces.get_mut(&usr)?.entity, | ||
100 | ClangEntityKind::Variable(_) => &mut self.variables.get_mut(&usr)?.entity, | ||
101 | ClangEntityKind::Struct(_) => &mut self.structs.get_mut(&usr)?.entity, | ||
102 | ClangEntityKind::Function(_) => &mut self.functions.get_mut(&usr)?.entity, | ||
103 | ClangEntityKind::Typedef => &mut self.typedefs.get_mut(&usr)?.entity, | ||
104 | ClangEntityKind::Enum => &mut self.enums.get_mut(&usr)?.entity, | ||
105 | ClangEntityKind::EnumConstant => panic!("enum variant getting"), | ||
106 | }) | ||
107 | } | ||
108 | } | ||
109 | |||
110 | fn get_namespace_mut(&mut self, path: clang::Entity) -> Option<&mut Described<Namespace>> { | ||
111 | let usr = path.get_usr()?; | ||
112 | |||
113 | if let Some(parent_path) = parent(path) { | ||
114 | let parent = self.get_entity_mut(parent_path)?; | ||
115 | parent.get_member_namespaces()?.get_mut(&usr) | ||
116 | } else { | ||
117 | self.namespaces.get_mut(&usr) | ||
118 | } | ||
119 | } | ||
120 | |||
121 | fn insert<T>(&mut self, path: clang::Entity, entity: Described<T>) -> Result<()> | ||
122 | where | ||
123 | T: ClangEntity + std::fmt::Debug, | ||
124 | Self: TopLevelManipulation<T>, | ||
125 | Namespace: NamespaceParentManipulation<T>, | ||
126 | { | ||
127 | let usr = path.get_usr().ok_or_else(|| anyhow!("no usr"))?; | ||
128 | if let Some(parent_path) = parent(path) { | ||
129 | if let Some(parent_namespace) = self.get_namespace_mut(parent_path) { | ||
130 | parent_namespace | ||
131 | .entity | ||
132 | .get_members_mut() | ||
133 | // Namespace should be able to contain every kind of entity | ||
134 | .unwrap() | ||
135 | .insert(usr, entity); | ||
136 | Ok(()) | ||
137 | } else { | ||
138 | Err(anyhow!( | ||
139 | "has parent: {:?} but no parent in tree", | ||
140 | parent_path | ||
141 | )) | ||
142 | } | ||
143 | } else { | ||
144 | self.insert_toplevel(usr, entity); | ||
145 | Ok(()) | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // Like .get_semantic_parent(), but return none if the parent is the translation unit | ||
151 | fn parent(libclang_entity: clang::Entity) -> Option<clang::Entity> { | ||
152 | match libclang_entity.get_semantic_parent() { | ||
153 | Some(parent) => { | ||
154 | if parent.get_kind() != clang::EntityKind::TranslationUnit { | ||
155 | Some(parent) | ||
156 | } else { | ||
157 | None | ||
158 | } | ||
159 | } | ||
160 | None => { | ||
161 | warn!("get_semantic_parent() returned None"); | ||
162 | None | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | trait TopLevelManipulation<T: ClangEntity> { | ||
168 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<T>); | ||
169 | } | ||
170 | |||
171 | impl TopLevelManipulation<Namespace> for TopLevel { | ||
172 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Namespace>) { | ||
173 | self.namespaces.insert(usr, entity); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | impl TopLevelManipulation<Variable> for TopLevel { | ||
178 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Variable>) { | ||
179 | self.variables.insert(usr, entity); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | impl TopLevelManipulation<Function> for TopLevel { | ||
184 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Function>) { | ||
185 | self.functions.insert(usr, entity); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | impl TopLevelManipulation<Struct> for TopLevel { | ||
190 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Struct>) { | ||
191 | self.structs.insert(usr, entity); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | impl TopLevelManipulation<Typedef> for TopLevel { | ||
196 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Typedef>) { | ||
197 | self.typedefs.insert(usr, entity); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | impl TopLevelManipulation<Enum> for TopLevel { | ||
202 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Enum>) { | ||
203 | self.enums.insert(usr, entity); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | trait FromTopLevel: ClangEntity + Sized { | ||
209 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>>; | ||
210 | } | ||
211 | |||
212 | impl FromTopLevel for Namespace { | ||
213 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>> { | ||
214 | toplevel.namespaces.get_mut(usr) | ||
215 | } | ||
216 | } | ||
217 | |||
218 | impl FromTopLevel for Variable { | ||
219 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>> { | ||
220 | toplevel.variables.get_mut(usr) | ||
221 | } | ||
222 | } | ||
223 | |||
224 | impl FromTopLevel for Function { | ||
225 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>> { | ||
226 | toplevel.functions.get_mut(usr) | ||
227 | } | ||
228 | } | ||
229 | |||
230 | impl FromTopLevel for Struct { | ||
231 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>> { | ||
232 | toplevel.structs.get_mut(usr) | ||
233 | } | ||
234 | } | ||
235 | */ | ||
236 | |||
237 | pub(crate) fn parse_compile_commands(config: &Config) -> Result<BTreeMap<EntityId, Entity>> { | ||
238 | let clang = Clang::new().unwrap(); | 16 | let clang = Clang::new().unwrap(); |
239 | let index = Index::new( | 17 | let index = Index::new( |
240 | &clang, /* exclude from pch = */ false, /* print diagnostics = */ false, | 18 | &clang, /* exclude from pch = */ false, /* print diagnostics = */ false, |
@@ -295,7 +73,7 @@ pub(crate) fn parse_compile_commands(config: &Config) -> Result<BTreeMap<EntityI | |||
295 | Ok(entities.into()) | 73 | Ok(entities.into()) |
296 | } | 74 | } |
297 | 75 | ||
298 | pub(crate) fn parse_file<T>(path: T, config: &Config) -> Result<BTreeMap<EntityId, Entity>> | 76 | pub(crate) fn parse_file<T>(path: T, config: &Config) -> Result<types::Entity> |
299 | where | 77 | where |
300 | T: Into<PathBuf>, | 78 | T: Into<PathBuf>, |
301 | T: AsRef<Path>, | 79 | T: AsRef<Path>, |
@@ -422,15 +200,13 @@ fn is_in_system_header(entity: clang::Entity, base_dir: impl AsRef<Path>) -> boo | |||
422 | } | 200 | } |
423 | 201 | ||
424 | // Entries encountered in the toplevel lexical context | 202 | // Entries encountered in the toplevel lexical context |
425 | fn add_entity( | 203 | fn add_entity(libclang_entity: clang::Entity, toplevel: &mut TopLevel) -> clang::EntityVisitResult { |
426 | libclang_entity: clang::Entity, | 204 | let usr = match libclang_entity.get_usr() { |
427 | toplevel: &mut TopLevel, | 205 | None => return clang::EntityVisitResult::Continue, |
428 | ) -> clang::EntityVisitResult { | 206 | Some(usr) => usr, |
429 | if libclang_entity.get_usr().is_none() { | ||
430 | return clang::EntityVisitResult::Continue; | ||
431 | }; | 207 | }; |
432 | 208 | ||
433 | let kind = match ClangEntityKind::try_from(libclang_entity.get_kind()) { | 209 | let kind = match EntityKind::try_from(libclang_entity.get_kind()) { |
434 | Ok(kind) => kind, | 210 | Ok(kind) => kind, |
435 | Err(err) => { | 211 | Err(err) => { |
436 | diagnostics::error(format!("{}", err), libclang_entity); | 212 | diagnostics::error(format!("{}", err), libclang_entity); |
@@ -438,51 +214,29 @@ fn add_entity( | |||
438 | } | 214 | } |
439 | }; | 215 | }; |
440 | 216 | ||
441 | if let Some(in_tree_entity) = toplevel.get_entity_mut(libclang_entity) { | 217 | match toplevel.entry_dyn(libclang_entity) { |
442 | // if current.has_documentation && !tree.has_documentation { | 218 | Err(err) => diagnostics::error(format!("{}", err), libclang_entity), |
443 | // append_documentation | 219 | Ok(EntityEntry::Occupied { entity }) => { |
444 | // } | 220 | // if current.has_documentation && !tree.has_documentation { |
445 | } else { | 221 | // append_documentation |
446 | //if libclang_entity.is_definition() { | 222 | // } |
447 | // TODO: This probably means that you can't put documentation in forward declarations. | 223 | // |
448 | // TODO: Ad-hoc toplevel functions are not documented | 224 | // if !curent.has_children && tree.has_children { |
449 | // | 225 | // parse(tree) |
450 | // This seems restrictive, but since there can be multiple declarations but only one definition, | 226 | // } |
451 | // you should probably put your documentation on the definition anyway? | 227 | } |
452 | // | 228 | Ok(EntityEntry::Vacant { parent: dyn_parent }) => { |
453 | // Also, skipping forward declarations allows us to not have to insert, then update the tree | 229 | if let Err(err) = libclang_entity |
454 | // when we see the definition. | 230 | .try_into() |
455 | 231 | .and_then(|entity| dyn_parent.entity.insert(usr, entity)) | |
456 | let result = match kind { | 232 | { |
457 | ClangEntityKind::Namespace => { | 233 | diagnostics::error(format!("{}", err), libclang_entity); |
458 | if libclang_entity.get_name().is_some() { | 234 | return ::clang::EntityVisitResult::Continue; |
459 | Described::<Namespace>::try_from(libclang_entity) | ||
460 | .and_then(|namespace| toplevel.insert(libclang_entity, namespace)) | ||
461 | } else { | ||
462 | Ok(()) | ||
463 | } | ||
464 | } | 235 | } |
465 | ClangEntityKind::Variable(_) => Described::<Variable>::try_from(libclang_entity) | ||
466 | .and_then(|variable| toplevel.insert(libclang_entity, variable)), | ||
467 | ClangEntityKind::Struct(_) => Described::<Struct>::try_from(libclang_entity) | ||
468 | .and_then(|r#struct| toplevel.insert(libclang_entity, r#struct)), | ||
469 | ClangEntityKind::Function(_) => Described::<Function>::try_from(libclang_entity) | ||
470 | .and_then(|function| toplevel.insert(libclang_entity, function)), | ||
471 | ClangEntityKind::Typedef => Described::<Typedef>::try_from(libclang_entity) | ||
472 | .and_then(|typedef| toplevel.insert(libclang_entity, typedef)), | ||
473 | ClangEntityKind::Enum => Described::<Enum>::try_from(libclang_entity) | ||
474 | .and_then(|r#enum| toplevel.insert(libclang_entity, r#enum)), | ||
475 | ClangEntityKind::EnumConstant => panic!("Enum variant encountered not within an enum"), | ||
476 | }; | ||
477 | // TODO: check result | ||
478 | |||
479 | if let Err(err) = result { | ||
480 | diagnostics::error(format!("{}", err), libclang_entity); | ||
481 | return ::clang::EntityVisitResult::Continue; | ||
482 | } | 236 | } |
483 | } | 237 | } |
484 | 238 | ||
485 | if kind == ClangEntityKind::Namespace && libclang_entity.get_name().is_some() { | 239 | if kind == EntityKind::Namespace && libclang_entity.get_name().is_some() { |
486 | // Recurse here since namespace definitions are allowed to change between translation units. | 240 | // Recurse here since namespace definitions are allowed to change between translation units. |
487 | ::clang::EntityVisitResult::Recurse | 241 | ::clang::EntityVisitResult::Recurse |
488 | } else { | 242 | } else { |
@@ -490,338 +244,6 @@ fn add_entity( | |||
490 | } | 244 | } |
491 | } | 245 | } |
492 | 246 | ||
493 | impl From<TopLevel> for BTreeMap<EntityId, Entity> { | ||
494 | fn from(toplevel: TopLevel) -> Self { | ||
495 | toplevel | ||
496 | .namespaces | ||
497 | .into_iter() | ||
498 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())) | ||
499 | .chain( | ||
500 | toplevel | ||
501 | .variables | ||
502 | .into_iter() | ||
503 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
504 | ) | ||
505 | .chain( | ||
506 | toplevel | ||
507 | .structs | ||
508 | .into_iter() | ||
509 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
510 | ) | ||
511 | .chain( | ||
512 | toplevel | ||
513 | .functions | ||
514 | .into_iter() | ||
515 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
516 | ) | ||
517 | .chain( | ||
518 | toplevel | ||
519 | .typedefs | ||
520 | .into_iter() | ||
521 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
522 | ) | ||
523 | .collect() | ||
524 | } | ||
525 | } | ||
526 | |||
527 | impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T> | ||
528 | where | ||
529 | T: TryFrom<clang::Entity<'a>, Error = Error>, | ||
530 | { | ||
531 | type Error = Error; | ||
532 | |||
533 | fn try_from(entity: clang::Entity<'a>) -> Result<Self, Error> { | ||
534 | Ok(Described::<T> { | ||
535 | description: get_description(entity)?, | ||
536 | entity: T::try_from(entity)?, | ||
537 | }) | ||
538 | } | ||
539 | } | ||
540 | |||
541 | impl<'a> TryFrom<clang::Entity<'a>> for Namespace { | ||
542 | type Error = Error; | ||
543 | |||
544 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
545 | match entity.get_kind().try_into() { | ||
546 | Ok(ClangEntityKind::Namespace) => {} | ||
547 | _ => panic!("Trying to parse a non-variable into a variable"), | ||
548 | } | ||
549 | debug!("Parsing Namespace: {:?}", entity); | ||
550 | |||
551 | // Do not recurse here, but recurse in the main loop, since namespace | ||
552 | // definitions is allowed to change between translation units | ||
553 | |||
554 | Ok(Namespace { | ||
555 | member_namespaces: Default::default(), | ||
556 | member_variables: Default::default(), | ||
557 | member_structs: Default::default(), | ||
558 | member_functions: Default::default(), | ||
559 | member_typedefs: Default::default(), | ||
560 | member_enums: Default::default(), | ||
561 | }) | ||
562 | } | ||
563 | } | ||
564 | |||
565 | impl<'a> TryFrom<clang::Entity<'a>> for Variable { | ||
566 | type Error = Error; | ||
567 | |||
568 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
569 | let variable_kind; | ||
570 | match entity.get_kind().try_into() { | ||
571 | Ok(ClangEntityKind::Variable(kind)) => { | ||
572 | variable_kind = kind; | ||
573 | } | ||
574 | _ => panic!("Trying to parse a non-variable into a variable"), | ||
575 | } | ||
576 | debug!("Parsing Variable: {:?}", entity); | ||
577 | |||
578 | let r#type = entity.get_type().unwrap().get_display_name(); | ||
579 | trace!("Variable has type: {:?}", r#type); | ||
580 | |||
581 | Ok(Variable { | ||
582 | r#type, | ||
583 | kind: variable_kind, | ||
584 | }) | ||
585 | } | ||
586 | } | ||
587 | |||
588 | impl<'a> TryFrom<clang::Entity<'a>> for Struct { | ||
589 | type Error = Error; | ||
590 | |||
591 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
592 | let struct_kind; | ||
593 | match entity.get_kind().try_into() { | ||
594 | Ok(ClangEntityKind::Struct(kind)) => { | ||
595 | struct_kind = kind; | ||
596 | } | ||
597 | _ => panic!("Trying to parse a non-struct into a struct"), | ||
598 | } | ||
599 | debug!("Parsing Struct: {:?}", entity); | ||
600 | |||
601 | let mut member_variables = BTreeMap::new(); | ||
602 | let mut member_structs = BTreeMap::new(); | ||
603 | let mut member_functions = BTreeMap::new(); | ||
604 | let mut member_typedefs = BTreeMap::new(); | ||
605 | let mut member_enums = BTreeMap::new(); | ||
606 | |||
607 | for child in entity.get_children() { | ||
608 | trace!("Struct has child: {:?}", child); | ||
609 | |||
610 | let kind = child.get_kind(); | ||
611 | |||
612 | match kind { | ||
613 | ::clang::EntityKind::AccessSpecifier | ::clang::EntityKind::BaseSpecifier => { | ||
614 | continue | ||
615 | } | ||
616 | _ => {} | ||
617 | } | ||
618 | |||
619 | let mut parse_child = || -> Result<()> { | ||
620 | match kind.try_into() { | ||
621 | Ok(ClangEntityKind::Variable(_)) => { | ||
622 | let child_usr = child | ||
623 | .get_usr() | ||
624 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
625 | member_variables.insert(child_usr, Described::<Variable>::try_from(child)?); | ||
626 | } | ||
627 | Ok(ClangEntityKind::Struct(_)) => { | ||
628 | let child_usr: Usr = child | ||
629 | .get_usr() | ||
630 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
631 | member_structs.insert(child_usr, Described::<Struct>::try_from(child)?); | ||
632 | } | ||
633 | Ok(ClangEntityKind::Function(_)) => { | ||
634 | let child_usr = child | ||
635 | .get_usr() | ||
636 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
637 | member_functions.insert(child_usr, Described::<Function>::try_from(child)?); | ||
638 | } | ||
639 | Ok(ClangEntityKind::Typedef) => { | ||
640 | let child_usr = child | ||
641 | .get_usr() | ||
642 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
643 | member_typedefs.insert(child_usr, Described::<Typedef>::try_from(child)?); | ||
644 | } | ||
645 | Ok(ClangEntityKind::Enum) => { | ||
646 | let child_usr = child | ||
647 | .get_usr() | ||
648 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
649 | member_enums.insert(child_usr, Described::<Enum>::try_from(child)?); | ||
650 | } | ||
651 | Ok(other) => warn!("Unsupported child of struct {:?}: {:?}", other, child), | ||
652 | Err(err) => info!("Error while parsing entity {:?}: {}", child, err), | ||
653 | } | ||
654 | |||
655 | Ok(()) | ||
656 | }; | ||
657 | |||
658 | match parse_child() { | ||
659 | Ok(()) => {} | ||
660 | Err(err) => { | ||
661 | warn!("Error while parsing child {:?}: {}", child, err); | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
666 | Ok(Struct { | ||
667 | kind: struct_kind, | ||
668 | member_functions, | ||
669 | member_structs, | ||
670 | member_variables, | ||
671 | member_typedefs, | ||
672 | member_enums, | ||
673 | }) | ||
674 | } | ||
675 | } | ||
676 | |||
677 | impl<'a> TryFrom<clang::Entity<'a>> for Function { | ||
678 | type Error = Error; | ||
679 | |||
680 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
681 | let function_kind; | ||
682 | match entity.get_kind().try_into() { | ||
683 | Ok(ClangEntityKind::Function(kind)) => { | ||
684 | function_kind = kind; | ||
685 | } | ||
686 | _ => panic!("Trying to parse a non-function into a function"), | ||
687 | } | ||
688 | debug!("Parsing Function: {:?}", entity); | ||
689 | |||
690 | let return_type = entity.get_result_type().unwrap().get_display_name(); | ||
691 | trace!("Function has return type: {:?}", return_type); | ||
692 | let arguments = entity | ||
693 | .get_arguments() | ||
694 | // TODO: this seems weird, but it fixes a None for a function that takes only a | ||
695 | // variadic argument from its own template declaration. | ||
696 | .unwrap_or_else(|| vec![]) | ||
697 | .into_iter() | ||
698 | .map(|arg| { | ||
699 | let name = arg | ||
700 | .get_display_name() | ||
701 | .unwrap_or_else(|| String::from("unnamed")); | ||
702 | let r#type = arg.get_type().unwrap().get_display_name(); | ||
703 | trace!("Function has argument {:?} of type {:?}", name, r#type); | ||
704 | FunctionArgument { name, r#type } | ||
705 | }) | ||
706 | .collect(); | ||
707 | |||
708 | Ok(Function { | ||
709 | kind: function_kind, | ||
710 | arguments, | ||
711 | return_type, | ||
712 | }) | ||
713 | } | ||
714 | } | ||
715 | |||
716 | impl<'a> TryFrom<clang::Entity<'a>> for Typedef { | ||
717 | type Error = Error; | ||
718 | |||
719 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
720 | match entity.get_kind().try_into() { | ||
721 | Ok(ClangEntityKind::Typedef) => {} | ||
722 | _ => panic!("Trying to parse a non-typedef into a typedef"), | ||
723 | } | ||
724 | debug!("Parsing typedef: {:?}", entity); | ||
725 | |||
726 | let referee = entity | ||
727 | .get_typedef_underlying_type() | ||
728 | .ok_or_else(|| anyhow!("No underlying type"))? | ||
729 | .get_display_name(); | ||
730 | |||
731 | Ok(Typedef { referee }) | ||
732 | } | ||
733 | } | ||
734 | |||
735 | impl<'a> TryFrom<clang::Entity<'a>> for Enum { | ||
736 | type Error = Error; | ||
737 | |||
738 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
739 | match entity.get_kind().try_into() { | ||
740 | Ok(ClangEntityKind::Enum) => {} | ||
741 | _ => panic!("Trying to parse a non-enum into a enum"), | ||
742 | } | ||
743 | debug!("Parsing enum: {:?}", entity); | ||
744 | |||
745 | let underlying_type = entity | ||
746 | .get_enum_underlying_type() | ||
747 | .ok_or_else(|| anyhow!("No enum underlying type"))? | ||
748 | .get_display_name(); | ||
749 | |||
750 | let mut constants = BTreeMap::new(); | ||
751 | for child in entity.get_children() { | ||
752 | trace!("Enum has child: {:?}", child); | ||
753 | match child.get_kind().try_into() { | ||
754 | Ok(ClangEntityKind::EnumConstant) => { | ||
755 | let child_usr = child | ||
756 | .get_usr() | ||
757 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
758 | constants.insert(child_usr, Described::<EnumConstant>::try_from(child)?); | ||
759 | } | ||
760 | Ok(other) => warn!("Unsupported child of enum {:?}: {:?}", other, child), | ||
761 | Err(err) => info!("Error while parsing entity {:?}: {}", child, err), | ||
762 | } | ||
763 | } | ||
764 | |||
765 | Ok(Enum { | ||
766 | underlying_type, | ||
767 | constants, | ||
768 | }) | ||
769 | } | ||
770 | } | ||
771 | |||
772 | impl<'a> TryFrom<clang::Entity<'a>> for EnumConstant { | ||
773 | type Error = Error; | ||
774 | |||
775 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
776 | match entity.get_kind().try_into() { | ||
777 | Ok(ClangEntityKind::EnumConstant) => {} | ||
778 | _ => panic!("Trying to parse a non-enum constant into a enum constant"), | ||
779 | } | ||
780 | debug!("Parsing enum: {:?}", entity); | ||
781 | |||
782 | let (signed_value, unsigned_value) = entity | ||
783 | .get_enum_constant_value() | ||
784 | .ok_or_else(|| anyhow!("No enum constant value"))?; | ||
785 | |||
786 | let is_signed = entity | ||
787 | .get_semantic_parent() | ||
788 | .ok_or_else(|| anyhow!("Enum constant not attached to an enum"))? | ||
789 | .get_enum_underlying_type() | ||
790 | .ok_or_else(|| anyhow!("Enum doesn't have an underlying type"))? | ||
791 | .get_canonical_type() | ||
792 | .is_signed_integer(); | ||
793 | |||
794 | let value = if is_signed { | ||
795 | format!("{}", signed_value) | ||
796 | } else { | ||
797 | format!("{}", unsigned_value) | ||
798 | }; | ||
799 | |||
800 | Ok(EnumConstant { value }) | ||
801 | } | ||
802 | } | ||
803 | |||
804 | fn get_description(entity: clang::Entity) -> Result<Description> { | ||
805 | let name = entity | ||
806 | .get_display_name() | ||
807 | .ok_or_else(|| anyhow!("Entity has no name: {:?}", entity))?; | ||
808 | |||
809 | // TODO: is that the best? | ||
810 | if let (Some(brief), Some(comment)) = (entity.get_comment_brief(), entity.get_comment()) { | ||
811 | Ok(Description { | ||
812 | name, | ||
813 | brief, | ||
814 | detailed: parse_comment(comment), | ||
815 | }) | ||
816 | } else { | ||
817 | Ok(Description { | ||
818 | name, | ||
819 | brief: String::new(), | ||
820 | detailed: String::new(), | ||
821 | }) | ||
822 | } | ||
823 | } | ||
824 | |||
825 | pub fn parse_comment(raw: String) -> String { | 247 | pub fn parse_comment(raw: String) -> String { |
826 | #[derive(Debug)] | 248 | #[derive(Debug)] |
827 | enum CommentStyle { | 249 | enum CommentStyle { |