@@ -25,7 +25,10 @@ use hir_def::{
25
25
} ;
26
26
use hir_expand:: { hygiene:: Hygiene , name:: AsName , HirFileId , InFile } ;
27
27
use hir_ty:: {
28
- diagnostics:: { record_literal_missing_fields, record_pattern_missing_fields} ,
28
+ diagnostics:: {
29
+ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
30
+ UnsafeExpr ,
31
+ } ,
29
32
Adjust , Adjustment , AutoBorrow , InferenceResult , Interner , Substitution , TyExt ,
30
33
TyLoweringContext ,
31
34
} ;
@@ -46,8 +49,7 @@ use base_db::CrateId;
46
49
pub ( crate ) struct SourceAnalyzer {
47
50
pub ( crate ) file_id : HirFileId ,
48
51
pub ( crate ) resolver : Resolver ,
49
- body : Option < Arc < Body > > ,
50
- body_source_map : Option < Arc < BodySourceMap > > ,
52
+ def : Option < ( DefWithBodyId , Arc < Body > , Arc < BodySourceMap > ) > ,
51
53
infer : Option < Arc < InferenceResult > > ,
52
54
}
53
55
@@ -67,8 +69,7 @@ impl SourceAnalyzer {
67
69
let resolver = resolver_for_scope ( db. upcast ( ) , def, scope) ;
68
70
SourceAnalyzer {
69
71
resolver,
70
- body : Some ( body) ,
71
- body_source_map : Some ( source_map) ,
72
+ def : Some ( ( def, body, source_map) ) ,
72
73
infer : Some ( db. infer ( def) ) ,
73
74
file_id,
74
75
}
@@ -87,26 +88,21 @@ impl SourceAnalyzer {
87
88
Some ( offset) => scope_for_offset ( db, & scopes, & source_map, node. with_value ( offset) ) ,
88
89
} ;
89
90
let resolver = resolver_for_scope ( db. upcast ( ) , def, scope) ;
90
- SourceAnalyzer {
91
- resolver,
92
- body : Some ( body) ,
93
- body_source_map : Some ( source_map) ,
94
- infer : None ,
95
- file_id,
96
- }
91
+ SourceAnalyzer { resolver, def : Some ( ( def, body, source_map) ) , infer : None , file_id }
97
92
}
98
93
99
94
pub ( crate ) fn new_for_resolver (
100
95
resolver : Resolver ,
101
96
node : InFile < & SyntaxNode > ,
102
97
) -> SourceAnalyzer {
103
- SourceAnalyzer {
104
- resolver,
105
- body : None ,
106
- body_source_map : None ,
107
- infer : None ,
108
- file_id : node. file_id ,
109
- }
98
+ SourceAnalyzer { resolver, def : None , infer : None , file_id : node. file_id }
99
+ }
100
+
101
+ fn body_source_map ( & self ) -> Option < & BodySourceMap > {
102
+ self . def . as_ref ( ) . map ( |( .., source_map) | & * * source_map)
103
+ }
104
+ fn body ( & self ) -> Option < & Body > {
105
+ self . def . as_ref ( ) . map ( |( _, body, _) | & * * body)
110
106
}
111
107
112
108
fn expr_id ( & self , db : & dyn HirDatabase , expr : & ast:: Expr ) -> Option < ExprId > {
@@ -116,22 +112,22 @@ impl SourceAnalyzer {
116
112
}
117
113
_ => InFile :: new ( self . file_id , expr. clone ( ) ) ,
118
114
} ;
119
- let sm = self . body_source_map . as_ref ( ) ?;
115
+ let sm = self . body_source_map ( ) ?;
120
116
sm. node_expr ( src. as_ref ( ) )
121
117
}
122
118
123
119
fn pat_id ( & self , pat : & ast:: Pat ) -> Option < PatId > {
124
120
// FIXME: macros, see `expr_id`
125
121
let src = InFile { file_id : self . file_id , value : pat } ;
126
- self . body_source_map . as_ref ( ) ?. node_pat ( src)
122
+ self . body_source_map ( ) ?. node_pat ( src)
127
123
}
128
124
129
125
fn expand_expr (
130
126
& self ,
131
127
db : & dyn HirDatabase ,
132
128
expr : InFile < ast:: MacroCall > ,
133
129
) -> Option < InFile < ast:: Expr > > {
134
- let macro_file = self . body_source_map . as_ref ( ) ?. node_macro_file ( expr. as_ref ( ) ) ?;
130
+ let macro_file = self . body_source_map ( ) ?. node_macro_file ( expr. as_ref ( ) ) ?;
135
131
let expanded = db. parse_or_expand ( macro_file) ?;
136
132
137
133
let res = match ast:: MacroCall :: cast ( expanded. clone ( ) ) {
@@ -196,7 +192,7 @@ impl SourceAnalyzer {
196
192
param : & ast:: SelfParam ,
197
193
) -> Option < Type > {
198
194
let src = InFile { file_id : self . file_id , value : param } ;
199
- let pat_id = self . body_source_map . as_ref ( ) ?. node_self_param ( src) ?;
195
+ let pat_id = self . body_source_map ( ) ?. node_self_param ( src) ?;
200
196
let ty = self . infer . as_ref ( ) ?[ pat_id] . clone ( ) ;
201
197
Type :: new_with_resolver ( db, & self . resolver , ty)
202
198
}
@@ -226,7 +222,7 @@ impl SourceAnalyzer {
226
222
) -> Option < ( Field , Option < Local > , Type ) > {
227
223
let record_expr = ast:: RecordExpr :: cast ( field. syntax ( ) . parent ( ) . and_then ( |p| p. parent ( ) ) ?) ?;
228
224
let expr = ast:: Expr :: from ( record_expr) ;
229
- let expr_id = self . body_source_map . as_ref ( ) ?. node_expr ( InFile :: new ( self . file_id , & expr) ) ?;
225
+ let expr_id = self . body_source_map ( ) ?. node_expr ( InFile :: new ( self . file_id , & expr) ) ?;
230
226
231
227
let local_name = field. field_name ( ) ?. as_name ( ) ;
232
228
let local = if field. name_ref ( ) . is_some ( ) {
@@ -279,7 +275,7 @@ impl SourceAnalyzer {
279
275
pat : & ast:: IdentPat ,
280
276
) -> Option < ModuleDef > {
281
277
let pat_id = self . pat_id ( & pat. clone ( ) . into ( ) ) ?;
282
- let body = self . body . as_ref ( ) ?;
278
+ let body = self . body ( ) ?;
283
279
let path = match & body[ pat_id] {
284
280
Pat :: Path ( path) => path,
285
281
_ => return None ,
@@ -415,7 +411,7 @@ impl SourceAnalyzer {
415
411
literal : & ast:: RecordExpr ,
416
412
) -> Option < Vec < ( Field , Type ) > > {
417
413
let krate = self . resolver . krate ( ) ?;
418
- let body = self . body . as_ref ( ) ?;
414
+ let body = self . body ( ) ?;
419
415
let infer = self . infer . as_ref ( ) ?;
420
416
421
417
let expr_id = self . expr_id ( db, & literal. clone ( ) . into ( ) ) ?;
@@ -433,7 +429,7 @@ impl SourceAnalyzer {
433
429
pattern : & ast:: RecordPat ,
434
430
) -> Option < Vec < ( Field , Type ) > > {
435
431
let krate = self . resolver . krate ( ) ?;
436
- let body = self . body . as_ref ( ) ?;
432
+ let body = self . body ( ) ?;
437
433
let infer = self . infer . as_ref ( ) ?;
438
434
439
435
let pat_id = self . pat_id ( & pattern. clone ( ) . into ( ) ) ?;
@@ -488,6 +484,34 @@ impl SourceAnalyzer {
488
484
let expr_id = self . expr_id ( db, & record_lit. into ( ) ) ?;
489
485
infer. variant_resolution_for_expr ( expr_id)
490
486
}
487
+
488
+ pub ( crate ) fn is_unsafe_macro_call (
489
+ & self ,
490
+ db : & dyn HirDatabase ,
491
+ macro_call : InFile < & ast:: MacroCall > ,
492
+ ) -> bool {
493
+ if let ( Some ( ( def, body, sm) ) , Some ( infer) ) = ( & self . def , & self . infer ) {
494
+ if let Some ( expr_ids) = sm. macro_expansion_expr ( macro_call) {
495
+ let mut is_unsafe = false ;
496
+ for & expr_id in expr_ids {
497
+ unsafe_expressions (
498
+ db,
499
+ infer,
500
+ * def,
501
+ body,
502
+ expr_id,
503
+ & mut |UnsafeExpr { inside_unsafe_block, .. } | {
504
+ is_unsafe |= !inside_unsafe_block
505
+ } ,
506
+ ) ;
507
+ if is_unsafe {
508
+ return true ;
509
+ }
510
+ }
511
+ }
512
+ }
513
+ false
514
+ }
491
515
}
492
516
493
517
fn scope_for (
0 commit comments