diff options
Diffstat (limited to 'src/parser/clang/parsing.rs')
-rw-r--r-- | src/parser/clang/parsing.rs | 282 |
1 files changed, 203 insertions, 79 deletions
diff --git a/src/parser/clang/parsing.rs b/src/parser/clang/parsing.rs index a654681..1f1691f 100644 --- a/src/parser/clang/parsing.rs +++ b/src/parser/clang/parsing.rs | |||
@@ -11,12 +11,15 @@ use std::collections::BTreeMap; | |||
11 | use std::convert::{TryFrom, TryInto}; | 11 | use std::convert::{TryFrom, TryInto}; |
12 | use std::path::{Path, PathBuf}; | 12 | use std::path::{Path, PathBuf}; |
13 | 13 | ||
14 | // TODO: check for use of Extend instead of loop+insert | ||
15 | |||
14 | #[derive(Debug, Default)] | 16 | #[derive(Debug, Default)] |
15 | struct TopLevel { | 17 | struct TopLevel { |
16 | namespaces: BTreeMap<Usr, Described<Namespace>>, | 18 | namespaces: BTreeMap<Usr, Described<Namespace>>, |
17 | variables: BTreeMap<Usr, Described<Variable>>, | 19 | variables: BTreeMap<Usr, Described<Variable>>, |
18 | structs: BTreeMap<Usr, Described<Struct>>, | 20 | structs: BTreeMap<Usr, Described<Struct>>, |
19 | functions: BTreeMap<Usr, Described<Function>>, | 21 | functions: BTreeMap<Usr, Described<Function>>, |
22 | typedefs: BTreeMap<Usr, Described<Typedef>>, | ||
20 | } | 23 | } |
21 | 24 | ||
22 | /* | 25 | /* |
@@ -82,6 +85,9 @@ impl TopLevel { | |||
82 | ClangEntityKind::Struct(_) => { | 85 | ClangEntityKind::Struct(_) => { |
83 | &mut parent.get_member_structs()?.get_mut(&usr)?.entity | 86 | &mut parent.get_member_structs()?.get_mut(&usr)?.entity |
84 | } | 87 | } |
88 | ClangEntityKind::Typedef => { | ||
89 | &mut parent.get_member_typedefs()?.get_mut(&usr)?.entity | ||
90 | } | ||
85 | }) | 91 | }) |
86 | } else { | 92 | } else { |
87 | Some(match path.get_kind().try_into().ok()? { | 93 | Some(match path.get_kind().try_into().ok()? { |
@@ -89,6 +95,7 @@ impl TopLevel { | |||
89 | ClangEntityKind::Variable(_) => &mut self.variables.get_mut(&usr)?.entity, | 95 | ClangEntityKind::Variable(_) => &mut self.variables.get_mut(&usr)?.entity, |
90 | ClangEntityKind::Struct(_) => &mut self.structs.get_mut(&usr)?.entity, | 96 | ClangEntityKind::Struct(_) => &mut self.structs.get_mut(&usr)?.entity, |
91 | ClangEntityKind::Function(_) => &mut self.functions.get_mut(&usr)?.entity, | 97 | ClangEntityKind::Function(_) => &mut self.functions.get_mut(&usr)?.entity, |
98 | ClangEntityKind::Typedef => &mut self.typedefs.get_mut(&usr)?.entity, | ||
92 | }) | 99 | }) |
93 | } | 100 | } |
94 | } | 101 | } |
@@ -121,7 +128,10 @@ impl TopLevel { | |||
121 | .insert(usr, entity); | 128 | .insert(usr, entity); |
122 | Ok(()) | 129 | Ok(()) |
123 | } else { | 130 | } else { |
124 | Err(anyhow!("has parent but no parent in tree")) | 131 | Err(anyhow!( |
132 | "has parent: {:?} but no parent in tree", | ||
133 | parent_path | ||
134 | )) | ||
125 | } | 135 | } |
126 | } else { | 136 | } else { |
127 | self.insert_toplevel(usr, entity); | 137 | self.insert_toplevel(usr, entity); |
@@ -175,6 +185,12 @@ impl TopLevelManipulation<Struct> for TopLevel { | |||
175 | } | 185 | } |
176 | } | 186 | } |
177 | 187 | ||
188 | impl TopLevelManipulation<Typedef> for TopLevel { | ||
189 | fn insert_toplevel(&mut self, usr: Usr, entity: Described<Typedef>) { | ||
190 | self.typedefs.insert(usr, entity); | ||
191 | } | ||
192 | } | ||
193 | |||
178 | /* | 194 | /* |
179 | trait FromTopLevel: ClangEntity + Sized { | 195 | trait FromTopLevel: ClangEntity + Sized { |
180 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>>; | 196 | fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described<Self>>; |
@@ -268,7 +284,7 @@ pub(crate) fn parse_compile_commands( | |||
268 | &codemap, | 284 | &codemap, |
269 | )?; | 285 | )?; |
270 | 286 | ||
271 | trace!("Changing directory to: {:?}", directory); | 287 | trace!("Changing directory to: {:?}", toplevel_directory); |
272 | std::env::set_current_dir(&toplevel_directory).with_context(|| { | 288 | std::env::set_current_dir(&toplevel_directory).with_context(|| { |
273 | format!( | 289 | format!( |
274 | "Cannot change current directory to: {:?}", | 290 | "Cannot change current directory to: {:?}", |
@@ -277,74 +293,77 @@ pub(crate) fn parse_compile_commands( | |||
277 | })?; | 293 | })?; |
278 | } | 294 | } |
279 | 295 | ||
280 | let normalized_entities = entities | 296 | Ok(entities.into()) |
281 | .namespaces | ||
282 | .into_iter() | ||
283 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())) | ||
284 | .chain( | ||
285 | entities | ||
286 | .variables | ||
287 | .into_iter() | ||
288 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
289 | ) | ||
290 | .chain( | ||
291 | entities | ||
292 | .structs | ||
293 | .into_iter() | ||
294 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
295 | ) | ||
296 | .chain( | ||
297 | entities | ||
298 | .functions | ||
299 | .into_iter() | ||
300 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
301 | ) | ||
302 | .collect(); | ||
303 | |||
304 | Ok(normalized_entities) | ||
305 | } | 297 | } |
306 | 298 | ||
307 | /* | 299 | pub(crate) fn parse_file<T>( |
308 | pub(crate) fn parse_file<T, S>(path: T, extra_args: &[S]) -> EntitiesManager | 300 | path: T, |
301 | config: &Config, | ||
302 | codemap: &mut CodeMap, | ||
303 | ) -> Result<BTreeMap<EntityId, Entity>> | ||
309 | where | 304 | where |
310 | T: Into<PathBuf>, | 305 | T: Into<PathBuf>, |
311 | T: AsRef<Path>, | 306 | T: AsRef<Path>, |
312 | T: ToString, | 307 | T: ToString, |
313 | S: AsRef<str>, | ||
314 | S: std::fmt::Debug, | ||
315 | { | 308 | { |
316 | let mut codemap = CodeMap::new(); | ||
317 | let file_map = codemap.add_file(path.to_string(), std::fs::read_to_string(&path).unwrap()); | ||
318 | let file_span = file_map.span; | ||
319 | |||
320 | let clang = Clang::new().unwrap(); | 309 | let clang = Clang::new().unwrap(); |
321 | let index = Index::new(&clang, true, false); | 310 | let index = Index::new(&clang, true, false); |
322 | let mut parser = index.parser(path); | ||
323 | parser.skip_function_bodies(true); | ||
324 | 311 | ||
325 | parser.arguments(&extra_args); | 312 | // as provided in the command line |
313 | let filename = path.to_string(); | ||
314 | let file_map = codemap.add_file(filename.clone(), std::fs::read_to_string(&path)?); | ||
326 | 315 | ||
327 | if log_enabled!(log::Level::Debug) { | 316 | let path = path.as_ref().canonicalize()?; |
328 | for extra_arg in extra_args { | 317 | let toplevel_directory = std::env::current_dir().context("Cannot read current directory")?; |
329 | debug!("Extra libclang argument: {:?}", extra_arg); | 318 | |
330 | } | 319 | let maybe_commands = CompilationDatabase::from_directory(&config.compile_commands_location) |
320 | .and_then(|database| database.get_compile_commands(&path)) | ||
321 | .ok(); | ||
322 | let maybe_command = maybe_commands | ||
323 | .as_ref() | ||
324 | .and_then(|commands| commands.get_commands().pop()); | ||
325 | |||
326 | let mut clang_arguments = maybe_command | ||
327 | .map(|command| command.get_arguments()) | ||
328 | .unwrap_or_default(); | ||
329 | clang_arguments.extend_from_slice(&config.extra_args); | ||
330 | |||
331 | if let Some(command) = maybe_command { | ||
332 | let directory = command.get_directory(); | ||
333 | trace!("Changing directory to: {:?}", directory); | ||
334 | std::env::set_current_dir(&directory) | ||
335 | .with_context(|| format!("Cannot change current directory to: {:?}", directory))?; | ||
331 | } | 336 | } |
332 | 337 | ||
333 | let trans_unit = parser.parse().unwrap(); | 338 | let mut parser = index.parser(""); |
334 | let mut entities = EntitiesManager::new(); | 339 | parser.skip_function_bodies(true); |
340 | |||
341 | parser.arguments(&clang_arguments); | ||
342 | |||
343 | trace!("Parsing with libclang arguments: {:?}", clang_arguments); | ||
344 | |||
345 | let mut entities = TopLevel::default(); | ||
335 | 346 | ||
336 | parse_unit( | 347 | parse_unit( |
337 | &trans_unit, | 348 | &parser |
349 | .parse() | ||
350 | .with_context(|| format!("Could not parse file: {:?}", filename))?, | ||
338 | &mut entities, | 351 | &mut entities, |
339 | &std::env::current_dir().unwrap(), | 352 | &toplevel_directory, |
340 | file_span, | 353 | file_map.span, |
341 | &codemap, | 354 | &codemap, |
342 | ) | 355 | )?; |
343 | .unwrap(); | ||
344 | 356 | ||
345 | entities | 357 | trace!("Changing directory to: {:?}", toplevel_directory); |
358 | std::env::set_current_dir(&toplevel_directory).with_context(|| { | ||
359 | format!( | ||
360 | "Cannot change current directory to: {:?}", | ||
361 | toplevel_directory | ||
362 | ) | ||
363 | })?; | ||
364 | |||
365 | Ok(entities.into()) | ||
346 | } | 366 | } |
347 | */ | ||
348 | 367 | ||
349 | fn parse_unit( | 368 | fn parse_unit( |
350 | trans_unit: &TranslationUnit, | 369 | trans_unit: &TranslationUnit, |
@@ -355,10 +374,7 @@ fn parse_unit( | |||
355 | ) -> Result<()> { | 374 | ) -> Result<()> { |
356 | trans_unit.get_entity().visit_children(|entity, _parent| { | 375 | trans_unit.get_entity().visit_children(|entity, _parent| { |
357 | if is_in_system_header(entity, &base_dir) { | 376 | if is_in_system_header(entity, &base_dir) { |
358 | trace!( | 377 | trace!("Entity is in system header, skipping: {:?}", entity); |
359 | "Entity is in system header, skipping: USR = {:?}", | ||
360 | entity.get_display_name() | ||
361 | ); | ||
362 | return clang::EntityVisitResult::Continue; | 378 | return clang::EntityVisitResult::Continue; |
363 | } | 379 | } |
364 | 380 | ||
@@ -374,12 +390,13 @@ fn parse_unit( | |||
374 | add_entity(entity, entities, file_span, codemap) | 390 | add_entity(entity, entities, file_span, codemap) |
375 | }); | 391 | }); |
376 | 392 | ||
377 | /* | ||
378 | use codemap_diagnostic::{ColorConfig, Emitter}; | 393 | use codemap_diagnostic::{ColorConfig, Emitter}; |
379 | 394 | ||
380 | let mut emitter = Emitter::stderr(ColorConfig::Auto, Some(&codemap)); | 395 | let mut emitter = Emitter::stderr(ColorConfig::Auto, Some(&codemap)); |
381 | 396 | ||
382 | for diagnostic in trans_unit.get_diagnostics().iter() { | 397 | for diagnostic in trans_unit.get_diagnostics().iter() { |
398 | warn!("{}", diagnostic); | ||
399 | /* | ||
383 | let main_diag = match clang_diag_to_codemap_diag(&diagnostic, file_span) { | 400 | let main_diag = match clang_diag_to_codemap_diag(&diagnostic, file_span) { |
384 | Some(diag) => diag, | 401 | Some(diag) => diag, |
385 | None => continue, | 402 | None => continue, |
@@ -401,8 +418,8 @@ fn parse_unit( | |||
401 | .chain(fix_it_diags) | 418 | .chain(fix_it_diags) |
402 | .collect::<Vec<_>>(), | 419 | .collect::<Vec<_>>(), |
403 | ); | 420 | ); |
421 | */ | ||
404 | } | 422 | } |
405 | */ | ||
406 | 423 | ||
407 | Ok(()) | 424 | Ok(()) |
408 | } | 425 | } |
@@ -412,11 +429,12 @@ fn is_in_system_header(entity: clang::Entity, base_dir: impl AsRef<Path>) -> boo | |||
412 | true | 429 | true |
413 | } else if let Some(location) = entity.get_location() { | 430 | } else if let Some(location) = entity.get_location() { |
414 | if let Some(file) = location.get_file_location().file { | 431 | if let Some(file) = location.get_file_location().file { |
415 | !file | 432 | // !file |
416 | .get_path() | 433 | // .get_path() |
417 | .canonicalize() | 434 | // .canonicalize() |
418 | .unwrap() | 435 | // .unwrap() |
419 | .starts_with(base_dir) | 436 | // .starts_with(base_dir) |
437 | false | ||
420 | } else { | 438 | } else { |
421 | // Not defined in a file? probably shouldn't document | 439 | // Not defined in a file? probably shouldn't document |
422 | true | 440 | true |
@@ -481,7 +499,8 @@ fn add_entity( | |||
481 | // if current.has_documentation && !tree.has_documentation { | 499 | // if current.has_documentation && !tree.has_documentation { |
482 | // append_documentation | 500 | // append_documentation |
483 | // } | 501 | // } |
484 | } else if libclang_entity.is_definition() { | 502 | } else { |
503 | //if libclang_entity.is_definition() { | ||
485 | // TODO: This probably means that you can't put documentation in forward declarations. | 504 | // TODO: This probably means that you can't put documentation in forward declarations. |
486 | // TODO: Ad-hoc toplevel functions are not documented | 505 | // TODO: Ad-hoc toplevel functions are not documented |
487 | // | 506 | // |
@@ -492,19 +511,32 @@ fn add_entity( | |||
492 | // when we see the definition. | 511 | // when we see the definition. |
493 | 512 | ||
494 | let result = match kind { | 513 | let result = match kind { |
495 | ClangEntityKind::Namespace => Described::<Namespace>::try_from(libclang_entity) | 514 | ClangEntityKind::Namespace => { |
496 | .and_then(|namespace| toplevel.insert(libclang_entity, namespace)), | 515 | if libclang_entity.get_name().is_some() { |
516 | Described::<Namespace>::try_from(libclang_entity) | ||
517 | .and_then(|namespace| toplevel.insert(libclang_entity, namespace)) | ||
518 | } else { | ||
519 | Ok(()) | ||
520 | } | ||
521 | } | ||
497 | ClangEntityKind::Variable(_) => Described::<Variable>::try_from(libclang_entity) | 522 | ClangEntityKind::Variable(_) => Described::<Variable>::try_from(libclang_entity) |
498 | .and_then(|variable| toplevel.insert(libclang_entity, variable)), | 523 | .and_then(|variable| toplevel.insert(libclang_entity, variable)), |
499 | ClangEntityKind::Struct(_) => Described::<Struct>::try_from(libclang_entity) | 524 | ClangEntityKind::Struct(_) => Described::<Struct>::try_from(libclang_entity) |
500 | .and_then(|r#struct| toplevel.insert(libclang_entity, r#struct)), | 525 | .and_then(|r#struct| toplevel.insert(libclang_entity, r#struct)), |
501 | ClangEntityKind::Function(_) => Described::<Function>::try_from(libclang_entity) | 526 | ClangEntityKind::Function(_) => Described::<Function>::try_from(libclang_entity) |
502 | .and_then(|function| toplevel.insert(libclang_entity, function)), | 527 | .and_then(|function| toplevel.insert(libclang_entity, function)), |
528 | ClangEntityKind::Typedef => Described::<Typedef>::try_from(libclang_entity) | ||
529 | .and_then(|function| toplevel.insert(libclang_entity, function)), | ||
503 | }; | 530 | }; |
504 | // TODO: check result | 531 | // TODO: check result |
532 | |||
533 | if let Err(err) = result { | ||
534 | error!("{}: {:?}", err, libclang_entity); | ||
535 | return ::clang::EntityVisitResult::Continue; | ||
536 | } | ||
505 | } | 537 | } |
506 | 538 | ||
507 | if kind == ClangEntityKind::Namespace { | 539 | if kind == ClangEntityKind::Namespace && libclang_entity.get_name().is_some() { |
508 | // Recurse here since namespace definitions are allowed to change between translation units. | 540 | // Recurse here since namespace definitions are allowed to change between translation units. |
509 | ::clang::EntityVisitResult::Recurse | 541 | ::clang::EntityVisitResult::Recurse |
510 | } else { | 542 | } else { |
@@ -512,6 +544,40 @@ fn add_entity( | |||
512 | } | 544 | } |
513 | } | 545 | } |
514 | 546 | ||
547 | impl From<TopLevel> for BTreeMap<EntityId, Entity> { | ||
548 | fn from(toplevel: TopLevel) -> Self { | ||
549 | toplevel | ||
550 | .namespaces | ||
551 | .into_iter() | ||
552 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())) | ||
553 | .chain( | ||
554 | toplevel | ||
555 | .variables | ||
556 | .into_iter() | ||
557 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
558 | ) | ||
559 | .chain( | ||
560 | toplevel | ||
561 | .structs | ||
562 | .into_iter() | ||
563 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
564 | ) | ||
565 | .chain( | ||
566 | toplevel | ||
567 | .functions | ||
568 | .into_iter() | ||
569 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
570 | ) | ||
571 | .chain( | ||
572 | toplevel | ||
573 | .typedefs | ||
574 | .into_iter() | ||
575 | .map(|(usr, entity)| (EntityId(usr.0), entity.into())), | ||
576 | ) | ||
577 | .collect() | ||
578 | } | ||
579 | } | ||
580 | |||
515 | impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T> | 581 | impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T> |
516 | where | 582 | where |
517 | T: TryFrom<clang::Entity<'a>, Error = Error>, | 583 | T: TryFrom<clang::Entity<'a>, Error = Error>, |
@@ -544,6 +610,7 @@ impl<'a> TryFrom<clang::Entity<'a>> for Namespace { | |||
544 | member_variables: Default::default(), | 610 | member_variables: Default::default(), |
545 | member_structs: Default::default(), | 611 | member_structs: Default::default(), |
546 | member_functions: Default::default(), | 612 | member_functions: Default::default(), |
613 | member_typedefs: Default::default(), | ||
547 | }) | 614 | }) |
548 | } | 615 | } |
549 | } | 616 | } |
@@ -580,31 +647,65 @@ impl<'a> TryFrom<clang::Entity<'a>> for Struct { | |||
580 | Ok(ClangEntityKind::Struct(kind)) => { | 647 | Ok(ClangEntityKind::Struct(kind)) => { |
581 | struct_kind = kind; | 648 | struct_kind = kind; |
582 | } | 649 | } |
583 | _ => panic!("Trying to parse a non-class into a class"), | 650 | _ => panic!("Trying to parse a non-struct into a struct"), |
584 | } | 651 | } |
585 | debug!("Parsing Struct: {:?}", entity); | 652 | debug!("Parsing Struct: {:?}", entity); |
586 | 653 | ||
587 | let mut member_variables = BTreeMap::new(); | 654 | let mut member_variables = BTreeMap::new(); |
588 | let mut member_structs = BTreeMap::new(); | 655 | let mut member_structs = BTreeMap::new(); |
589 | let mut member_functions = BTreeMap::new(); | 656 | let mut member_functions = BTreeMap::new(); |
657 | let mut member_typedefs = BTreeMap::new(); | ||
590 | 658 | ||
591 | for child in entity.get_children() { | 659 | for child in entity.get_children() { |
592 | trace!("Struct has child: {:?}", child); | 660 | trace!("Struct has child: {:?}", child); |
593 | 661 | ||
594 | match child.get_kind().try_into() { | 662 | let kind = child.get_kind(); |
595 | Ok(ClangEntityKind::Variable(_)) => { | 663 | |
596 | let child_usr = child.get_usr().ok_or_else(|| anyhow!("no usr"))?; | 664 | match kind { |
597 | member_variables.insert(child_usr, Described::<Variable>::try_from(child)?); | 665 | ::clang::EntityKind::AccessSpecifier | ::clang::EntityKind::BaseSpecifier => { |
666 | continue | ||
598 | } | 667 | } |
599 | Ok(ClangEntityKind::Struct(_)) => { | 668 | _ => {} |
600 | let child_usr: Usr = child.get_usr().ok_or_else(|| anyhow!("no usr"))?; | 669 | } |
601 | member_structs.insert(child_usr, Described::<Struct>::try_from(child)?); | 670 | |
671 | let mut parse_child = || -> Result<()> { | ||
672 | match kind.try_into() { | ||
673 | Ok(ClangEntityKind::Variable(_)) => { | ||
674 | let child_usr = child | ||
675 | .get_usr() | ||
676 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
677 | member_variables.insert(child_usr, Described::<Variable>::try_from(child)?); | ||
678 | } | ||
679 | Ok(ClangEntityKind::Struct(_)) => { | ||
680 | let child_usr: Usr = child | ||
681 | .get_usr() | ||
682 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
683 | member_structs.insert(child_usr, Described::<Struct>::try_from(child)?); | ||
684 | } | ||
685 | Ok(ClangEntityKind::Function(_)) => { | ||
686 | let child_usr = child | ||
687 | .get_usr() | ||
688 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
689 | member_functions.insert(child_usr, Described::<Function>::try_from(child)?); | ||
690 | } | ||
691 | Ok(ClangEntityKind::Typedef) => { | ||
692 | let child_usr = child | ||
693 | .get_usr() | ||
694 | .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; | ||
695 | member_typedefs.insert(child_usr, Described::<Typedef>::try_from(child)?); | ||
696 | } | ||
697 | Ok(other) => warn!("Unsupported child of struct {:?}: {:?}", other, child), | ||
698 | Err(err) => info!("Error while parsing entity {:?}: {}", child, err), | ||
602 | } | 699 | } |
603 | Ok(ClangEntityKind::Function(_)) => { | 700 | |
604 | let child_usr = child.get_usr().ok_or_else(|| anyhow!("no usr"))?; | 701 | Ok(()) |
605 | member_functions.insert(child_usr, Described::<Function>::try_from(child)?); | 702 | }; |
703 | |||
704 | match parse_child() { | ||
705 | Ok(()) => {} | ||
706 | Err(err) => { | ||
707 | warn!("Error while parsing child {:?}: {}", child, err); | ||
606 | } | 708 | } |
607 | _ => trace!("Skipping child"), | ||
608 | } | 709 | } |
609 | } | 710 | } |
610 | 711 | ||
@@ -613,6 +714,7 @@ impl<'a> TryFrom<clang::Entity<'a>> for Struct { | |||
613 | member_functions, | 714 | member_functions, |
614 | member_structs, | 715 | member_structs, |
615 | member_variables, | 716 | member_variables, |
717 | member_typedefs, | ||
616 | }) | 718 | }) |
617 | } | 719 | } |
618 | } | 720 | } |
@@ -634,7 +736,9 @@ impl<'a> TryFrom<clang::Entity<'a>> for Function { | |||
634 | trace!("Function has return type: {:?}", return_type); | 736 | trace!("Function has return type: {:?}", return_type); |
635 | let arguments = entity | 737 | let arguments = entity |
636 | .get_arguments() | 738 | .get_arguments() |
637 | .unwrap() | 739 | // TODO: this seems weird, but it fixes a None for a function that takes only a |
740 | // variadic argument from its own template declaration. | ||
741 | .unwrap_or_else(|| vec![]) | ||
638 | .into_iter() | 742 | .into_iter() |
639 | .map(|arg| { | 743 | .map(|arg| { |
640 | let name = arg | 744 | let name = arg |
@@ -654,6 +758,26 @@ impl<'a> TryFrom<clang::Entity<'a>> for Function { | |||
654 | } | 758 | } |
655 | } | 759 | } |
656 | 760 | ||
761 | impl<'a> TryFrom<clang::Entity<'a>> for Typedef { | ||
762 | type Error = Error; | ||
763 | |||
764 | fn try_from(entity: clang::Entity) -> Result<Self, Error> { | ||
765 | match entity.get_kind().try_into() { | ||
766 | Ok(ClangEntityKind::Typedef) => {} | ||
767 | _ => panic!("Trying to parse a non-typedef into a typedef"), | ||
768 | } | ||
769 | debug!("Parsing typedef: {:?}", entity); | ||
770 | |||
771 | // TODO: unwrap (and unwrap in other similar places too) | ||
772 | let referee = entity | ||
773 | .get_typedef_underlying_type() | ||
774 | .ok_or_else(|| anyhow!("No underlying type"))? | ||
775 | .get_display_name(); | ||
776 | |||
777 | Ok(Typedef { referee }) | ||
778 | } | ||
779 | } | ||
780 | |||
657 | fn get_description(entity: clang::Entity) -> Result<Description> { | 781 | fn get_description(entity: clang::Entity) -> Result<Description> { |
658 | let name = entity | 782 | let name = entity |
659 | .get_display_name() | 783 | .get_display_name() |