summaryrefslogtreecommitdiffstats
path: root/src/parser/clang/parsing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/clang/parsing.rs')
-rw-r--r--src/parser/clang/parsing.rs636
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 @@
1use super::config::Config; 1use super::config::Config;
2use super::diagnostics; 2use super::diagnostics;
3use super::entities::*; 3use super::entities::*;
4use crate::types::*; 4use crate::types;
5 5
6use anyhow::{anyhow, Context, Error, Result}; 6use anyhow::{Context, Result};
7use clang::{Clang, CompilationDatabase, Index, TranslationUnit, Usr}; 7use clang::{Clang, CompilationDatabase, Index, TranslationUnit};
8use thiserror::Error; 8use thiserror::Error;
9 9
10use std::collections::BTreeMap;
11use std::convert::{TryFrom, TryInto}; 10use std::convert::{TryFrom, TryInto};
12use std::path::{Path, PathBuf}; 11use 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)] 15pub(crate) fn parse_compile_commands(config: &Config) -> Result<types::Entity> {
17struct 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/*
27enum 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
40impl 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
151fn 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
167trait TopLevelManipulation<T: ClangEntity> {
168 fn insert_toplevel(&mut self, usr: Usr, entity: Described<T>);
169}
170
171impl TopLevelManipulation<Namespace> for TopLevel {
172 fn insert_toplevel(&mut self, usr: Usr, entity: Described<Namespace>) {
173 self.namespaces.insert(usr, entity);
174 }
175}
176
177impl TopLevelManipulation<Variable> for TopLevel {
178 fn insert_toplevel(&mut self, usr: Usr, entity: Described<Variable>) {
179 self.variables.insert(usr, entity);
180 }
181}
182
183impl TopLevelManipulation<Function> for TopLevel {
184 fn insert_toplevel(&mut self, usr: Usr, entity: Described<Function>) {
185 self.functions.insert(usr, entity);
186 }
187}
188
189impl TopLevelManipulation<Struct> for TopLevel {
190 fn insert_toplevel(&mut self, usr: Usr, entity: Described<Struct>) {
191 self.structs.insert(usr, entity);
192 }
193}
194
195impl TopLevelManipulation<Typedef> for TopLevel {
196 fn insert_toplevel(&mut self, usr: Usr, entity: Described<Typedef>) {
197 self.typedefs.insert(usr, entity);
198 }
199}
200
201impl 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/*
208trait FromTopLevel: ClangEntity + Sized {
209 fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>>;
210}
211
212impl 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
218impl 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
224impl 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
230impl 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
237pub(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
298pub(crate) fn parse_file<T>(path: T, config: &Config) -> Result<BTreeMap<EntityId, Entity>> 76pub(crate) fn parse_file<T>(path: T, config: &Config) -> Result<types::Entity>
299where 77where
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
425fn add_entity( 203fn 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
493impl 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
527impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T>
528where
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
541impl<'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
565impl<'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
588impl<'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
677impl<'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
716impl<'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
735impl<'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
772impl<'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
804fn 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
825pub fn parse_comment(raw: String) -> String { 247pub fn parse_comment(raw: String) -> String {
826 #[derive(Debug)] 248 #[derive(Debug)]
827 enum CommentStyle { 249 enum CommentStyle {