11use hir:: db:: ExpandDatabase ;
2- use hir:: { InFile , MacroFileIdExt , Semantics } ;
2+ use hir:: { ExpandResult , InFile , MacroFileIdExt , Semantics } ;
33use ide_db:: base_db:: CrateId ;
44use ide_db:: {
55 helpers:: pick_best_token, syntax_helpers:: prettify_macro_expansion, FileId , RootDatabase ,
66} ;
77use span:: { Edition , SpanMap , SyntaxContextId , TextRange , TextSize } ;
8+ use stdx:: format_to;
89use syntax:: { ast, ted, AstNode , NodeOrToken , SyntaxKind , SyntaxNode , T } ;
910
1011use crate :: FilePosition ;
@@ -63,17 +64,23 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
6364 . take_while ( |it| it != & token)
6465 . filter ( |it| it. kind ( ) == T ! [ , ] )
6566 . count ( ) ;
66- let expansion = expansions. get ( idx) ?. clone ( ) ;
67+ let ExpandResult { err , value : expansion } = expansions. get ( idx) ?. clone ( ) ;
6768 let expansion_file_id = sema. hir_file_for ( & expansion) . macro_file ( ) ?;
6869 let expansion_span_map = db. expansion_span_map ( expansion_file_id) ;
69- let expansion = format (
70+ let mut expansion = format (
7071 db,
7172 SyntaxKind :: MACRO_ITEMS ,
7273 position. file_id ,
7374 expansion,
7475 & expansion_span_map,
7576 krate,
7677 ) ;
78+ if let Some ( err) = err {
79+ expansion. insert_str (
80+ 0 ,
81+ & format ! ( "Expansion had errors: {}\n \n " , err. render_to_string( sema. db) ) ,
82+ ) ;
83+ }
7784 Some ( ExpandedMacro { name, expansion } )
7885 } ) ;
7986
@@ -83,6 +90,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
8390
8491 let mut anc = tok. parent_ancestors ( ) ;
8592 let mut span_map = SpanMap :: empty ( ) ;
93+ let mut error = String :: new ( ) ;
8694 let ( name, expanded, kind) = loop {
8795 let node = anc. next ( ) ?;
8896
@@ -97,7 +105,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
97105 . unwrap_or ( Edition :: CURRENT ) ,
98106 )
99107 . to_string ( ) ,
100- expand_macro_recur ( & sema, & item, & mut span_map, TextSize :: new ( 0 ) ) ?,
108+ expand_macro_recur ( & sema, & item, & mut error , & mut span_map, TextSize :: new ( 0 ) ) ?,
101109 SyntaxKind :: MACRO_ITEMS ,
102110 ) ;
103111 }
@@ -112,6 +120,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
112120 expand_macro_recur (
113121 & sema,
114122 & ast:: Item :: MacroCall ( mac) ,
123+ & mut error,
115124 & mut span_map,
116125 TextSize :: new ( 0 ) ,
117126 ) ?,
@@ -123,24 +132,31 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
123132 // FIXME:
124133 // macro expansion may lose all white space information
125134 // But we hope someday we can use ra_fmt for that
126- let expansion = format ( db, kind, position. file_id , expanded, & span_map, krate) ;
135+ let mut expansion = format ( db, kind, position. file_id , expanded, & span_map, krate) ;
127136
137+ if !error. is_empty ( ) {
138+ expansion. insert_str ( 0 , & format ! ( "Expansion had errors:{error}\n \n " ) ) ;
139+ }
128140 Some ( ExpandedMacro { name, expansion } )
129141}
130142
131143fn expand_macro_recur (
132144 sema : & Semantics < ' _ , RootDatabase > ,
133145 macro_call : & ast:: Item ,
146+ error : & mut String ,
134147 result_span_map : & mut SpanMap < SyntaxContextId > ,
135148 offset_in_original_node : TextSize ,
136149) -> Option < SyntaxNode > {
137- let expanded = match macro_call {
138- item @ ast:: Item :: MacroCall ( macro_call) => sema
139- . expand_attr_macro ( item)
140- . or_else ( || sema. expand_allowed_builtins ( macro_call) ) ?
141- . clone_for_update ( ) ,
142- item => sema. expand_attr_macro ( item) ?. clone_for_update ( ) ,
150+ let ExpandResult { value : expanded, err } = match macro_call {
151+ item @ ast:: Item :: MacroCall ( macro_call) => {
152+ sema. expand_attr_macro ( item) . or_else ( || sema. expand_allowed_builtins ( macro_call) ) ?
153+ }
154+ item => sema. expand_attr_macro ( item) ?,
143155 } ;
156+ let expanded = expanded. clone_for_update ( ) ;
157+ if let Some ( err) = err {
158+ format_to ! ( error, "\n {}" , err. render_to_string( sema. db) ) ;
159+ }
144160 let file_id =
145161 sema. hir_file_for ( & expanded) . macro_file ( ) . expect ( "expansion must produce a macro file" ) ;
146162 let expansion_span_map = sema. db . expansion_span_map ( file_id) ;
@@ -149,12 +165,13 @@ fn expand_macro_recur(
149165 expanded. text_range ( ) . len ( ) ,
150166 & expansion_span_map,
151167 ) ;
152- Some ( expand ( sema, expanded, result_span_map, u32:: from ( offset_in_original_node) as i32 ) )
168+ Some ( expand ( sema, expanded, error , result_span_map, u32:: from ( offset_in_original_node) as i32 ) )
153169}
154170
155171fn expand (
156172 sema : & Semantics < ' _ , RootDatabase > ,
157173 expanded : SyntaxNode ,
174+ error : & mut String ,
158175 result_span_map : & mut SpanMap < SyntaxContextId > ,
159176 mut offset_in_original_node : i32 ,
160177) -> SyntaxNode {
@@ -165,6 +182,7 @@ fn expand(
165182 if let Some ( new_node) = expand_macro_recur (
166183 sema,
167184 & child,
185+ error,
168186 result_span_map,
169187 TextSize :: new (
170188 ( offset_in_original_node + ( u32:: from ( child. syntax ( ) . text_range ( ) . start ( ) ) as i32 ) )
@@ -495,6 +513,9 @@ fn main() {
495513"# ,
496514 expect ! [ [ r#"
497515 foo!
516+ Expansion had errors:
517+ expected ident: `BAD`
518+
498519 "# ] ] ,
499520 ) ;
500521 }
0 commit comments