1
- use crate :: generated:: { self , AstNode } ;
1
+ use crate :: generated:: MacroCall ;
2
+ use crate :: generated:: { self } ;
2
3
use crate :: trap:: { DiagnosticSeverity , TrapFile , TrapId } ;
3
4
use crate :: trap:: { Label , TrapClass } ;
4
5
use codeql_extractor:: trap:: { self } ;
6
+ use log:: Level ;
7
+ use ra_ap_hir:: db:: ExpandDatabase ;
5
8
use ra_ap_hir:: Semantics ;
6
9
use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
7
10
use ra_ap_ide_db:: RootDatabase ;
8
11
use ra_ap_parser:: SyntaxKind ;
9
12
use ra_ap_syntax:: ast:: RangeItem ;
10
- use ra_ap_syntax:: { ast, NodeOrToken , SyntaxElementChildren , SyntaxError , SyntaxToken , TextRange } ;
13
+ use ra_ap_syntax:: {
14
+ ast, AstNode , NodeOrToken , SyntaxElementChildren , SyntaxError , SyntaxToken , TextRange ,
15
+ } ;
11
16
pub trait TextValue {
12
17
fn try_get_text ( & self ) -> Option < String > ;
13
18
}
@@ -60,32 +65,35 @@ impl TextValue for ast::RangePat {
60
65
}
61
66
pub struct Translator < ' a > {
62
67
pub trap : TrapFile ,
68
+ path : & ' a str ,
63
69
label : trap:: Label ,
64
70
line_index : LineIndex ,
65
- semi : Option < Semantics < ' a , RootDatabase > > ,
71
+ pub semi : Option < Semantics < ' a , RootDatabase > > ,
66
72
}
67
73
68
- impl Translator < ' _ > {
74
+ impl < ' a > Translator < ' a > {
69
75
pub fn new (
70
76
trap : TrapFile ,
77
+ path : & ' a str ,
71
78
label : trap:: Label ,
72
79
line_index : LineIndex ,
73
- semi : Option < Semantics < ' _ , RootDatabase > > ,
74
- ) -> Translator {
80
+ semi : Option < Semantics < ' a , RootDatabase > > ,
81
+ ) -> Translator < ' a > {
75
82
Translator {
76
83
trap,
84
+ path,
77
85
label,
78
86
line_index,
79
87
semi,
80
88
}
81
89
}
82
- pub fn location ( & self , range : TextRange ) -> ( LineCol , LineCol ) {
90
+ fn location ( & self , range : TextRange ) -> ( LineCol , LineCol ) {
83
91
let start = self . line_index . line_col ( range. start ( ) ) ;
84
92
let range_end = range. end ( ) ;
85
93
// QL end positions are inclusive, while TextRange offsets are exclusive and point at the position
86
94
// right after the last character of the range. We need to shift the end offset one character to the left to
87
95
// get the right inclusive QL position. Unfortunately, simply subtracting `1` from the end-offset may cause
88
- // the offset to point in the middle of a mult -byte character, resulting in a `panic`. Therefore we use `try_line_col`
96
+ // the offset to point in the middle of a multi -byte character, resulting in a `panic`. Therefore we use `try_line_col`
89
97
// with decreasing offsets to find the start of the last character included in the range.
90
98
for i in 1 ..4 {
91
99
if let Some ( end) = range_end
@@ -98,28 +106,72 @@ impl Translator<'_> {
98
106
let end = self . line_index . line_col ( range_end) ;
99
107
( start, end)
100
108
}
109
+
110
+ pub fn text_range_for_node ( & mut self , node : & impl ast:: AstNode ) -> TextRange {
111
+ if let Some ( semi) = self . semi . as_ref ( ) {
112
+ let file_range = semi. original_range ( node. syntax ( ) ) ;
113
+ file_range. range
114
+ } else {
115
+ node. syntax ( ) . text_range ( )
116
+ }
117
+ }
101
118
pub fn emit_location < T : TrapClass > ( & mut self , label : Label < T > , node : & impl ast:: AstNode ) {
102
- let ( start, end) = self . location ( node. syntax ( ) . text_range ( ) ) ;
119
+ let range = self . text_range_for_node ( node) ;
120
+ let ( start, end) = self . location ( range) ;
103
121
self . trap . emit_location ( self . label , label, start, end)
104
122
}
105
123
pub fn emit_location_token ( & mut self , label : Label < generated:: Token > , token : & SyntaxToken ) {
106
124
let ( start, end) = self . location ( token. text_range ( ) ) ;
107
125
self . trap . emit_location ( self . label , label, start, end)
108
126
}
109
- pub fn emit_parse_error ( & mut self , path : & str , err : SyntaxError ) {
110
- let ( start, end) = self . location ( err. range ( ) ) ;
111
- log:: warn!( "{}:{}:{}: {}" , path, start. line + 1 , start. col + 1 , err) ;
112
- let message = err. to_string ( ) ;
127
+ pub fn emit_diagnostic (
128
+ & mut self ,
129
+ severity : DiagnosticSeverity ,
130
+ error_tag : String ,
131
+ error_message : String ,
132
+ full_error_message : String ,
133
+ location : ( LineCol , LineCol ) ,
134
+ ) {
135
+ let ( start, end) = location;
136
+ let level = match severity {
137
+ DiagnosticSeverity :: Debug => Level :: Debug ,
138
+ DiagnosticSeverity :: Info => Level :: Info ,
139
+ DiagnosticSeverity :: Warning => Level :: Warn ,
140
+ DiagnosticSeverity :: Error => Level :: Error ,
141
+ } ;
142
+ log:: log!(
143
+ level,
144
+ "{}:{}:{}: {}" ,
145
+ self . path,
146
+ start. line + 1 ,
147
+ start. col + 1 ,
148
+ & error_message
149
+ ) ;
113
150
let location = self . trap . emit_location_label ( self . label , start, end) ;
114
151
self . trap . emit_diagnostic (
152
+ severity,
153
+ error_tag,
154
+ error_message,
155
+ full_error_message,
156
+ location,
157
+ ) ;
158
+ }
159
+ pub fn emit_parse_error ( & mut self , err : & SyntaxError ) {
160
+ let location = self . location ( err. range ( ) ) ;
161
+ let message = err. to_string ( ) ;
162
+ self . emit_diagnostic (
115
163
DiagnosticSeverity :: Warning ,
116
164
"parse_error" . to_owned ( ) ,
117
165
message. clone ( ) ,
118
166
message,
119
167
location,
120
168
) ;
121
169
}
122
- pub fn emit_tokens ( & mut self , parent : Label < AstNode > , children : SyntaxElementChildren ) {
170
+ pub fn emit_tokens (
171
+ & mut self ,
172
+ parent : Label < generated:: AstNode > ,
173
+ children : SyntaxElementChildren ,
174
+ ) {
123
175
for child in children {
124
176
if let NodeOrToken :: Token ( token) = child {
125
177
if token. kind ( ) == SyntaxKind :: COMMENT {
@@ -133,4 +185,83 @@ impl Translator<'_> {
133
185
}
134
186
}
135
187
}
188
+ pub ( crate ) fn extract_macro_call_expanded (
189
+ & mut self ,
190
+ mcall : & ast:: MacroCall ,
191
+ label : Label < generated:: MacroCall > ,
192
+ ) {
193
+ if let Some ( semi) = & self . semi {
194
+ if let Some ( expanded) = semi. expand ( mcall) {
195
+ if let Some ( value) =
196
+ semi. hir_file_for ( & expanded)
197
+ . macro_file ( )
198
+ . and_then ( |macro_file| {
199
+ semi. db
200
+ . parse_macro_expansion_error ( macro_file. macro_call_id )
201
+ } )
202
+ {
203
+ if let Some ( err) = & value. err {
204
+ let ( message, _error) = err. render_to_string ( semi. db ) ;
205
+
206
+ if err. span ( ) . anchor . file_id == semi. hir_file_for ( mcall. syntax ( ) ) {
207
+ let location = err. span ( ) . range
208
+ + semi
209
+ . db
210
+ . ast_id_map ( err. span ( ) . anchor . file_id . into ( ) )
211
+ . get_erased ( err. span ( ) . anchor . ast_id )
212
+ . text_range ( )
213
+ . start ( ) ;
214
+ self . emit_parse_error ( & SyntaxError :: new ( message, location) ) ;
215
+ } ;
216
+ }
217
+ for err in value. value . iter ( ) {
218
+ self . emit_parse_error ( err) ;
219
+ }
220
+ }
221
+ let expand_to = ra_ap_hir_expand:: ExpandTo :: from_call_site ( mcall) ;
222
+ let kind = expanded. kind ( ) ;
223
+ let value: Option < Label < crate :: generated:: AstNode > > = match expand_to {
224
+ ra_ap_hir_expand:: ExpandTo :: Statements => {
225
+ ast:: MacroStmts :: cast ( expanded) . map ( |x| self . emit_macro_stmts ( x) . into ( ) )
226
+ }
227
+ ra_ap_hir_expand:: ExpandTo :: Items => {
228
+ ast:: MacroItems :: cast ( expanded) . map ( |x| self . emit_macro_items ( x) . into ( ) )
229
+ }
230
+
231
+ ra_ap_hir_expand:: ExpandTo :: Pattern => {
232
+ ast:: Pat :: cast ( expanded) . map ( |x| self . emit_pat ( x) . into ( ) )
233
+ }
234
+ ra_ap_hir_expand:: ExpandTo :: Type => {
235
+ ast:: Type :: cast ( expanded) . map ( |x| self . emit_type ( x) . into ( ) )
236
+ }
237
+ ra_ap_hir_expand:: ExpandTo :: Expr => {
238
+ ast:: Expr :: cast ( expanded) . map ( |x| self . emit_expr ( x) . into ( ) )
239
+ }
240
+ } ;
241
+ if let Some ( value) = value {
242
+ MacroCall :: emit_expanded ( label, value, & mut self . trap . writer ) ;
243
+ } else {
244
+ let range = self . text_range_for_node ( mcall) ;
245
+ self . emit_parse_error ( & SyntaxError :: new (
246
+ format ! (
247
+ "macro expansion failed: the macro '{}' expands to {:?} but a {:?} was expected" ,
248
+ mcall. path( ) . map( |p| p. to_string( ) ) . unwrap_or_default( ) ,
249
+ kind, expand_to
250
+ ) ,
251
+ range,
252
+ ) ) ;
253
+ }
254
+ } else {
255
+ let range = self . text_range_for_node ( mcall) ;
256
+
257
+ self . emit_parse_error ( & SyntaxError :: new (
258
+ format ! (
259
+ "macro expansion failed: could not resolve macro '{}'" ,
260
+ mcall. path( ) . map( |p| p. to_string( ) ) . unwrap_or_default( )
261
+ ) ,
262
+ range,
263
+ ) ) ;
264
+ }
265
+ }
266
+ }
136
267
}
0 commit comments