1- use crate :: generated:: { self , AstNode } ;
1+ use crate :: generated:: MacroCall ;
2+ use crate :: generated:: { self } ;
23use crate :: trap:: { DiagnosticSeverity , TrapFile , TrapId } ;
34use crate :: trap:: { Label , TrapClass } ;
45use codeql_extractor:: trap:: { self } ;
6+ use log:: Level ;
7+ use ra_ap_hir:: db:: ExpandDatabase ;
58use ra_ap_hir:: Semantics ;
69use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
710use ra_ap_ide_db:: RootDatabase ;
811use ra_ap_parser:: SyntaxKind ;
912use 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+ } ;
1116pub trait TextValue {
1217 fn try_get_text ( & self ) -> Option < String > ;
1318}
@@ -60,32 +65,35 @@ impl TextValue for ast::RangePat {
6065}
6166pub struct Translator < ' a > {
6267 pub trap : TrapFile ,
68+ path : & ' a str ,
6369 label : trap:: Label ,
6470 line_index : LineIndex ,
65- semi : Option < Semantics < ' a , RootDatabase > > ,
71+ pub semi : Option < Semantics < ' a , RootDatabase > > ,
6672}
6773
68- impl Translator < ' _ > {
74+ impl < ' a > Translator < ' a > {
6975 pub fn new (
7076 trap : TrapFile ,
77+ path : & ' a str ,
7178 label : trap:: Label ,
7279 line_index : LineIndex ,
73- semi : Option < Semantics < ' _ , RootDatabase > > ,
74- ) -> Translator {
80+ semi : Option < Semantics < ' a , RootDatabase > > ,
81+ ) -> Translator < ' a > {
7582 Translator {
7683 trap,
84+ path,
7785 label,
7886 line_index,
7987 semi,
8088 }
8189 }
82- pub fn location ( & self , range : TextRange ) -> ( LineCol , LineCol ) {
90+ fn location ( & self , range : TextRange ) -> ( LineCol , LineCol ) {
8391 let start = self . line_index . line_col ( range. start ( ) ) ;
8492 let range_end = range. end ( ) ;
8593 // QL end positions are inclusive, while TextRange offsets are exclusive and point at the position
8694 // right after the last character of the range. We need to shift the end offset one character to the left to
8795 // 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`
8997 // with decreasing offsets to find the start of the last character included in the range.
9098 for i in 1 ..4 {
9199 if let Some ( end) = range_end
@@ -98,28 +106,72 @@ impl Translator<'_> {
98106 let end = self . line_index . line_col ( range_end) ;
99107 ( start, end)
100108 }
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+ }
101118 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) ;
103121 self . trap . emit_location ( self . label , label, start, end)
104122 }
105123 pub fn emit_location_token ( & mut self , label : Label < generated:: Token > , token : & SyntaxToken ) {
106124 let ( start, end) = self . location ( token. text_range ( ) ) ;
107125 self . trap . emit_location ( self . label , label, start, end)
108126 }
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+ ) ;
113150 let location = self . trap . emit_location_label ( self . label , start, end) ;
114151 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 (
115163 DiagnosticSeverity :: Warning ,
116164 "parse_error" . to_owned ( ) ,
117165 message. clone ( ) ,
118166 message,
119167 location,
120168 ) ;
121169 }
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+ ) {
123175 for child in children {
124176 if let NodeOrToken :: Token ( token) = child {
125177 if token. kind ( ) == SyntaxKind :: COMMENT {
@@ -133,4 +185,83 @@ impl Translator<'_> {
133185 }
134186 }
135187 }
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+ }
136267}
0 commit comments