1
+ use crate :: rust_analyzer:: path_to_file_id;
1
2
use anyhow:: Context ;
2
3
use archive:: Archiver ;
3
4
use log:: info;
4
5
use ra_ap_hir:: Semantics ;
5
6
use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
7
+ use ra_ap_ide_db:: RootDatabase ;
6
8
use ra_ap_project_model:: ProjectManifest ;
9
+ use ra_ap_vfs:: Vfs ;
7
10
use rust_analyzer:: { ParseResult , RustAnalyzer } ;
8
11
use std:: {
9
12
collections:: HashMap ,
10
13
path:: { Path , PathBuf } ,
11
14
} ;
15
+
12
16
mod archive;
13
17
mod config;
14
18
pub mod generated;
@@ -17,54 +21,71 @@ mod rust_analyzer;
17
21
mod translate;
18
22
pub mod trap;
19
23
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
+ }
27
28
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) ;
46
32
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 ( ) ,
58
49
) ;
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) ;
59
88
}
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
- } ) ;
68
89
}
69
90
70
91
fn main ( ) -> anyhow:: Result < ( ) > {
@@ -82,6 +103,10 @@ fn main() -> anyhow::Result<()> {
82
103
let archiver = archive:: Archiver {
83
104
root : cfg. source_archive_dir . clone ( ) ,
84
105
} ;
106
+ let extractor = Extractor {
107
+ archiver : & archiver,
108
+ traps : & traps,
109
+ } ;
85
110
let files: Vec < PathBuf > = cfg
86
111
. inputs
87
112
. iter ( )
@@ -95,38 +120,39 @@ fn main() -> anyhow::Result<()> {
95
120
. iter ( )
96
121
. map ( |x| ( x. manifest_path ( ) . parent ( ) . as_ref ( ) , ( x, Vec :: new ( ) ) ) )
97
122
. collect ( ) ;
98
- let mut other_files = Vec :: new ( ) ;
99
123
100
124
' 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) {
105
127
files. push ( file) ;
106
128
continue ' outer;
107
129
}
108
130
}
109
- other_files . push ( file) ;
131
+ extractor . extract_without_semantics ( file, "no manifest found" ) ;
110
132
}
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 ( ) ) {
115
134
if let Some ( ( ref db, ref vfs) ) = RustAnalyzer :: load_workspace ( manifest, & cfg. scratch_dir ) {
116
135
let semantics = Semantics :: new ( db) ;
117
- let rust_analyzer = RustAnalyzer :: new ( vfs, semantics) ;
118
136
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) ;
120
149
}
121
150
} else {
122
151
for file in files {
123
- extract ( & RustAnalyzer :: WithoutSemantics , & archiver , & traps , file ) ;
152
+ extractor . extract_without_semantics ( file , "unable to load manifest" ) ;
124
153
}
125
154
}
126
155
}
127
- for file in other_files {
128
- extract ( & RustAnalyzer :: WithoutSemantics , & archiver, & traps, file) ;
129
- }
130
156
131
157
Ok ( ( ) )
132
158
}
0 commit comments