1010//
1111// SPDX-License-Identifier: Apache-2.0
1212////////////////////////////////////////////////////////////////////////////////////
13- use clang:: { Entity , EntityKind , EntityVisitResult } ;
1413use clap:: Parser as ClapParser ;
14+ use env_logger:: Builder ;
15+ use log:: { debug, error, LevelFilter } ;
1516use std:: collections:: BTreeMap ;
1617use std:: fs;
17- use std:: fs:: OpenOptions ;
18- use std:: io:: { BufWriter , Write } ;
1918use std:: path:: PathBuf ;
19+
20+ use utils:: { render_entity_tree, write_entity_tree} ;
2021use visit_tu:: context;
2122use visit_tu:: visitor;
2223use visit_tu:: { FunctionDef , VisitContext , Visitor } ;
@@ -41,10 +42,6 @@ struct Args {
4142 /// Output JSON format for debugging (internal use only)
4243 #[ arg( long, hide = true ) ]
4344 json : bool ,
44-
45- /// Print verbose output
46- #[ arg( short, long) ]
47- verbose : bool ,
4845}
4946
5047fn parse_file (
@@ -55,11 +52,11 @@ fn parse_file(
5552 all_classes : & mut BTreeMap < String , context:: TypeMapValue > ,
5653 all_functions : & mut Vec < FunctionDef > ,
5754) {
58- println ! ( "Parsing TU: {:?}" , file) ;
55+ debug ! ( "Parsing TU: {:?}" , file) ;
5956
6057 if let Some ( path_str) = file. to_str ( ) {
6158 if visitor:: is_external_dependency_path ( path_str) {
62- println ! ( " Skipping external dependency file: {:?}" , file) ;
59+ debug ! ( "Skipping external dependency file: {:?}" , file) ;
6360 return ;
6461 }
6562 } ;
@@ -68,62 +65,88 @@ fn parse_file(
6865
6966 match parse_result {
7067 Ok ( parsed) => {
71- println ! ( " Parsed successfully, parsed is {:?}" , parsed) ;
72-
7368 let diagnostics = parsed. get_diagnostics ( ) ;
7469 if !diagnostics. is_empty ( ) {
75- println ! ( " Diagnostics: {}" , diagnostics. len( ) ) ;
70+ debug ! ( "Diagnostics: {}" , diagnostics. len( ) ) ;
71+ for diagnostic in & diagnostics {
72+ debug ! ( "Diagnostic: {:?}" , diagnostic) ;
73+ }
7674 }
7775
7876 let entity = parsed. get_entity ( ) ;
79- print_entity ( & entity, 0 , PrintMode :: File ( ast_file_output_path) ) ;
80- print_entity ( & entity, 0 , PrintMode :: Stdout ) ;
77+ debug ! ( "Parsed {:?} successfully" , parsed) ;
78+ if log:: log_enabled!( log:: Level :: Trace ) {
79+ let entity_tree = render_entity_tree ( & entity, 0 ) ;
80+ write_entity_tree ( ast_file_output_path, & entity_tree) ;
81+ }
8182
8283 let mut ctx = VisitContext :: default ( ) ;
8384 let mut visitor = Visitor :: new ( & mut ctx) ;
8485 visitor. visit ( entity) ;
85- println ! (
86- " Visited TU, extracted {} classes, {} functions" ,
86+ debug ! (
87+ "Visited TU, extracted {} classes, {} functions" ,
8788 ctx. types. len( ) ,
8889 ctx. functions. len( )
8990 ) ;
9091 for ( class_name, logic_class) in & ctx. types {
91- println ! ( " - class: {}" , class_name) ;
92- println ! ( "{:#?}" , logic_class) ;
92+ debug ! ( "Class {}:\n {:#?}" , class_name, logic_class) ;
9393 all_classes. insert ( class_name. clone ( ) , logic_class. clone ( ) ) ;
9494 }
9595 all_functions. extend ( ctx. functions ) ;
9696 }
9797 Err ( e) => {
98- eprintln ! ( " Failed to parse {:?}: {:?}" , file, e) ;
98+ error ! ( "Failed to parse {:?}: {:?}" , file, e) ;
9999 }
100100 }
101101}
102102
103- fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
104- println ! ( "=== libclang Information ===\n " ) ;
105- println ! ( "Command line: {:?}" , std:: env:: args( ) . collect:: <Vec <_>>( ) ) ;
103+ fn parse_log_level_from_env ( ) -> LevelFilter {
104+ std:: env:: var ( "LIBCLANG_LOG" )
105+ . ok ( )
106+ . and_then ( |value| value. parse :: < LevelFilter > ( ) . ok ( ) )
107+ . unwrap_or ( LevelFilter :: Error )
108+ }
109+
110+ fn init_logging ( ) {
111+ Builder :: new ( )
112+ . filter_level ( parse_log_level_from_env ( ) )
113+ . init ( ) ;
114+ }
115+
116+ fn init_libclang ( ) -> clang:: Clang {
117+ debug ! ( "=== libclang Information ===" ) ;
118+ debug ! ( "Command line: {:?}" , std:: env:: args( ) . collect:: <Vec <_>>( ) ) ;
106119
107120 if let Ok ( path) = std:: env:: var ( "LIBCLANG_PATH" ) {
108- println ! ( "LIBCLANG_PATH: {}" , path) ;
121+ debug ! ( "LIBCLANG_PATH: {}" , path) ;
109122 }
110123
111- // Load clang - keep it alive for the entire scope
112124 let clang = match clang:: Clang :: new ( ) {
113125 Ok ( c) => {
114- println ! ( "✓ Successfully loaded libclang\n " ) ;
126+ debug ! ( "Successfully loaded libclang" ) ;
115127 c
116128 }
117129 Err ( e) => {
118- eprintln ! ( "Failed to load libclang: {}" , e) ;
130+ error ! ( "Failed to load libclang: {}" , e) ;
119131 std:: process:: exit ( 1 ) ;
120132 }
121133 } ;
122134
123- // All operations use the clang-rs wrapper API
124- let index = clang:: Index :: new ( & clang, false , true ) ;
125- println ! ( "✓ Created clang index" ) ;
126- println ! ( "libclang version: {}" , clang:: get_version( ) ) ;
135+ debug ! ( "libclang version: {}" , clang:: get_version( ) ) ;
136+ debug ! ( "Using Bazel's LLVM toolchain with clang-rs wrapper" ) ;
137+ clang
138+ }
139+
140+ fn init_clang_index ( clang : & clang:: Clang ) -> clang:: Index {
141+ let index = clang:: Index :: new ( clang, false , true ) ;
142+ debug ! ( "Created clang index" ) ;
143+ index
144+ }
145+
146+ fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
147+ init_logging ( ) ;
148+ let clang = init_libclang ( ) ;
149+ let index = init_clang_index ( & clang) ;
127150
128151 let command_line_args = Args :: parse ( ) ;
129152 let mut all_classes = BTreeMap :: new ( ) ;
@@ -155,59 +178,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
155178 ) ;
156179 let output_json = serde_json:: to_string_pretty ( & output) ?;
157180 fs:: write ( & command_line_args. output , output_json) ?;
158- println ! ( "Wrote AST JSON to {:?}" , command_line_args. output) ;
159- println ! ( "\n Using Bazel's LLVM toolchain with clang-rs wrapper!" ) ;
181+ debug ! ( "Wrote AST JSON to {:?}" , command_line_args. output) ;
160182
161183 Ok ( ( ) )
162184}
163-
164- enum PrintMode < ' a > {
165- Stdout ,
166- File ( & ' a PathBuf ) ,
167- }
168-
169- fn print_entity ( entity : & Entity , level : usize , print_mode : PrintMode ) {
170- match print_mode {
171- PrintMode :: Stdout => {
172- let mut stdout = std:: io:: stdout ( ) . lock ( ) ;
173- print_entity_to ( entity, level, & mut stdout)
174- }
175- PrintMode :: File ( path) => {
176- let file = OpenOptions :: new ( )
177- . create ( true )
178- . append ( true )
179- . open ( path)
180- . unwrap_or_else ( |e| {
181- panic ! ( "Failed to open file {:?} for writing: {}" , path, e) ;
182- } ) ;
183- let mut file_out = BufWriter :: new ( file) ;
184- print_entity_to ( entity, level, & mut file_out)
185- }
186- }
187- }
188-
189- fn print_entity_to ( entity : & Entity , level : usize , out : & mut dyn Write ) {
190- let indent = " " . repeat ( level) ;
191- let kind = entity. get_kind ( ) ;
192- let spelling = match kind {
193- EntityKind :: AccessSpecifier => entity
194- . get_accessibility ( )
195- . map ( |a| format ! ( "{:?}" , a) . to_lowercase ( ) )
196- . unwrap_or_default ( ) ,
197- _ => entity. get_name ( ) . unwrap_or_default ( ) ,
198- } ;
199- let output = format ! ( "{}{:?} | {}\n " , indent, kind, spelling) ;
200-
201- // we soft fail since this is just a diagnostic print and should not crush the main programm
202- out. write_all ( output. as_bytes ( ) ) . unwrap_or_else ( |e| {
203- eprintln ! ( "Failed to write entity info: {}" , e) ;
204- } ) ;
205- out. flush ( ) . unwrap_or_else ( |e| {
206- eprintln ! ( "Failed to flush output: {}" , e) ;
207- } ) ;
208-
209- entity. visit_children ( |child, _parent| {
210- print_entity_to ( & child, level + 1 , out) ;
211- EntityVisitResult :: Continue
212- } ) ;
213- }
0 commit comments