1+ use crate :: rust_analyzer:: path_to_file_id;
12use anyhow:: Context ;
23use archive:: Archiver ;
34use log:: info;
45use ra_ap_hir:: Semantics ;
56use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
7+ use ra_ap_ide_db:: RootDatabase ;
68use ra_ap_project_model:: ProjectManifest ;
9+ use ra_ap_vfs:: Vfs ;
710use rust_analyzer:: { ParseResult , RustAnalyzer } ;
811use std:: {
912 collections:: HashMap ,
1013 path:: { Path , PathBuf } ,
1114} ;
15+
1216mod archive;
1317mod config;
1418pub mod generated;
@@ -17,54 +21,71 @@ mod rust_analyzer;
1721mod translate;
1822pub mod trap;
1923
20- fn extract (
21- rust_analyzer : & rust_analyzer:: RustAnalyzer ,
22- archiver : & Archiver ,
23- traps : & trap:: TrapFileProvider ,
24- file : & std:: path:: Path ,
25- ) {
26- archiver. archive ( file) ;
24+ struct Extractor < ' a > {
25+ archiver : & ' a Archiver ,
26+ traps : & ' a trap:: TrapFileProvider ,
27+ }
2728
28- let ParseResult {
29- ast,
30- text,
31- errors,
32- file_id,
33- } = rust_analyzer. parse ( file) ;
34- let line_index = LineIndex :: new ( text. as_ref ( ) ) ;
35- let display_path = file. to_string_lossy ( ) ;
36- let mut trap = traps. create ( "source" , file) ;
37- let label = trap. emit_file ( file) ;
38- let mut translator = translate:: Translator :: new (
39- trap,
40- display_path. as_ref ( ) ,
41- label,
42- line_index,
43- file_id,
44- file_id. and ( rust_analyzer. semantics ( ) ) ,
45- ) ;
29+ impl Extractor < ' _ > {
30+ fn extract ( & self , rust_analyzer : & rust_analyzer:: RustAnalyzer , file : & std:: path:: Path ) {
31+ self . archiver . archive ( file) ;
4632
47- for err in errors {
48- translator. emit_parse_error ( & ast, & err) ;
49- }
50- let no_location = ( LineCol { line : 0 , col : 0 } , LineCol { line : 0 , col : 0 } ) ;
51- if translator. semantics . is_none ( ) {
52- translator. emit_diagnostic (
53- trap:: DiagnosticSeverity :: Warning ,
54- "semantics" . to_owned ( ) ,
55- "semantic analyzer unavailable" . to_owned ( ) ,
56- "semantic analyzer unavailable: macro expansion, call graph, and type inference will be skipped." . to_owned ( ) ,
57- no_location,
33+ let ParseResult {
34+ ast,
35+ text,
36+ errors,
37+ semantics_info,
38+ } = rust_analyzer. parse ( file) ;
39+ let line_index = LineIndex :: new ( text. as_ref ( ) ) ;
40+ let display_path = file. to_string_lossy ( ) ;
41+ let mut trap = self . traps . create ( "source" , file) ;
42+ let label = trap. emit_file ( file) ;
43+ let mut translator = translate:: Translator :: new (
44+ trap,
45+ display_path. as_ref ( ) ,
46+ label,
47+ line_index,
48+ semantics_info. as_ref ( ) . ok ( ) ,
5849 ) ;
50+
51+ for err in errors {
52+ translator. emit_parse_error ( & ast, & err) ;
53+ }
54+ let no_location = ( LineCol { line : 0 , col : 0 } , LineCol { line : 0 , col : 0 } ) ;
55+ if let Err ( reason) = semantics_info {
56+ let message = format ! ( "semantic analyzer unavailable ({reason})" ) ;
57+ let full_message = format ! (
58+ "{message}: macro expansion, call graph, and type inference will be skipped."
59+ ) ;
60+ translator. emit_diagnostic (
61+ trap:: DiagnosticSeverity :: Warning ,
62+ "semantics" . to_owned ( ) ,
63+ message,
64+ full_message,
65+ no_location,
66+ ) ;
67+ }
68+ translator. emit_source_file ( ast) ;
69+ translator. trap . commit ( ) . unwrap_or_else ( |err| {
70+ log:: error!(
71+ "Failed to write trap file for: {}: {}" ,
72+ display_path,
73+ err. to_string( )
74+ )
75+ } ) ;
76+ }
77+
78+ pub fn extract_with_semantics (
79+ & self ,
80+ file : & Path ,
81+ semantics : & Semantics < ' _ , RootDatabase > ,
82+ vfs : & Vfs ,
83+ ) {
84+ self . extract ( & RustAnalyzer :: new ( vfs, semantics) , file) ;
85+ }
86+ pub fn extract_without_semantics ( & self , file : & Path , reason : & str ) {
87+ self . extract ( & RustAnalyzer :: WithoutSemantics { reason } , file) ;
5988 }
60- translator. emit_source_file ( ast) ;
61- translator. trap . commit ( ) . unwrap_or_else ( |err| {
62- log:: error!(
63- "Failed to write trap file for: {}: {}" ,
64- display_path,
65- err. to_string( )
66- )
67- } ) ;
6889}
6990
7091fn main ( ) -> anyhow:: Result < ( ) > {
@@ -82,6 +103,10 @@ fn main() -> anyhow::Result<()> {
82103 let archiver = archive:: Archiver {
83104 root : cfg. source_archive_dir . clone ( ) ,
84105 } ;
106+ let extractor = Extractor {
107+ archiver : & archiver,
108+ traps : & traps,
109+ } ;
85110 let files: Vec < PathBuf > = cfg
86111 . inputs
87112 . iter ( )
@@ -95,38 +120,39 @@ fn main() -> anyhow::Result<()> {
95120 . iter ( )
96121 . map ( |x| ( x. manifest_path ( ) . parent ( ) . as_ref ( ) , ( x, Vec :: new ( ) ) ) )
97122 . collect ( ) ;
98- let mut other_files = Vec :: new ( ) ;
99123
100124 ' outer: for file in & files {
101- let mut p = file. as_path ( ) ;
102- while let Some ( parent) = p. parent ( ) {
103- p = parent;
104- if let Some ( ( _, files) ) = map. get_mut ( parent) {
125+ for ancestor in file. as_path ( ) . ancestors ( ) {
126+ if let Some ( ( _, files) ) = map. get_mut ( ancestor) {
105127 files. push ( file) ;
106128 continue ' outer;
107129 }
108130 }
109- other_files . push ( file) ;
131+ extractor . extract_without_semantics ( file, "no manifest found" ) ;
110132 }
111- for ( manifest, files) in map. values ( ) {
112- if files. is_empty ( ) {
113- break ;
114- }
133+ for ( manifest, files) in map. values ( ) . filter ( |( _, files) | !files. is_empty ( ) ) {
115134 if let Some ( ( ref db, ref vfs) ) = RustAnalyzer :: load_workspace ( manifest, & cfg. scratch_dir ) {
116135 let semantics = Semantics :: new ( db) ;
117- let rust_analyzer = RustAnalyzer :: new ( vfs, semantics) ;
118136 for file in files {
119- extract ( & rust_analyzer, & archiver, & traps, file) ;
137+ let Some ( id) = path_to_file_id ( file, vfs) else {
138+ extractor. extract_without_semantics (
139+ file,
140+ "not included in files loaded from manifest" ,
141+ ) ;
142+ continue ;
143+ } ;
144+ if semantics. file_to_module_def ( id) . is_none ( ) {
145+ extractor. extract_without_semantics ( file, "not included as a module" ) ;
146+ continue ;
147+ }
148+ extractor. extract_with_semantics ( file, & semantics, vfs) ;
120149 }
121150 } else {
122151 for file in files {
123- extract ( & RustAnalyzer :: WithoutSemantics , & archiver , & traps , file ) ;
152+ extractor . extract_without_semantics ( file , "unable to load manifest" ) ;
124153 }
125154 }
126155 }
127- for file in other_files {
128- extract ( & RustAnalyzer :: WithoutSemantics , & archiver, & traps, file) ;
129- }
130156
131157 Ok ( ( ) )
132158}
0 commit comments