diff options
Diffstat (limited to 'src/parser/clang/parsing.rs')
-rw-r--r-- | src/parser/clang/parsing.rs | 636 |
1 files changed, 29 insertions, 607 deletions
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 { |