diff options
author | Paul Daniel Faria <[email protected]> | 2020-07-23 15:11:37 +0100 |
---|---|---|
committer | Paul Daniel Faria <[email protected]> | 2020-08-10 13:46:34 +0100 |
commit | a6af0272f7bf129a3063cdd7096f685fc58438e6 (patch) | |
tree | 8a7041a76beb5df60742ad16b6325938efd4b3da /crates/ra_hir/src | |
parent | 87cb09365cf841b559e76951eedb826f2d4d3dfd (diff) |
Move semantic logic into Semantics, fix missing tag for safe amp operator, using functional methods rather than clunky inline closure
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 1072b3971..f706a186e 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -25,7 +25,8 @@ use crate::{ | |||
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, |
27 | AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, | 27 | AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, |
28 | Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, | 28 | Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef, |
29 | VariantDef, | ||
29 | }; | 30 | }; |
30 | use resolver::TypeNs; | 31 | use resolver::TypeNs; |
31 | 32 | ||
@@ -280,45 +281,84 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
280 | self.imp.assert_contains_node(node) | 281 | self.imp.assert_contains_node(node) |
281 | } | 282 | } |
282 | 283 | ||
283 | pub fn is_unsafe_pat(&self, pat: &ast::Pat) -> bool { | 284 | pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> Option<()> { |
284 | let ty = (|| { | 285 | let expr = method_call_expr.expr()?; |
285 | let parent = match pat { | 286 | let field_expr = |
286 | ast::Pat::BindPat(bind_pat) => bind_pat.syntax().parent()?, | 287 | if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None }; |
287 | _ => return None, | 288 | let ty = self.type_of_expr(&field_expr.expr()?)?; |
288 | }; | 289 | if !ty.is_packed(self.db) { |
289 | 290 | return None; | |
290 | // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or | 291 | } |
291 | // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, | ||
292 | // so this tries to lookup the `BindPat` anywhere along that structure to the | ||
293 | // `RecordPat` so we can get the containing type. | ||
294 | let record_pat = ast::RecordFieldPat::cast(parent.clone()) | ||
295 | .and_then(|record_pat| record_pat.syntax().parent()) | ||
296 | .or_else(|| Some(parent.clone())) | ||
297 | .and_then(|parent| { | ||
298 | ast::RecordFieldPatList::cast(parent)? | ||
299 | .syntax() | ||
300 | .parent() | ||
301 | .and_then(ast::RecordPat::cast) | ||
302 | }); | ||
303 | |||
304 | // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if | ||
305 | // this is initialized from a `FieldExpr`. | ||
306 | if let Some(record_pat) = record_pat { | ||
307 | self.type_of_pat(&ast::Pat::RecordPat(record_pat)) | ||
308 | } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { | ||
309 | let field_expr = match let_stmt.initializer()? { | ||
310 | ast::Expr::FieldExpr(field_expr) => field_expr, | ||
311 | _ => return None, | ||
312 | }; | ||
313 | 292 | ||
314 | self.type_of_expr(&field_expr.expr()?) | 293 | let func = self.resolve_method_call(&method_call_expr)?; |
294 | if func.has_self_param(self.db) { | ||
295 | let params = func.params(self.db); | ||
296 | if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) { | ||
297 | Some(()) | ||
315 | } else { | 298 | } else { |
316 | None | 299 | None |
317 | } | 300 | } |
318 | })(); | 301 | } else { |
302 | None | ||
303 | } | ||
304 | } | ||
319 | 305 | ||
320 | // Binding a reference to a packed type is possibly unsafe. | 306 | pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { |
321 | ty.map(|ty| ty.is_packed(self.db)).unwrap_or(false) | 307 | ref_expr |
308 | .expr() | ||
309 | .and_then(|expr| { | ||
310 | let field_expr = match expr { | ||
311 | ast::Expr::FieldExpr(field_expr) => field_expr, | ||
312 | _ => return None, | ||
313 | }; | ||
314 | let expr = field_expr.expr()?; | ||
315 | self.type_of_expr(&expr) | ||
316 | }) | ||
317 | // Binding a reference to a packed type is possibly unsafe. | ||
318 | .map(|ty| ty.is_packed(self.db)) | ||
319 | .unwrap_or(false) | ||
320 | |||
321 | // FIXME This needs layout computation to be correct. It will highlight | ||
322 | // more than it should with the current implementation. | ||
323 | } | ||
324 | |||
325 | pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { | ||
326 | bind_pat | ||
327 | .syntax() | ||
328 | .parent() | ||
329 | .and_then(|parent| { | ||
330 | // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or | ||
331 | // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, | ||
332 | // so this tries to lookup the `BindPat` anywhere along that structure to the | ||
333 | // `RecordPat` so we can get the containing type. | ||
334 | let record_pat = ast::RecordFieldPat::cast(parent.clone()) | ||
335 | .and_then(|record_pat| record_pat.syntax().parent()) | ||
336 | .or_else(|| Some(parent.clone())) | ||
337 | .and_then(|parent| { | ||
338 | ast::RecordFieldPatList::cast(parent)? | ||
339 | .syntax() | ||
340 | .parent() | ||
341 | .and_then(ast::RecordPat::cast) | ||
342 | }); | ||
343 | |||
344 | // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if | ||
345 | // this is initialized from a `FieldExpr`. | ||
346 | if let Some(record_pat) = record_pat { | ||
347 | self.type_of_pat(&ast::Pat::RecordPat(record_pat)) | ||
348 | } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { | ||
349 | let field_expr = match let_stmt.initializer()? { | ||
350 | ast::Expr::FieldExpr(field_expr) => field_expr, | ||
351 | _ => return None, | ||
352 | }; | ||
353 | |||
354 | self.type_of_expr(&field_expr.expr()?) | ||
355 | } else { | ||
356 | None | ||
357 | } | ||
358 | }) | ||
359 | // Binding a reference to a packed type is possibly unsafe. | ||
360 | .map(|ty| ty.is_packed(self.db)) | ||
361 | .unwrap_or(false) | ||
322 | } | 362 | } |
323 | } | 363 | } |
324 | 364 | ||