1
1
use hir:: db:: ExpandDatabase ;
2
- use hir:: { InFile , MacroFileIdExt , Semantics } ;
2
+ use hir:: { ExpandResult , InFile , MacroFileIdExt , Semantics } ;
3
3
use ide_db:: base_db:: CrateId ;
4
4
use ide_db:: {
5
5
helpers:: pick_best_token, syntax_helpers:: prettify_macro_expansion, FileId , RootDatabase ,
6
6
} ;
7
7
use span:: { Edition , SpanMap , SyntaxContextId , TextRange , TextSize } ;
8
+ use stdx:: format_to;
8
9
use syntax:: { ast, ted, AstNode , NodeOrToken , SyntaxKind , SyntaxNode , T } ;
9
10
10
11
use crate :: FilePosition ;
@@ -63,17 +64,23 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
63
64
. take_while ( |it| it != & token)
64
65
. filter ( |it| it. kind ( ) == T ! [ , ] )
65
66
. count ( ) ;
66
- let expansion = expansions. get ( idx) ?. clone ( ) ;
67
+ let ExpandResult { err , value : expansion } = expansions. get ( idx) ?. clone ( ) ;
67
68
let expansion_file_id = sema. hir_file_for ( & expansion) . macro_file ( ) ?;
68
69
let expansion_span_map = db. expansion_span_map ( expansion_file_id) ;
69
- let expansion = format (
70
+ let mut expansion = format (
70
71
db,
71
72
SyntaxKind :: MACRO_ITEMS ,
72
73
position. file_id ,
73
74
expansion,
74
75
& expansion_span_map,
75
76
krate,
76
77
) ;
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
+ }
77
84
Some ( ExpandedMacro { name, expansion } )
78
85
} ) ;
79
86
@@ -83,6 +90,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
83
90
84
91
let mut anc = tok. parent_ancestors ( ) ;
85
92
let mut span_map = SpanMap :: empty ( ) ;
93
+ let mut error = String :: new ( ) ;
86
94
let ( name, expanded, kind) = loop {
87
95
let node = anc. next ( ) ?;
88
96
@@ -97,7 +105,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
97
105
. unwrap_or ( Edition :: CURRENT ) ,
98
106
)
99
107
. 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 ) ) ?,
101
109
SyntaxKind :: MACRO_ITEMS ,
102
110
) ;
103
111
}
@@ -112,6 +120,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
112
120
expand_macro_recur (
113
121
& sema,
114
122
& ast:: Item :: MacroCall ( mac) ,
123
+ & mut error,
115
124
& mut span_map,
116
125
TextSize :: new ( 0 ) ,
117
126
) ?,
@@ -123,24 +132,31 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
123
132
// FIXME:
124
133
// macro expansion may lose all white space information
125
134
// 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) ;
127
136
137
+ if !error. is_empty ( ) {
138
+ expansion. insert_str ( 0 , & format ! ( "Expansion had errors:{error}\n \n " ) ) ;
139
+ }
128
140
Some ( ExpandedMacro { name, expansion } )
129
141
}
130
142
131
143
fn expand_macro_recur (
132
144
sema : & Semantics < ' _ , RootDatabase > ,
133
145
macro_call : & ast:: Item ,
146
+ error : & mut String ,
134
147
result_span_map : & mut SpanMap < SyntaxContextId > ,
135
148
offset_in_original_node : TextSize ,
136
149
) -> 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) ?,
143
155
} ;
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
+ }
144
160
let file_id =
145
161
sema. hir_file_for ( & expanded) . macro_file ( ) . expect ( "expansion must produce a macro file" ) ;
146
162
let expansion_span_map = sema. db . expansion_span_map ( file_id) ;
@@ -149,12 +165,13 @@ fn expand_macro_recur(
149
165
expanded. text_range ( ) . len ( ) ,
150
166
& expansion_span_map,
151
167
) ;
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 ) )
153
169
}
154
170
155
171
fn expand (
156
172
sema : & Semantics < ' _ , RootDatabase > ,
157
173
expanded : SyntaxNode ,
174
+ error : & mut String ,
158
175
result_span_map : & mut SpanMap < SyntaxContextId > ,
159
176
mut offset_in_original_node : i32 ,
160
177
) -> SyntaxNode {
@@ -165,6 +182,7 @@ fn expand(
165
182
if let Some ( new_node) = expand_macro_recur (
166
183
sema,
167
184
& child,
185
+ error,
168
186
result_span_map,
169
187
TextSize :: new (
170
188
( offset_in_original_node + ( u32:: from ( child. syntax ( ) . text_range ( ) . start ( ) ) as i32 ) )
@@ -495,6 +513,9 @@ fn main() {
495
513
"# ,
496
514
expect ! [ [ r#"
497
515
foo!
516
+ Expansion had errors:
517
+ expected ident: `BAD`
518
+
498
519
"# ] ] ,
499
520
) ;
500
521
}
0 commit comments