summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.rs7
-rw-r--r--src/main.rs21
-rw-r--r--src/parser/clang/entities.rs55
-rw-r--r--src/parser/clang/mod.rs2
-rw-r--r--src/parser/clang/parsing.rs282
5 files changed, 275 insertions, 92 deletions
diff --git a/src/cli.rs b/src/cli.rs
index 0000644..946ebc9 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -5,6 +5,7 @@ use structopt::StructOpt;
5use std::path::PathBuf; 5use std::path::PathBuf;
6 6
7#[derive(Debug, Clone, StructOpt)] 7#[derive(Debug, Clone, StructOpt)]
8#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
8pub(crate) struct Cli { 9pub(crate) struct Cli {
9 #[structopt(long, short, parse(from_occurrences))] 10 #[structopt(long, short, parse(from_occurrences))]
10 pub(crate) verbosity: u8, 11 pub(crate) verbosity: u8,
@@ -22,9 +23,11 @@ pub(crate) struct Cli {
22#[derive(Debug, Clone, StructOpt)] 23#[derive(Debug, Clone, StructOpt)]
23pub(crate) enum Command { 24pub(crate) enum Command {
24 Generate { 25 Generate {
25 file: String, 26 file: Option<String>,
27 },
28 Inspect {
29 file: Option<String>,
26 }, 30 },
27 Inspect,
28 Config { 31 Config {
29 #[structopt(subcommand)] 32 #[structopt(subcommand)]
30 command: ConfigCommand, 33 command: ConfigCommand,
diff --git a/src/main.rs b/src/main.rs
index 5c613e0..5a0b175 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
1#![deny(unsafe_code)]
1#![warn(clippy::all)] 2#![warn(clippy::all)]
2 3
3mod cli; 4mod cli;
@@ -83,19 +84,27 @@ fn start(codemap: &mut CodeMap) -> Result<()> {
83 .with_context(|| format!("Cannot change current directory to: {:?}", cli.directory))?; 84 .with_context(|| format!("Cannot change current directory to: {:?}", cli.directory))?;
84 85
85 match &cli.command { 86 match &cli.command {
86 Command::Generate { file: _ } => { 87 Command::Generate { file } => {
87 //let file = file.clone(); 88 let file = file.clone();
88 let config = load_effective_config(cli, codemap)?; 89 let config = load_effective_config(cli, codemap)?;
89 90
90 let entities = parser::clang::parse_compile_commands(&config.clang, codemap)?; 91 let entities = if let Some(file) = file {
91 //let manager = parse_file(file, &config.extra_clang_args); 92 parser::clang::parse_file(file, &config.clang, codemap)?
93 } else {
94 parser::clang::parse_compile_commands(&config.clang, codemap)?
95 };
92 96
93 let base_output_dir = std::path::Path::new("doc"); 97 let base_output_dir = std::path::Path::new("doc");
94 generate(&base_output_dir, entities, &config.generator)?; 98 generate(&base_output_dir, entities, &config.generator)?;
95 } 99 }
96 Command::Inspect => { 100 Command::Inspect { file } => {
101 let file = file.clone();
97 let config = load_effective_config(cli, codemap)?; 102 let config = load_effective_config(cli, codemap)?;
98 let entities = parser::clang::parse_compile_commands(&config.clang, codemap)?; 103 let entities = if let Some(file) = file {
104 parser::clang::parse_file(file, &config.clang, codemap)?
105 } else {
106 parser::clang::parse_compile_commands(&config.clang, codemap)?
107 };
99 serde_json::to_writer_pretty(std::io::stdout().lock(), &entities)?; 108 serde_json::to_writer_pretty(std::io::stdout().lock(), &entities)?;
100 } 109 }
101 Command::Config { 110 Command::Config {
diff --git a/src/parser/clang/entities.rs b/src/parser/clang/entities.rs
index cbc17b7..a5b6462 100644
--- a/src/parser/clang/entities.rs
+++ b/src/parser/clang/entities.rs
@@ -14,6 +14,7 @@ pub(super) struct Children {
14 variables: Option<BTreeMap<Usr, Described<Variable>>>, 14 variables: Option<BTreeMap<Usr, Described<Variable>>>,
15 structs: Option<BTreeMap<Usr, Described<Struct>>>, 15 structs: Option<BTreeMap<Usr, Described<Struct>>>,
16 functions: Option<BTreeMap<Usr, Described<Function>>>, 16 functions: Option<BTreeMap<Usr, Described<Function>>>,
17 typedefs: Option<BTreeMap<Usr, Described<Typedef>>>,
17} 18}
18 19
19#[derive(Debug, Clone, Copy, PartialEq, Eq)] 20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -22,6 +23,7 @@ pub(super) enum ClangEntityKind {
22 Variable(VariableKind), 23 Variable(VariableKind),
23 Struct(StructKind), 24 Struct(StructKind),
24 Function(FunctionKind), 25 Function(FunctionKind),
26 Typedef,
25} 27}
26 28
27#[derive(Debug, Clone, Copy, PartialEq, Eq)] 29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -52,6 +54,7 @@ impl ClangEntityKind {
52 ClangEntityKind::Struct(StructKind::Class) => "class", 54 ClangEntityKind::Struct(StructKind::Class) => "class",
53 ClangEntityKind::Function(FunctionKind::Function) => "function", 55 ClangEntityKind::Function(FunctionKind::Function) => "function",
54 ClangEntityKind::Function(FunctionKind::Method) => "method", 56 ClangEntityKind::Function(FunctionKind::Method) => "method",
57 ClangEntityKind::Typedef => "typedef",
55 } 58 }
56 } 59 }
57 60
@@ -64,6 +67,7 @@ impl ClangEntityKind {
64 ClangEntityKind::Struct(StructKind::Class) => "classes", 67 ClangEntityKind::Struct(StructKind::Class) => "classes",
65 ClangEntityKind::Function(FunctionKind::Function) => "functions", 68 ClangEntityKind::Function(FunctionKind::Function) => "functions",
66 ClangEntityKind::Function(FunctionKind::Method) => "methods", 69 ClangEntityKind::Function(FunctionKind::Method) => "methods",
70 ClangEntityKind::Typedef => "typedefs",
67 } 71 }
68 } 72 }
69} 73}
@@ -80,12 +84,19 @@ impl TryFrom<EntityKind> for ClangEntityKind {
80 EntityKind::Namespace => ClangEntityKind::Namespace, 84 EntityKind::Namespace => ClangEntityKind::Namespace,
81 EntityKind::VarDecl => ClangEntityKind::Variable(VariableKind::Variable), 85 EntityKind::VarDecl => ClangEntityKind::Variable(VariableKind::Variable),
82 EntityKind::FieldDecl => ClangEntityKind::Variable(VariableKind::Field), 86 EntityKind::FieldDecl => ClangEntityKind::Variable(VariableKind::Field),
83 EntityKind::FunctionDecl => ClangEntityKind::Function(FunctionKind::Function), 87 EntityKind::FunctionDecl | EntityKind::FunctionTemplate => {
84 EntityKind::Method | EntityKind::Constructor => { 88 ClangEntityKind::Function(FunctionKind::Function)
89 }
90 EntityKind::Method | EntityKind::Constructor | EntityKind::Destructor => {
85 ClangEntityKind::Function(FunctionKind::Method) 91 ClangEntityKind::Function(FunctionKind::Method)
86 } 92 }
87 EntityKind::StructDecl => ClangEntityKind::Struct(StructKind::Struct), 93 EntityKind::StructDecl => ClangEntityKind::Struct(StructKind::Struct),
88 EntityKind::ClassDecl => ClangEntityKind::Struct(StructKind::Class), 94 EntityKind::ClassDecl | EntityKind::ClassTemplate => {
95 ClangEntityKind::Struct(StructKind::Class)
96 }
97 EntityKind::TypedefDecl
98 | EntityKind::TypeAliasDecl
99 | EntityKind::TypeAliasTemplateDecl => ClangEntityKind::Typedef,
89 kind => return Err(TryFromEntityKindError(format!("{:?}", kind))), 100 kind => return Err(TryFromEntityKindError(format!("{:?}", kind))),
90 }) 101 })
91 } 102 }
@@ -106,6 +117,9 @@ pub(super) trait ClangEntity {
106 fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { 117 fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> {
107 None 118 None
108 } 119 }
120 fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> {
121 None
122 }
109 123
110 fn into_children(self) -> Children 124 fn into_children(self) -> Children
111 where 125 where
@@ -116,6 +130,7 @@ pub(super) trait ClangEntity {
116 variables: None, 130 variables: None,
117 structs: None, 131 structs: None,
118 functions: None, 132 functions: None,
133 typedefs: None,
119 } 134 }
120 } 135 }
121} 136}
@@ -169,12 +184,23 @@ where
169 } 184 }
170} 185}
171 186
187impl<U> NamespaceParentManipulation<Typedef> for U
188where
189 U: ClangEntity,
190{
191 fn get_members_mut(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> {
192 self.get_member_typedefs()
193 }
194}
195
172fn entity_id(usr: Usr) -> EntityId { 196fn entity_id(usr: Usr) -> EntityId {
173 // This is a somewhat ugly workaround, because Pandoc parses markdown identifiers as alphanum 197 // This is a somewhat ugly workaround, because Pandoc parses markdown identifiers as alphanum
174 // or one of "-_:.", which means Pandoc can't parse libclang's USRs in title ids and related. 198 // or one of "-_:.", which means Pandoc can't parse libclang's USRs in title ids and related.
175 // 199 //
176 // <https://github.com/jgm/pandoc/blob/2.9/src/Text/Pandoc/Readers/Markdown.hs#L581> 200 // <https://github.com/jgm/pandoc/blob/2.9/src/Text/Pandoc/Readers/Markdown.hs#L581>
177 EntityId(usr.0.replace("@", "::").replace("#", ".").replace("$", "-")) 201 EntityId(
202 usr.0.replace("@", "::").replace("#", ".").replace("$", "-")
203 )
178} 204}
179 205
180fn append_children<T: ClangEntity>( 206fn append_children<T: ClangEntity>(
@@ -243,6 +269,7 @@ pub(super) struct Namespace {
243 pub(super) member_variables: BTreeMap<Usr, Described<Variable>>, 269 pub(super) member_variables: BTreeMap<Usr, Described<Variable>>,
244 pub(super) member_structs: BTreeMap<Usr, Described<Struct>>, 270 pub(super) member_structs: BTreeMap<Usr, Described<Struct>>,
245 pub(super) member_functions: BTreeMap<Usr, Described<Function>>, 271 pub(super) member_functions: BTreeMap<Usr, Described<Function>>,
272 pub(super) member_typedefs: BTreeMap<Usr, Described<Typedef>>,
246} 273}
247 274
248impl ClangEntity for Namespace { 275impl ClangEntity for Namespace {
@@ -262,6 +289,9 @@ impl ClangEntity for Namespace {
262 fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { 289 fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> {
263 Some(&mut self.member_functions) 290 Some(&mut self.member_functions)
264 } 291 }
292 fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> {
293 Some(&mut self.member_typedefs)
294 }
265 295
266 fn into_children(self) -> Children { 296 fn into_children(self) -> Children {
267 Children { 297 Children {
@@ -269,6 +299,7 @@ impl ClangEntity for Namespace {
269 variables: Some(self.member_variables), 299 variables: Some(self.member_variables),
270 structs: Some(self.member_structs), 300 structs: Some(self.member_structs),
271 functions: Some(self.member_functions), 301 functions: Some(self.member_functions),
302 typedefs: Some(self.member_typedefs),
272 } 303 }
273 } 304 }
274} 305}
@@ -314,6 +345,7 @@ pub(super) struct Struct {
314 pub(super) member_variables: BTreeMap<Usr, Described<Variable>>, 345 pub(super) member_variables: BTreeMap<Usr, Described<Variable>>,
315 pub(super) member_structs: BTreeMap<Usr, Described<Struct>>, 346 pub(super) member_structs: BTreeMap<Usr, Described<Struct>>,
316 pub(super) member_functions: BTreeMap<Usr, Described<Function>>, 347 pub(super) member_functions: BTreeMap<Usr, Described<Function>>,
348 pub(super) member_typedefs: BTreeMap<Usr, Described<Typedef>>,
317} 349}
318 350
319impl ClangEntity for Struct { 351impl ClangEntity for Struct {
@@ -330,6 +362,9 @@ impl ClangEntity for Struct {
330 fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> { 362 fn get_member_functions(&mut self) -> Option<&mut BTreeMap<Usr, Described<Function>>> {
331 Some(&mut self.member_functions) 363 Some(&mut self.member_functions)
332 } 364 }
365 fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap<Usr, Described<Typedef>>> {
366 Some(&mut self.member_typedefs)
367 }
333 368
334 fn into_children(self) -> Children { 369 fn into_children(self) -> Children {
335 Children { 370 Children {
@@ -337,6 +372,7 @@ impl ClangEntity for Struct {
337 variables: Some(self.member_variables), 372 variables: Some(self.member_variables),
338 structs: Some(self.member_structs), 373 structs: Some(self.member_structs),
339 functions: Some(self.member_functions), 374 functions: Some(self.member_functions),
375 typedefs: Some(self.member_typedefs),
340 } 376 }
341 } 377 }
342} 378}
@@ -381,3 +417,14 @@ pub(super) struct FunctionArgument {
381 pub(super) name: String, 417 pub(super) name: String,
382 pub(super) r#type: String, 418 pub(super) r#type: String,
383} 419}
420
421#[derive(Debug, Clone)]
422pub(super) struct Typedef {
423 pub(super) referee: String,
424}
425
426impl ClangEntity for Typedef {
427 fn kind(&self) -> ClangEntityKind {
428 ClangEntityKind::Typedef
429 }
430}
diff --git a/src/parser/clang/mod.rs b/src/parser/clang/mod.rs
index 047c49e..da49462 100644
--- a/src/parser/clang/mod.rs
+++ b/src/parser/clang/mod.rs
@@ -2,4 +2,4 @@ pub(crate) mod config;
2mod entities; 2mod entities;
3mod parsing; 3mod parsing;
4 4
5pub(crate) use parsing::parse_compile_commands; 5pub(crate) use parsing::{parse_compile_commands, parse_file};
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;
11use std::convert::{TryFrom, TryInto}; 11use std::convert::{TryFrom, TryInto};
12use std::path::{Path, PathBuf}; 12use 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)]
15struct TopLevel { 17struct 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
188impl 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/*
179trait FromTopLevel: ClangEntity + Sized { 195trait 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/* 299pub(crate) fn parse_file<T>(
308pub(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>>
309where 304where
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
349fn parse_unit( 368fn 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
547impl 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
515impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T> 581impl<'a, T> TryFrom<clang::Entity<'a>> for Described<T>
516where 582where
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
761impl<'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
657fn get_description(entity: clang::Entity) -> Result<Description> { 781fn get_description(entity: clang::Entity) -> Result<Description> {
658 let name = entity 782 let name = entity
659 .get_display_name() 783 .get_display_name()