summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs8
-rw-r--r--src/parser/clang/diagnostics.rs313
-rw-r--r--src/parser/clang/mod.rs1
-rw-r--r--src/parser/clang/parsing.rs102
6 files changed, 336 insertions, 90 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4a11c70..c36fa9d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -306,6 +306,7 @@ dependencies = [
306 "clang 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", 306 "clang 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
307 "codemap 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 307 "codemap 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
308 "codemap-diagnostic 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 308 "codemap-diagnostic 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
309 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
309 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 310 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
310 "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 311 "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
311 "pandoc_types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 312 "pandoc_types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index fe4118d..a2aaa92 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,6 +11,7 @@ anyhow = "1"
11clang = { version = "0.23", features = ["clang_8_0"] } 11clang = { version = "0.23", features = ["clang_8_0"] }
12codemap = "0.1" 12codemap = "0.1"
13codemap-diagnostic = "0.1" 13codemap-diagnostic = "0.1"
14lazy_static = "1"
14log = "0.4" 15log = "0.4"
15num_cpus = "1" 16num_cpus = "1"
16pandoc_types = "0.2" 17pandoc_types = "0.2"
diff --git a/src/main.rs b/src/main.rs
index 5a0b175..254d8d1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -89,9 +89,9 @@ fn start(codemap: &mut CodeMap) -> Result<()> {
89 let config = load_effective_config(cli, codemap)?; 89 let config = load_effective_config(cli, codemap)?;
90 90
91 let entities = if let Some(file) = file { 91 let entities = if let Some(file) = file {
92 parser::clang::parse_file(file, &config.clang, codemap)? 92 parser::clang::parse_file(file, &config.clang)?
93 } else { 93 } else {
94 parser::clang::parse_compile_commands(&config.clang, codemap)? 94 parser::clang::parse_compile_commands(&config.clang)?
95 }; 95 };
96 96
97 let base_output_dir = std::path::Path::new("doc"); 97 let base_output_dir = std::path::Path::new("doc");
@@ -101,9 +101,9 @@ fn start(codemap: &mut CodeMap) -> Result<()> {
101 let file = file.clone(); 101 let file = file.clone();
102 let config = load_effective_config(cli, codemap)?; 102 let config = load_effective_config(cli, codemap)?;
103 let entities = if let Some(file) = file { 103 let entities = if let Some(file) = file {
104 parser::clang::parse_file(file, &config.clang, codemap)? 104 parser::clang::parse_file(file, &config.clang)?
105 } else { 105 } else {
106 parser::clang::parse_compile_commands(&config.clang, codemap)? 106 parser::clang::parse_compile_commands(&config.clang)?
107 }; 107 };
108 serde_json::to_writer_pretty(std::io::stdout().lock(), &entities)?; 108 serde_json::to_writer_pretty(std::io::stdout().lock(), &entities)?;
109 } 109 }
diff --git a/src/parser/clang/diagnostics.rs b/src/parser/clang/diagnostics.rs
new file mode 100644
index 0000000..7aa43be
--- /dev/null
+++ b/src/parser/clang/diagnostics.rs
@@ -0,0 +1,313 @@
1use anyhow::{anyhow, Context, Result};
2use clang::{
3 source::{SourceLocation as ClangSourceLocation, SourceRange as ClangSourceRange},
4 Entity as ClangEntity,
5};
6use codemap::File;
7use codemap_diagnostic::{Diagnostic, Level, SpanLabel};
8use lazy_static::lazy_static;
9
10use std::collections::{hash_map, HashMap};
11use std::path::PathBuf;
12use std::sync::{Arc, RwLock};
13
14lazy_static! {
15 pub(super) static ref CODEMAP: RwLock<CodeMap> = RwLock::new(CodeMap::new());
16}
17
18#[derive(Default)]
19pub(super) struct CodeMap {
20 files: HashMap<PathBuf, Arc<File>>,
21 raw_codemap: codemap::CodeMap,
22}
23
24impl CodeMap {
25 pub fn new() -> Self {
26 Default::default()
27 }
28
29 pub fn span_from_entity(&mut self, entity: ClangEntity) -> Result<codemap::Span> {
30 self.span_from_libclang_range(entity.get_range().ok_or_else(|| {
31 anyhow!("Trying to build a diagnostic from an entity that doesn't have a range")
32 })?)
33 }
34
35 pub fn span_from_libclang_range(&mut self, range: ClangSourceRange) -> Result<codemap::Span> {
36 let start_file_location = range.get_start().get_file_location();
37 let file_name = start_file_location
38 .file
39 .ok_or_else(|| {
40 anyhow!("Trying to build a diagnostic from an entity that isn't located in a file")
41 })?
42 .get_path();
43
44 let file = self.get_file(file_name)?;
45
46 let begin = start_file_location.offset as u64;
47 let end = range.get_end().get_file_location().offset as u64;
48
49 Ok(file.span.subspan(begin, end))
50 }
51
52 pub fn span_from_libclang_location(
53 &mut self,
54 location: ClangSourceLocation,
55 ) -> Result<codemap::Span> {
56 let file_location = location.get_file_location();
57 let file_name = file_location
58 .file
59 .ok_or_else(|| {
60 anyhow!("Trying to build a diagnostic from an entity that isn't located in a file")
61 })?
62 .get_path();
63
64 let file = self.get_file(file_name)?;
65
66 let offset = file_location.offset as u64;
67
68 Ok(file.span.subspan(offset, offset))
69 }
70
71 pub fn get_file(&mut self, file_name: PathBuf) -> Result<&mut Arc<File>> {
72 Ok(match self.files.entry(file_name.clone()) {
73 hash_map::Entry::Occupied(file) => file.into_mut(),
74 hash_map::Entry::Vacant(entry) => {
75 let file = self.raw_codemap.add_file(
76 file_name
77 .to_str()
78 .context("Filename is not valid UTF-8")?
79 .to_owned(),
80 std::fs::read_to_string(&file_name)
81 .with_context(|| format!("Cannot readfile: {:?}", file_name))?,
82 );
83 entry.insert(file)
84 }
85 })
86 }
87
88 pub fn emitter(&self) -> codemap_diagnostic::Emitter {
89 use codemap_diagnostic::{ColorConfig, Emitter};
90 Emitter::stderr(ColorConfig::Auto, Some(&self.raw_codemap))
91 }
92}
93
94#[derive(Debug, Clone)]
95pub(super) struct DiagnosticBuilder {
96 level: Level,
97 message: String,
98 code: Option<String>,
99 spans: Vec<SpanLabel>,
100}
101
102impl DiagnosticBuilder {
103 pub fn new(level: Level, message: String) -> Self {
104 DiagnosticBuilder {
105 level,
106 message,
107 code: None,
108 spans: vec![],
109 }
110 }
111
112 /*
113 pub fn error(message: String) -> Self {
114 Self::new(Level::Error, message)
115 }
116
117 pub fn warning(message: String) -> Self {
118 Self::new(Level::Warning, message)
119 }
120
121 pub fn note(message: String) -> Self {
122 Self::new(Level::Note, message)
123 }
124
125 pub fn help(message: String) -> Self {
126 Self::new(Level::Help, message)
127 }
128
129 pub fn bug(message: String) -> Self {
130 Self::new(Level::Bug, message)
131 }
132
133 pub fn level(&mut self, level: Level) -> &mut Self {
134 self.level = level;
135 self
136 }
137
138 pub fn message(&mut self, message: String) -> &mut Self {
139 self.message = message;
140 self
141 }
142
143 pub fn code(&mut self, code: String) -> &mut Self {
144 self.code = Some(code);
145 self
146 }
147 */
148
149 pub fn span(&mut self, span: SpanLabel) -> &mut Self {
150 self.spans.push(span);
151 self
152 }
153
154 pub fn build(self) -> Diagnostic {
155 Diagnostic {
156 level: self.level,
157 code: self.code,
158 message: self.message,
159 spans: self.spans,
160 }
161 }
162}
163
164fn clang_fixit_to_label(
165 fixit: clang::diagnostic::FixIt,
166) -> Result<SpanLabel> {
167 use clang::diagnostic::FixIt;
168 use codemap_diagnostic::SpanStyle;
169
170 let mut codemap = CODEMAP
171 .write()
172 .expect("Failed to lock the codemap for writing");
173
174 Ok(match fixit {
175 FixIt::Deletion(range) => {
176 let span = codemap.span_from_libclang_range(range)?;
177 SpanLabel {
178 span,
179 label: Some(String::from("help: try deleting this")),
180 style: SpanStyle::Secondary,
181 }
182 }
183 FixIt::Insertion(location, text) => {
184 let span = codemap.span_from_libclang_location(location)?;
185 SpanLabel {
186 span,
187 label: Some(format!("help: try inserting {:?}", text)),
188 style: SpanStyle::Secondary,
189 }
190 }
191 FixIt::Replacement(range, text) => {
192 let span = codemap.span_from_libclang_range(range)?;
193 SpanLabel {
194 span,
195 label: Some(format!("help: try replacing this with {:?}", text)),
196 style: SpanStyle::Secondary,
197 }
198 }
199 })
200}
201
202pub(super) fn clang_diagnostic_to_diagnostics(
203 diagnostic: clang::diagnostic::Diagnostic,
204) -> Vec<Diagnostic> {
205 use clang::diagnostic::Severity;
206 use codemap_diagnostic::SpanStyle;
207
208 let level = match diagnostic.get_severity() {
209 Severity::Error | Severity::Fatal => Level::Error,
210 Severity::Warning => Level::Warning,
211 Severity::Note => Level::Note,
212 Severity::Ignored => return vec![],
213 };
214
215 let mut diag = DiagnosticBuilder::new(level, diagnostic.get_text());
216
217 {
218 let mut codemap = CODEMAP
219 .write()
220 .expect("Failed to lock the codemap for writing");
221 if let Ok(span) = codemap.span_from_libclang_location(diagnostic.get_location()) {
222 diag.span(SpanLabel {
223 span,
224 label: None,
225 style: SpanStyle::Primary,
226 });
227 };
228 }
229
230 for range in diagnostic.get_ranges() {
231 let mut codemap = CODEMAP
232 .write()
233 .expect("Failed to lock the codemap for writing");
234 let span = match codemap.span_from_libclang_range(range) {
235 Ok(span) => span,
236 Err(_) => continue,
237 };
238
239 diag.span(SpanLabel {
240 span,
241 label: None,
242 style: SpanStyle::Primary,
243 });
244 }
245
246 let mut child_diags = diagnostic
247 .get_children()
248 .into_iter()
249 .flat_map(|diag| clang_diagnostic_to_diagnostics(diag))
250 .collect();
251
252 for fixit_label in diagnostic
253 .get_fix_its()
254 .into_iter()
255 .filter_map(|fixit| clang_fixit_to_label(fixit).ok())
256 {
257 diag.span(fixit_label);
258 }
259
260 let mut diags = vec![diag.build()];
261 diags.append(&mut child_diags);
262 diags
263}
264
265pub(super) fn emit(diagnostics: &[Diagnostic]) {
266 CODEMAP
267 .read()
268 .expect("Failed to lock the codemap for reading")
269 .emitter()
270 .emit(diagnostics)
271}
272
273pub(super) fn log(level: Level, message: String, entity: ClangEntity) {
274 use codemap_diagnostic::SpanStyle;
275
276 let mut diag = DiagnosticBuilder::new(level, message);
277
278 if let Ok(span) = CODEMAP
279 .write()
280 .expect("Failed to lock the codemap for writing")
281 .span_from_entity(entity)
282 {
283 diag.span(SpanLabel {
284 span,
285 label: None,
286 style: SpanStyle::Primary,
287 });
288 };
289
290 emit(&[diag.build()]);
291}
292
293pub(super) fn error(message: String, entity: ClangEntity) {
294 log(Level::Error, message, entity)
295}
296
297/*
298pub(super) fn warn(message: String, entity: ClangEntity) {
299 log(Level::Warning, message, entity)
300}
301
302pub(super) fn note(message: String, entity: ClangEntity) {
303 log(Level::Note, message, entity)
304}
305
306pub(super) fn help(message: String, entity: ClangEntity) {
307 log(Level::Help, message, entity)
308}
309
310pub(super) fn bug(message: String, entity: ClangEntity) {
311 log(Level::Bug, message, entity)
312}
313*/
diff --git a/src/parser/clang/mod.rs b/src/parser/clang/mod.rs
index da49462..a65beed 100644
--- a/src/parser/clang/mod.rs
+++ b/src/parser/clang/mod.rs
@@ -1,4 +1,5 @@
1pub(crate) mod config; 1pub(crate) mod config;
2mod diagnostics;
2mod entities; 3mod entities;
3mod parsing; 4mod parsing;
4 5
diff --git a/src/parser/clang/parsing.rs b/src/parser/clang/parsing.rs
index 6883d06..50ec5d9 100644
--- a/src/parser/clang/parsing.rs
+++ b/src/parser/clang/parsing.rs
@@ -1,10 +1,10 @@
1use super::config::Config; 1use super::config::Config;
2use super::diagnostics;
2use super::entities::*; 3use super::entities::*;
3use crate::types::*; 4use crate::types::*;
4 5
5use anyhow::{anyhow, Context, Error, Result}; 6use anyhow::{anyhow, Context, Error, Result};
6use clang::{Clang, CompilationDatabase, Index, TranslationUnit, Usr}; 7use clang::{Clang, CompilationDatabase, Index, TranslationUnit, Usr};
7use codemap::CodeMap;
8use thiserror::Error; 8use thiserror::Error;
9 9
10use std::collections::BTreeMap; 10use std::collections::BTreeMap;
@@ -234,10 +234,7 @@ impl FromTopLevel for Struct {
234} 234}
235*/ 235*/
236 236
237pub(crate) fn parse_compile_commands( 237pub(crate) fn parse_compile_commands(config: &Config) -> Result<BTreeMap<EntityId, Entity>> {
238 config: &Config,
239 codemap: &mut CodeMap,
240) -> Result<BTreeMap<EntityId, Entity>> {
241 let clang = Clang::new().unwrap(); 238 let clang = Clang::new().unwrap();
242 let index = Index::new( 239 let index = Index::new(
243 &clang, /* exclude from pch = */ false, /* print diagnostics = */ false, 240 &clang, /* exclude from pch = */ false, /* print diagnostics = */ false,
@@ -268,15 +265,6 @@ pub(crate) fn parse_compile_commands(
268 265
269 let filename = command.get_filename(); 266 let filename = command.get_filename();
270 267
271 let file_map = codemap.add_file(
272 filename
273 .to_str()
274 .context("File is not valid UTF-8")?
275 .to_owned(),
276 std::fs::read_to_string(&filename)
277 .with_context(|| format!("Cannot readfile: {:?}", filename))?,
278 );
279
280 trace!("Parsing file: {:?}", filename); 268 trace!("Parsing file: {:?}", filename);
281 // The file name is passed as an argument in the compile commands 269 // The file name is passed as an argument in the compile commands
282 let mut parser = index.parser(""); 270 let mut parser = index.parser("");
@@ -293,8 +281,6 @@ pub(crate) fn parse_compile_commands(
293 .with_context(|| format!("Could not parse file: {:?}", filename))?, 281 .with_context(|| format!("Could not parse file: {:?}", filename))?,
294 &mut entities, 282 &mut entities,
295 &toplevel_directory, 283 &toplevel_directory,
296 file_map.span,
297 &codemap,
298 )?; 284 )?;
299 285
300 trace!("Changing directory to: {:?}", toplevel_directory); 286 trace!("Changing directory to: {:?}", toplevel_directory);
@@ -309,11 +295,7 @@ pub(crate) fn parse_compile_commands(
309 Ok(entities.into()) 295 Ok(entities.into())
310} 296}
311 297
312pub(crate) fn parse_file<T>( 298pub(crate) fn parse_file<T>(path: T, config: &Config) -> Result<BTreeMap<EntityId, Entity>>
313 path: T,
314 config: &Config,
315 codemap: &mut CodeMap,
316) -> Result<BTreeMap<EntityId, Entity>>
317where 299where
318 T: Into<PathBuf>, 300 T: Into<PathBuf>,
319 T: AsRef<Path>, 301 T: AsRef<Path>,
@@ -324,7 +306,6 @@ where
324 306
325 // as provided in the command line 307 // as provided in the command line
326 let filename = path.to_string(); 308 let filename = path.to_string();
327 let file_map = codemap.add_file(filename.clone(), std::fs::read_to_string(&path)?);
328 309
329 let path = path.as_ref().canonicalize()?; 310 let path = path.as_ref().canonicalize()?;
330 let toplevel_directory = std::env::current_dir().context("Cannot read current directory")?; 311 let toplevel_directory = std::env::current_dir().context("Cannot read current directory")?;
@@ -341,14 +322,18 @@ where
341 .unwrap_or_default(); 322 .unwrap_or_default();
342 clang_arguments.extend_from_slice(&config.extra_args); 323 clang_arguments.extend_from_slice(&config.extra_args);
343 324
344 if let Some(command) = maybe_command { 325 let mut parser = if let Some(command) = maybe_command {
345 let directory = command.get_directory(); 326 let directory = command.get_directory();
346 trace!("Changing directory to: {:?}", directory); 327 trace!("Changing directory to: {:?}", directory);
347 std::env::set_current_dir(&directory) 328 std::env::set_current_dir(&directory)
348 .with_context(|| format!("Cannot change current directory to: {:?}", directory))?; 329 .with_context(|| format!("Cannot change current directory to: {:?}", directory))?;
349 } 330 // If it has the parameters provided by the compilation database,
331 // then it knows which file to parse
332 index.parser("")
333 } else {
334 index.parser(path)
335 };
350 336
351 let mut parser = index.parser("");
352 parser.skip_function_bodies(true); 337 parser.skip_function_bodies(true);
353 338
354 parser.arguments(&clang_arguments); 339 parser.arguments(&clang_arguments);
@@ -363,8 +348,6 @@ where
363 .with_context(|| format!("Could not parse file: {:?}", filename))?, 348 .with_context(|| format!("Could not parse file: {:?}", filename))?,
364 &mut entities, 349 &mut entities,
365 &toplevel_directory, 350 &toplevel_directory,
366 file_map.span,
367 &codemap,
368 )?; 351 )?;
369 352
370 trace!("Changing directory to: {:?}", toplevel_directory); 353 trace!("Changing directory to: {:?}", toplevel_directory);
@@ -382,8 +365,6 @@ fn parse_unit(
382 trans_unit: &TranslationUnit, 365 trans_unit: &TranslationUnit,
383 entities: &mut TopLevel, 366 entities: &mut TopLevel,
384 base_dir: impl AsRef<Path>, 367 base_dir: impl AsRef<Path>,
385 file_span: codemap::Span,
386 codemap: &CodeMap,
387) -> Result<()> { 368) -> Result<()> {
388 trans_unit.get_entity().visit_children(|entity, _parent| { 369 trans_unit.get_entity().visit_children(|entity, _parent| {
389 if is_in_system_header(entity, &base_dir) { 370 if is_in_system_header(entity, &base_dir) {
@@ -400,36 +381,18 @@ fn parse_unit(
400 trace!("Entity with USR = {:?}", usr); 381 trace!("Entity with USR = {:?}", usr);
401 debug!("Parsing toplevel entity: {:?}", entity); 382 debug!("Parsing toplevel entity: {:?}", entity);
402 383
403 add_entity(entity, entities, file_span, codemap) 384 add_entity(entity, entities)
404 }); 385 });
405 386
406 use codemap_diagnostic::{ColorConfig, Emitter}; 387 for diagnostic in trans_unit.get_diagnostics() {
407 388 let diags = diagnostics::clang_diagnostic_to_diagnostics(diagnostic);
408 let mut emitter = Emitter::stderr(ColorConfig::Auto, Some(&codemap)); 389 diagnostics::emit(&diags);
409
410 for diagnostic in trans_unit.get_diagnostics().iter() {
411 warn!("{}", diagnostic);
412 /* 390 /*
413 let main_diag = match clang_diag_to_codemap_diag(&diagnostic, file_span) {
414 Some(diag) => diag,
415 None => continue,
416 };
417
418 let sub_diags = diagnostic 391 let sub_diags = diagnostic
419 .get_children() 392 .get_children()
420 .into_iter() 393 .into_iter()
421 .filter_map(|diagnostic| clang_diag_to_codemap_diag(&diagnostic, file_span)); 394 .filter_map(|diagnostic| clang_diag_to_codemap_diag(&diagnostic, file_span));
422 395
423 let fix_it_diags = diagnostic
424 .get_fix_its()
425 .into_iter()
426 .map(|fix_it| clang_fix_it_to_codemap_diag(&fix_it, file_span));
427
428 emitter.emit(
429 &std::iter::once(main_diag)
430 .chain(sub_diags)
431 .chain(fix_it_diags)
432 .collect::<Vec<_>>(),
433 ); 396 );
434 */ 397 */
435 } 398 }
@@ -462,8 +425,6 @@ fn is_in_system_header(entity: clang::Entity, base_dir: impl AsRef<Path>) -> boo
462fn add_entity( 425fn add_entity(
463 libclang_entity: clang::Entity, 426 libclang_entity: clang::Entity,
464 toplevel: &mut TopLevel, 427 toplevel: &mut TopLevel,
465 file_span: codemap::Span,
466 codemap: &CodeMap,
467) -> clang::EntityVisitResult { 428) -> clang::EntityVisitResult {
468 if libclang_entity.get_usr().is_none() { 429 if libclang_entity.get_usr().is_none() {
469 return clang::EntityVisitResult::Continue; 430 return clang::EntityVisitResult::Continue;
@@ -472,38 +433,7 @@ fn add_entity(
472 let kind = match ClangEntityKind::try_from(libclang_entity.get_kind()) { 433 let kind = match ClangEntityKind::try_from(libclang_entity.get_kind()) {
473 Ok(kind) => kind, 434 Ok(kind) => kind,
474 Err(err) => { 435 Err(err) => {
475 use codemap_diagnostic::{ 436 diagnostics::error(format!("{}", err), libclang_entity);
476 ColorConfig, Diagnostic, Emitter, Level, SpanLabel, SpanStyle,
477 };
478 let spans = if let Some(range) = libclang_entity.get_range() {
479 // TODO: add every file parsed in this translation unit to the
480 // codemap, so we can properly report errors
481 if !range.is_in_main_file() {
482 vec![]
483 } else {
484 let begin = range.get_start().get_file_location().offset as u64;
485 let end = range.get_end().get_file_location().offset as u64;
486
487 vec![SpanLabel {
488 span: file_span.subspan(begin, end),
489 label: None,
490 style: SpanStyle::Primary,
491 }]
492 }
493 } else {
494 vec![]
495 };
496
497 let diag = Diagnostic {
498 level: Level::Warning,
499 message: format!("{}", err),
500 code: None,
501 spans,
502 };
503
504 let mut emitter = Emitter::stderr(ColorConfig::Auto, Some(codemap));
505 emitter.emit(&[diag]);
506
507 return clang::EntityVisitResult::Continue; 437 return clang::EntityVisitResult::Continue;
508 } 438 }
509 }; 439 };
@@ -547,7 +477,7 @@ fn add_entity(
547 // TODO: check result 477 // TODO: check result
548 478
549 if let Err(err) = result { 479 if let Err(err) = result {
550 error!("{}: {:?}", err, libclang_entity); 480 diagnostics::error(format!("{}", err), libclang_entity);
551 return ::clang::EntityVisitResult::Continue; 481 return ::clang::EntityVisitResult::Continue;
552 } 482 }
553 } 483 }