summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2020-02-23 17:01:14 +0100
committerMinijackson <minijackson@riseup.net>2020-02-23 17:01:14 +0100
commit5b137e8bb767aa2b381e9d5a0710583c4edaa889 (patch)
treeb732d1071bffda7b9d54aaa5ebeb0122890a750a
parent5a83e2b55b672042562601866ed0253613c5e8b8 (diff)
downloadposeidoc-5b137e8bb767aa2b381e9d5a0710583c4edaa889.tar.gz
poseidoc-5b137e8bb767aa2b381e9d5a0710583c4edaa889.zip
Big clang refactoring
- Manipulating the entity tree should be much nicer: - "Typesafe type erasure" - Entry API for the tree - *NOT clang specific*: There is now a single entity at the top of the tree: the global namespace scope for the case of C/C++
-rw-r--r--src/generator/mod.rs23
-rw-r--r--src/parser/clang/entities.rs1477
-rw-r--r--src/parser/clang/parsing.rs636
-rw-r--r--src/types.rs2
4 files changed, 1147 insertions, 991 deletions
diff --git a/src/generator/mod.rs b/src/generator/mod.rs
index 3f62779..f351bb1 100644
--- a/src/generator/mod.rs
+++ b/src/generator/mod.rs
@@ -17,7 +17,7 @@ const DEFAULT_CSS: &[u8] = include_bytes!("../../res/style.css");
17 17
18pub(crate) fn generate( 18pub(crate) fn generate(
19 base_dir: &Path, 19 base_dir: &Path,
20 entities: BTreeMap<EntityId, Entity>, 20 toplevel_entity: Entity,
21 config: &Config, 21 config: &Config,
22) -> Result<()> { 22) -> Result<()> {
23 let md_output_dir = base_dir.join("markdown"); 23 let md_output_dir = base_dir.join("markdown");
@@ -38,17 +38,16 @@ pub(crate) fn generate(
38 debug!("Generated temporary file with CSS at: {:?}", css_path); 38 debug!("Generated temporary file with CSS at: {:?}", css_path);
39 39
40 rayon::scope(|scope| { 40 rayon::scope(|scope| {
41 for (id, entity) in entities { 41 generate_recursively(
42 generate_recursively( 42 // TODO: a bit hacky?
43 id, 43 EntityId(String::from("index")),
44 entity, 44 toplevel_entity,
45 scope, 45 scope,
46 &md_output_dir, 46 &md_output_dir,
47 &html_output_dir, 47 &html_output_dir,
48 css_path, 48 css_path,
49 config, 49 config,
50 ); 50 );
51 }
52 }); 51 });
53 52
54 Ok(()) 53 Ok(())
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 @@
1use crate::types::{self, *}; 1use crate::types;
2 2
3use clang::{EntityKind, Usr}; 3use anyhow::{anyhow, Error, Result};
4use serde_json::{Map, Value as JSONValue}; 4use clang::Usr;
5use serde_json::{json, Map as JSONMap, Value as JSONValue};
5use thiserror::Error; 6use thiserror::Error;
6 7
7use std::collections::BTreeMap; 8use std::collections::BTreeMap;
8use std::convert::TryFrom; 9use 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)]
13pub(super) enum ClangEntityKind { 12pub(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)]
24pub(super) enum VariableKind {
25 Variable, 14 Variable,
26 Field,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub(super) enum StructKind {
31 Struct, 15 Struct,
32 Class,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub(super) enum FunctionKind {
37 Function, 16 Function,
38 Method, 17 Enum,
39} 18 EnumConstant,
40 19 TypeAlias,
41impl 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)]
75pub(super) struct TryFromEntityKindError(String); 24pub(super) struct TryFromEntityKindError(String);
76 25
77impl TryFrom<EntityKind> for ClangEntityKind { 26impl 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)]
106pub(super) struct PartialEntity { 54pub(super) struct Description {
107 properties: Map<String, JSONValue>, 55 name: String,
108 children: Children, 56 brief: String,
57 detailed: String,
109} 58}
110 59
111pub(super) trait ClangEntity { 60impl<'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)]
86pub(super) struct Described<T> {
87 pub description: Description,
88 pub entity: T,
89}
90
91type DescribedDynEntity = Described<DynEntity>;
92
93impl<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
119impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T>
120where
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
133impl<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)]
151pub(super) struct DescribedRef<'a, T> {
152 pub description: &'a Description,
153 pub entity: T,
154}
155
156type DescribedDynEntityRef<'d, 'e> = DescribedRef<'d, DynEntityRef<'e>>;
157
134/* 158/*
135pub(super) trait FromNamespaceParent: ClangEntity + Sized { 159impl<'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
143pub(super) trait NamespaceParentManipulation<T: ClangEntity + Sized> { 169#[derive(Debug, Clone)]
144 fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<T>>>; 170pub(super) struct DescribedRefMut<'a, T> {
171 pub description: &'a Description,
172 pub entity: T,
145} 173}
146 174
147impl<U> NamespaceParentManipulation<Namespace> for U 175type DescribedDynEntityRefMut<'a, 'b> = DescribedRefMut<'a, DynEntityRefMut<'b>>;
148where 176
149 U: ClangEntity, 177impl<'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
156impl<U> NamespaceParentManipulation<Variable> for U 186pub(super) trait Entity: Traversable + KindName {
157where 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
165impl<U> NamespaceParentManipulation<Function> for U 198 /// Transform a generic entity to a specific entity
166where 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
174impl<U> NamespaceParentManipulation<Struct> for U 219pub(super) trait Traversable {
175where 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
183impl<U> NamespaceParentManipulation<Typedef> for U 230pub(super) trait KindName {
184where 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
192impl<U> NamespaceParentManipulation<Enum> for U 235#[derive(Debug)]
193where 236pub(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
201fn entity_id(usr: Usr) -> EntityId { 241fn 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
209fn append_children<T: ClangEntity + Into<PartialEntity>>( 258macro_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
222impl<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)]
240pub(super) struct Description { 425pub(super) struct TopLevel(Described<Namespace>);
241 pub(super) name: String, 426
242 pub(super) brief: String, 427impl 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)] 440impl From<TopLevel> for types::Entity {
247pub(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
253pub(super) struct Namespace { 447#[derive(Debug)]
254 pub(super) member_namespaces: BTreeMap<Usr, Described<Namespace>>, 448pub(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)]
458pub(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
262impl ClangEntity for Namespace { 467impl 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)]
614pub(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)]
625pub(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/*
288impl FromNamespaceParent for Namespace { 636impl<'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
298impl From<Namespace> for PartialEntity { 654#[derive(Debug)]
299 fn from(entity: Namespace) -> Self { 655pub(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(), 665impl<'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
316pub(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
321impl ClangEntity for Variable { 697impl<'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
327impl From<Variable> for PartialEntity { 713#[derive(Debug, Clone, Copy, PartialEq, Eq)]
328 fn from(entity: Variable) -> Self { 714struct 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(), 719pub(super) enum TryFromClassMemberPropsError {
334 } 720 #[error("Failed to get accessibility status")]
721 Accessibility,
722}
723
724impl 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/* 734impl From<ClassMemberProperties> for JSONMap<String, JSONValue> {
339impl 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// =================
350pub(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>>, 753entity! {
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
360impl ClangEntity for Struct { 769impl 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>>> { 778impl 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
797impl 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
811impl<'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)]
834enum VariableKind {
835 Variable,
836 Field {
837 member_properties: ClassMemberProperties,
838 },
839}
840
841entity! {
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
382impl From<Struct> for PartialEntity { 855impl 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/* 871impl<'a> TryFrom<clang::Entity<'a>> for Variable {
399impl 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// ==============
410pub(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)]
905pub(super) enum StructKind {
906 Struct,
907 Class,
414} 908}
415 909
416impl ClangEntity for Function { 910entity! {
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
422impl From<Function> for PartialEntity { 923impl 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
939impl<'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// ================
442impl 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>> { 1040pub(super) enum FunctionKind {
447 parent.entity.member_functions.get_mut(name) 1041 Function,
1042 Method,
1043}
1044
1045entity! {
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)]
453pub(super) struct FunctionArgument { 1054pub(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
458impl From<FunctionArgument> for JSONValue { 1059impl 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)] 1075impl<'a> TryFrom<clang::Entity<'a>> for Function {
468pub(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
472impl ClangEntity for Typedef { 1124// ============
473 fn kind(&self) -> ClangEntityKind { 1125// === Enum ===
474 ClangEntityKind::Typedef 1126// ============
1127
1128entity! {
1129 pub(super) struct Enum {
1130 underlying_type: String,
1131 #children => [
1132 constants: EnumConstant,
1133 ],
475 } 1134 }
476} 1135}
477 1136
478impl From<Typedef> for PartialEntity { 1137impl 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 { 1147impl<'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// ======================
491pub(super) struct Enum { 1186// === Enum Constants ===
492 pub(super) underlying_type: String, 1187// ======================
493 pub(super) constants: BTreeMap<Usr, Described<EnumConstant>>, 1188
1189entity! {
1190 pub(super) struct EnumConstant {
1191 value: String,
1192 }
494} 1193}
495 1194
496impl ClangEntity for Enum { 1195impl 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
502impl From<Enum> for PartialEntity { 1205impl<'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 { 1242entity! {
514 properties, 1243 pub(super) struct TypeAlias {
515 children, 1244 referee: String,
516 }
517 } 1245 }
518} 1246}
519 1247
520#[derive(Debug, Clone)] 1248impl KindName for TypeAlias {
521pub(super) struct EnumConstant { 1249 fn kind_name_singular(&self) -> &'static str {
522 pub(super) value: String, 1250 "type alias"
523} 1251 }
524 1252
525impl 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
531impl From<EnumConstant> for PartialEntity { 1258impl<'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 @@
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 {
diff --git a/src/types.rs b/src/types.rs
index 4099714..33a86c6 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -13,7 +13,7 @@ use std::str::FromStr;
13#[non_exhaustive] 13#[non_exhaustive]
14pub struct Poseidoc { 14pub struct Poseidoc {
15 pub config: toml::Value, 15 pub config: toml::Value,
16 pub entities: BTreeMap<String, Entity>, 16 pub toplevel_entity: Entity,
17} 17}
18 18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] 19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]