From 6cde0b1aa0f6b8623c6b81b2396f4a0345891233 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sat, 8 Aug 2020 14:14:18 -0400 Subject: Add support for extern crate This adds syntax highlighting, hover and goto def functionality for extern crate --- crates/ra_hir/src/semantics.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 307b336f2..e392130ab 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -8,7 +8,7 @@ use hir_def::{ resolver::{self, HasResolver, Resolver}, AsMacroCall, FunctionId, TraitId, VariantId, }; -use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; +use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, name::AsName, ExpansionInfo}; use hir_ty::associated_type_shorthand_candidates; use itertools::Itertools; use ra_db::{FileId, FileRange}; @@ -24,8 +24,8 @@ use crate::{ diagnostics::Diagnostic, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, - AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, - ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, + AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, + Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, }; use resolver::TypeNs; @@ -228,6 +228,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_path(path) } + pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option { + self.imp.resolve_extern_crate(extern_crate) + } + pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { self.imp.resolve_variant(record_lit).map(VariantDef::from) } @@ -443,6 +447,17 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax()).resolve_path(self.db, path) } + fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option { + let krate = self.scope(extern_crate.syntax()).krate()?; + krate.dependencies(self.db).into_iter().find_map(|dep| { + if dep.name == extern_crate.name_ref()?.as_name() { + Some(dep.krate) + } else { + None + } + }) + } + fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) } @@ -612,6 +627,10 @@ impl<'a> SemanticsScope<'a> { Some(Module { id: self.resolver.module()? }) } + pub fn krate(&self) -> Option { + Some(Crate { id: self.resolver.krate()? }) + } + /// Note: `FxHashSet` should be treated as an opaque type, passed into `Type // FIXME: rename to visible_traits to not repeat scope? pub fn traits_in_scope(&self) -> FxHashSet { -- cgit v1.2.3 From bf9b4578bbe038501ef7c337e22b448de477f61c Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 9 Aug 2020 18:52:19 -0400 Subject: Remove Option<...> from result of Crate::root_module There doesn't seem to be any need for it, and removing it simplies several paths of code that depend on it. --- crates/ra_hir/src/code_model.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 27cdabea0..44456e49e 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -83,9 +83,9 @@ impl Crate { .collect() } - pub fn root_module(self, db: &dyn HirDatabase) -> Option { + pub fn root_module(self, db: &dyn HirDatabase) -> Module { let module_id = db.crate_def_map(self.id).root; - Some(Module::new(self, module_id)) + Module::new(self, module_id) } pub fn root_file(self, db: &dyn HirDatabase) -> FileId { -- cgit v1.2.3 From 263f9a7f231a474dd56d02adbcd7c57d079e88fd Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Wed, 3 Jun 2020 23:38:25 -0400 Subject: Add tracking of packed repr, use it to highlight unsafe refs Taking a reference to a misaligned field on a packed struct is an unsafe operation. Highlight that behavior. Currently, the misaligned part isn't tracked, so this highlight is a bit too aggressive. --- crates/ra_hir/src/code_model.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 44456e49e..6f9c56d29 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -4,6 +4,7 @@ use std::{iter, sync::Arc}; use arrayvec::ArrayVec; use either::Either; use hir_def::{ + adt::ReprKind, adt::StructKind, adt::VariantData, builtin_type::BuiltinType, @@ -431,6 +432,10 @@ impl Struct { Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) } + pub fn is_packed(self, db: &dyn HirDatabase) -> bool { + matches!(db.struct_data(self.id).repr, Some(ReprKind::Packed)) + } + fn variant_data(self, db: &dyn HirDatabase) -> Arc { db.struct_data(self.id).variant_data.clone() } @@ -1253,6 +1258,19 @@ impl Type { ) } + pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { + let adt_id = match self.ty.value { + Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_id), .. }) => adt_id, + _ => return false, + }; + + let adt = adt_id.into(); + match adt { + Adt::Struct(s) => s.is_packed(db), + _ => false, + } + } + pub fn is_raw_ptr(&self) -> bool { matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) } -- cgit v1.2.3 From fd30134cf84b134259fe8140e513b152e37f3f88 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Mon, 15 Jun 2020 07:19:45 -0400 Subject: Remove token tree from ReprKind::Other variant, expose ReprKind higher, remove debug println. --- crates/ra_hir/src/code_model.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 6f9c56d29..0007d7fa8 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -432,8 +432,8 @@ impl Struct { Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) } - pub fn is_packed(self, db: &dyn HirDatabase) -> bool { - matches!(db.struct_data(self.id).repr, Some(ReprKind::Packed)) + pub fn repr(self, db: &dyn HirDatabase) -> Option { + db.struct_data(self.id).repr.clone() } fn variant_data(self, db: &dyn HirDatabase) -> Arc { @@ -1266,7 +1266,7 @@ impl Type { let adt = adt_id.into(); match adt { - Adt::Struct(s) => s.is_packed(db), + Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), _ => false, } } -- cgit v1.2.3 From d5f11e530dbf6edbdd0ca32d6cd5fafe634c8c4a Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sat, 27 Jun 2020 17:11:43 -0400 Subject: Unsafe borrow of packed fields: account for borrow through ref binding, auto ref function calls --- crates/ra_hir/src/code_model.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 0007d7fa8..a880fa671 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -11,6 +11,7 @@ use hir_def::{ docs::Documentation, expr::{BindingAnnotation, Pat, PatId}, import_map, + item_tree::SelfParam, per_ns::PerNs, resolver::{HasResolver, Resolver}, src::HasSource as _, @@ -670,8 +671,8 @@ impl Function { db.function_data(self.id).name.clone() } - pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).has_self_param + pub fn self_param(self, db: &dyn HirDatabase) -> Option { + db.function_data(self.id).self_param } pub fn params(self, db: &dyn HirDatabase) -> Vec { -- cgit v1.2.3 From c5cc24cb312c70159e63315ea49769b575e8cb65 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 28 Jun 2020 16:04:00 -0400 Subject: Revert function structs back to using bool to track self param, use first param for self information in syntax highlighting instead --- crates/ra_hir/src/code_model.rs | 5 ++--- crates/ra_hir/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index a880fa671..0007d7fa8 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -11,7 +11,6 @@ use hir_def::{ docs::Documentation, expr::{BindingAnnotation, Pat, PatId}, import_map, - item_tree::SelfParam, per_ns::PerNs, resolver::{HasResolver, Resolver}, src::HasSource as _, @@ -671,8 +670,8 @@ impl Function { db.function_data(self.id).name.clone() } - pub fn self_param(self, db: &dyn HirDatabase) -> Option { - db.function_data(self.id).self_param + pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { + db.function_data(self.id).has_self_param } pub fn params(self, db: &dyn HirDatabase) -> Vec { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 31f3241c9..34b02c536 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -49,7 +49,7 @@ pub use hir_def::{ docs::Documentation, nameres::ModuleSource, path::{ModPath, Path, PathKind}, - type_ref::Mutability, + type_ref::{Mutability, TypeRef}, }; pub use hir_expand::{ hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, -- cgit v1.2.3 From 08182aa9fad4021e60cdc80ee0a578929507e115 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sun, 19 Jul 2020 11:45:46 -0400 Subject: Move unsafe packed ref logic to Semantics, use `Attrs::by_key` to simplify repr attr lookup --- crates/ra_hir/src/semantics.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index e392130ab..1072b3971 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -279,6 +279,47 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub fn assert_contains_node(&self, node: &SyntaxNode) { self.imp.assert_contains_node(node) } + + pub fn is_unsafe_pat(&self, pat: &ast::Pat) -> bool { + let ty = (|| { + let parent = match pat { + ast::Pat::BindPat(bind_pat) => bind_pat.syntax().parent()?, + _ => return None, + }; + + // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or + // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, + // so this tries to lookup the `BindPat` anywhere along that structure to the + // `RecordPat` so we can get the containing type. + let record_pat = ast::RecordFieldPat::cast(parent.clone()) + .and_then(|record_pat| record_pat.syntax().parent()) + .or_else(|| Some(parent.clone())) + .and_then(|parent| { + ast::RecordFieldPatList::cast(parent)? + .syntax() + .parent() + .and_then(ast::RecordPat::cast) + }); + + // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if + // this is initialized from a `FieldExpr`. + if let Some(record_pat) = record_pat { + self.type_of_pat(&ast::Pat::RecordPat(record_pat)) + } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { + let field_expr = match let_stmt.initializer()? { + ast::Expr::FieldExpr(field_expr) => field_expr, + _ => return None, + }; + + self.type_of_expr(&field_expr.expr()?) + } else { + None + } + })(); + + // Binding a reference to a packed type is possibly unsafe. + ty.map(|ty| ty.is_packed(self.db)).unwrap_or(false) + } } impl<'db> SemanticsImpl<'db> { -- cgit v1.2.3 From a6af0272f7bf129a3063cdd7096f685fc58438e6 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 23 Jul 2020 10:11:37 -0400 Subject: Move semantic logic into Semantics, fix missing tag for safe amp operator, using functional methods rather than clunky inline closure --- crates/ra_hir/src/semantics.rs | 110 ++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 35 deletions(-) (limited to 'crates/ra_hir') 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::{ semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, - Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, + Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef, + VariantDef, }; use resolver::TypeNs; @@ -280,45 +281,84 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.assert_contains_node(node) } - pub fn is_unsafe_pat(&self, pat: &ast::Pat) -> bool { - let ty = (|| { - let parent = match pat { - ast::Pat::BindPat(bind_pat) => bind_pat.syntax().parent()?, - _ => return None, - }; - - // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or - // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, - // so this tries to lookup the `BindPat` anywhere along that structure to the - // `RecordPat` so we can get the containing type. - let record_pat = ast::RecordFieldPat::cast(parent.clone()) - .and_then(|record_pat| record_pat.syntax().parent()) - .or_else(|| Some(parent.clone())) - .and_then(|parent| { - ast::RecordFieldPatList::cast(parent)? - .syntax() - .parent() - .and_then(ast::RecordPat::cast) - }); - - // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if - // this is initialized from a `FieldExpr`. - if let Some(record_pat) = record_pat { - self.type_of_pat(&ast::Pat::RecordPat(record_pat)) - } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { - let field_expr = match let_stmt.initializer()? { - ast::Expr::FieldExpr(field_expr) => field_expr, - _ => return None, - }; + pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> Option<()> { + let expr = method_call_expr.expr()?; + let field_expr = + if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None }; + let ty = self.type_of_expr(&field_expr.expr()?)?; + if !ty.is_packed(self.db) { + return None; + } - self.type_of_expr(&field_expr.expr()?) + let func = self.resolve_method_call(&method_call_expr)?; + if func.has_self_param(self.db) { + let params = func.params(self.db); + if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) { + Some(()) } else { None } - })(); + } else { + None + } + } - // Binding a reference to a packed type is possibly unsafe. - ty.map(|ty| ty.is_packed(self.db)).unwrap_or(false) + pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { + ref_expr + .expr() + .and_then(|expr| { + let field_expr = match expr { + ast::Expr::FieldExpr(field_expr) => field_expr, + _ => return None, + }; + let expr = field_expr.expr()?; + self.type_of_expr(&expr) + }) + // Binding a reference to a packed type is possibly unsafe. + .map(|ty| ty.is_packed(self.db)) + .unwrap_or(false) + + // FIXME This needs layout computation to be correct. It will highlight + // more than it should with the current implementation. + } + + pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { + bind_pat + .syntax() + .parent() + .and_then(|parent| { + // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or + // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, + // so this tries to lookup the `BindPat` anywhere along that structure to the + // `RecordPat` so we can get the containing type. + let record_pat = ast::RecordFieldPat::cast(parent.clone()) + .and_then(|record_pat| record_pat.syntax().parent()) + .or_else(|| Some(parent.clone())) + .and_then(|parent| { + ast::RecordFieldPatList::cast(parent)? + .syntax() + .parent() + .and_then(ast::RecordPat::cast) + }); + + // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if + // this is initialized from a `FieldExpr`. + if let Some(record_pat) = record_pat { + self.type_of_pat(&ast::Pat::RecordPat(record_pat)) + } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { + let field_expr = match let_stmt.initializer()? { + ast::Expr::FieldExpr(field_expr) => field_expr, + _ => return None, + }; + + self.type_of_expr(&field_expr.expr()?) + } else { + None + } + }) + // Binding a reference to a packed type is possibly unsafe. + .map(|ty| ty.is_packed(self.db)) + .unwrap_or(false) } } -- cgit v1.2.3 From 39fdd41df4052cef5da4876067ae28615012476b Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 23 Jul 2020 18:31:28 -0400 Subject: Return bool from is_unsafe_method_call and cleanup usages --- crates/ra_hir/src/semantics.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index f706a186e..9697c7082 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -281,26 +281,26 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.assert_contains_node(node) } - pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> Option<()> { - let expr = method_call_expr.expr()?; - let field_expr = - if let ast::Expr::FieldExpr(field_expr) = expr { field_expr } else { return None }; - let ty = self.type_of_expr(&field_expr.expr()?)?; - if !ty.is_packed(self.db) { - return None; - } + pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool { + method_call_expr + .expr() + .and_then(|expr| { + let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { + field_expr + } else { + return None; + }; + let ty = self.type_of_expr(&field_expr.expr()?)?; + if !ty.is_packed(self.db) { + return None; + } - let func = self.resolve_method_call(&method_call_expr)?; - if func.has_self_param(self.db) { - let params = func.params(self.db); - if matches!(params.into_iter().next(), Some(TypeRef::Reference(..))) { - Some(()) - } else { - None - } - } else { - None - } + let func = self.resolve_method_call(&method_call_expr)?; + let is_unsafe = func.has_self_param(self.db) + && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..))); + Some(is_unsafe) + }) + .unwrap_or(false) } pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { -- cgit v1.2.3 From 61dff939f909e0c53bcd3be4c3e672c794022cde Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 30 Jul 2020 09:26:40 -0400 Subject: Move unsafe semantics methods into `SemanticsImpl` and reference them in `Semantics` --- crates/ra_hir/src/semantics.rs | 154 ++++++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 71 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 9697c7082..758d00409 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -282,83 +282,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { } pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool { - method_call_expr - .expr() - .and_then(|expr| { - let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { - field_expr - } else { - return None; - }; - let ty = self.type_of_expr(&field_expr.expr()?)?; - if !ty.is_packed(self.db) { - return None; - } - - let func = self.resolve_method_call(&method_call_expr)?; - let is_unsafe = func.has_self_param(self.db) - && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..))); - Some(is_unsafe) - }) - .unwrap_or(false) + self.imp.is_unsafe_method_call(method_call_expr) } pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { - ref_expr - .expr() - .and_then(|expr| { - let field_expr = match expr { - ast::Expr::FieldExpr(field_expr) => field_expr, - _ => return None, - }; - let expr = field_expr.expr()?; - self.type_of_expr(&expr) - }) - // Binding a reference to a packed type is possibly unsafe. - .map(|ty| ty.is_packed(self.db)) - .unwrap_or(false) - - // FIXME This needs layout computation to be correct. It will highlight - // more than it should with the current implementation. + self.imp.is_unsafe_ref_expr(ref_expr) } pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { - bind_pat - .syntax() - .parent() - .and_then(|parent| { - // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or - // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, - // so this tries to lookup the `BindPat` anywhere along that structure to the - // `RecordPat` so we can get the containing type. - let record_pat = ast::RecordFieldPat::cast(parent.clone()) - .and_then(|record_pat| record_pat.syntax().parent()) - .or_else(|| Some(parent.clone())) - .and_then(|parent| { - ast::RecordFieldPatList::cast(parent)? - .syntax() - .parent() - .and_then(ast::RecordPat::cast) - }); - - // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if - // this is initialized from a `FieldExpr`. - if let Some(record_pat) = record_pat { - self.type_of_pat(&ast::Pat::RecordPat(record_pat)) - } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { - let field_expr = match let_stmt.initializer()? { - ast::Expr::FieldExpr(field_expr) => field_expr, - _ => return None, - }; - - self.type_of_expr(&field_expr.expr()?) - } else { - None - } - }) - // Binding a reference to a packed type is possibly unsafe. - .map(|ty| ty.is_packed(self.db)) - .unwrap_or(false) + self.imp.is_unsafe_bind_pat(bind_pat) } } @@ -655,6 +587,86 @@ impl<'db> SemanticsImpl<'db> { }); InFile::new(file_id, node) } + + pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool { + method_call_expr + .expr() + .and_then(|expr| { + let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { + field_expr + } else { + return None; + }; + let ty = self.type_of_expr(&field_expr.expr()?)?; + if !ty.is_packed(self.db) { + return None; + } + + let func = self.resolve_method_call(&method_call_expr).map(Function::from)?; + let is_unsafe = func.has_self_param(self.db) + && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..))); + Some(is_unsafe) + }) + .unwrap_or(false) + } + + pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { + ref_expr + .expr() + .and_then(|expr| { + let field_expr = match expr { + ast::Expr::FieldExpr(field_expr) => field_expr, + _ => return None, + }; + let expr = field_expr.expr()?; + self.type_of_expr(&expr) + }) + // Binding a reference to a packed type is possibly unsafe. + .map(|ty| ty.is_packed(self.db)) + .unwrap_or(false) + + // FIXME This needs layout computation to be correct. It will highlight + // more than it should with the current implementation. + } + + pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { + bind_pat + .syntax() + .parent() + .and_then(|parent| { + // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or + // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, + // so this tries to lookup the `BindPat` anywhere along that structure to the + // `RecordPat` so we can get the containing type. + let record_pat = ast::RecordFieldPat::cast(parent.clone()) + .and_then(|record_pat| record_pat.syntax().parent()) + .or_else(|| Some(parent.clone())) + .and_then(|parent| { + ast::RecordFieldPatList::cast(parent)? + .syntax() + .parent() + .and_then(ast::RecordPat::cast) + }); + + // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if + // this is initialized from a `FieldExpr`. + if let Some(record_pat) = record_pat { + self.type_of_pat(&ast::Pat::RecordPat(record_pat)) + } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { + let field_expr = match let_stmt.initializer()? { + ast::Expr::FieldExpr(field_expr) => field_expr, + _ => return None, + }; + + self.type_of_expr(&field_expr.expr()?) + } else { + None + } + }) + // Binding a reference to a packed type is possibly unsafe. + .map(|ty| ty.is_packed(self.db)) + .unwrap_or(false) + } } pub trait ToDef: AstNode + Clone { -- cgit v1.2.3 From 2199d0cda9c745ecb460dd987b8da982d02bc130 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Fri, 7 Aug 2020 10:40:09 -0400 Subject: Fix type names broken by rebase, redo expected test because of rebase --- crates/ra_hir/src/semantics.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 758d00409..872f5fa4c 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -289,8 +289,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.is_unsafe_ref_expr(ref_expr) } - pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { - self.imp.is_unsafe_bind_pat(bind_pat) + pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool { + self.imp.is_unsafe_ident_pat(ident_pat) } } @@ -629,20 +629,24 @@ impl<'db> SemanticsImpl<'db> { // more than it should with the current implementation. } - pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { - bind_pat + pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool { + if !ident_pat.ref_token().is_some() { + return false; + } + + ident_pat .syntax() .parent() .and_then(|parent| { - // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or - // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`, - // so this tries to lookup the `BindPat` anywhere along that structure to the + // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or + // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`, + // so this tries to lookup the `IdentPat` anywhere along that structure to the // `RecordPat` so we can get the containing type. - let record_pat = ast::RecordFieldPat::cast(parent.clone()) + let record_pat = ast::RecordPatField::cast(parent.clone()) .and_then(|record_pat| record_pat.syntax().parent()) .or_else(|| Some(parent.clone())) .and_then(|parent| { - ast::RecordFieldPatList::cast(parent)? + ast::RecordPatFieldList::cast(parent)? .syntax() .parent() .and_then(ast::RecordPat::cast) -- cgit v1.2.3 From ee1586c1ed058ff0f090b552d52fe6bbe2dd7f7f Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 27 Jul 2020 22:46:25 +0300 Subject: Better naming --- crates/ra_hir/src/semantics.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index e392130ab..1c5dc3d51 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -145,6 +145,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.original_range(node) } + pub fn diagnostics_fix_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + self.imp.diagnostics_fix_range(diagnostics) + } + pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { self.imp.diagnostics_range(diagnostics) } @@ -376,6 +380,13 @@ impl<'db> SemanticsImpl<'db> { original_range(self.db, node.as_ref()) } + fn diagnostics_fix_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + let src = diagnostics.fix_source(); + let root = self.db.parse_or_expand(src.file_id).unwrap(); + let node = src.value.to_node(&root); + original_range(self.db, src.with_value(&node)) + } + fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { let src = diagnostics.source(); let root = self.db.parse_or_expand(src.file_id).unwrap(); -- cgit v1.2.3 From 9963f43d51071ea02f8f6d490b9c49882034b42c Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 9 Aug 2020 01:59:26 +0300 Subject: Refactor the diagnostics --- crates/ra_hir/src/semantics.rs | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 1c5dc3d51..b4420d378 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -109,11 +109,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.parse(file_id) } - pub fn ast(&self, d: &T) -> ::AST { - let file_id = d.source().file_id; + pub fn diagnostic_fix_source( + &self, + d: &T, + ) -> ::AST { + let file_id = d.presentation().file_id; let root = self.db.parse_or_expand(file_id).unwrap(); self.imp.cache(root, file_id); - d.ast(self.db.upcast()) + d.fix_source(self.db.upcast()) } pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { @@ -145,12 +148,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.original_range(node) } - pub fn diagnostics_fix_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - self.imp.diagnostics_fix_range(diagnostics) - } - - pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - self.imp.diagnostics_range(diagnostics) + pub fn diagnostics_presentation_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + self.imp.diagnostics_presentation_range(diagnostics) } pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { @@ -380,15 +379,8 @@ impl<'db> SemanticsImpl<'db> { original_range(self.db, node.as_ref()) } - fn diagnostics_fix_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - let src = diagnostics.fix_source(); - let root = self.db.parse_or_expand(src.file_id).unwrap(); - let node = src.value.to_node(&root); - original_range(self.db, src.with_value(&node)) - } - - fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - let src = diagnostics.source(); + fn diagnostics_presentation_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + let src = diagnostics.presentation(); let root = self.db.parse_or_expand(src.file_id).unwrap(); let node = src.value.to_node(&root); original_range(self.db, src.with_value(&node)) -- cgit v1.2.3 From 936861993935d5b2c78b953e2f4b719e1992bd73 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 10 Aug 2020 22:53:10 +0300 Subject: Make the fix AST source Optional --- crates/ra_hir/src/diagnostics.rs | 2 +- crates/ra_hir/src/semantics.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 266b513dc..564f6a5db 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here pub use hir_def::diagnostics::UnresolvedModule; pub use hir_expand::diagnostics::{ - AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, + Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, DiagnosticWithFix, }; pub use hir_ty::diagnostics::{ MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index b4420d378..c5bc2baff 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -8,7 +8,7 @@ use hir_def::{ resolver::{self, HasResolver, Resolver}, AsMacroCall, FunctionId, TraitId, VariantId, }; -use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, name::AsName, ExpansionInfo}; +use hir_expand::{diagnostics::DiagnosticWithFix, hygiene::Hygiene, name::AsName, ExpansionInfo}; use hir_ty::associated_type_shorthand_candidates; use itertools::Itertools; use ra_db::{FileId, FileRange}; @@ -109,12 +109,12 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.parse(file_id) } - pub fn diagnostic_fix_source( + pub fn diagnostic_fix_source( &self, d: &T, - ) -> ::AST { + ) -> Option<::AST> { let file_id = d.presentation().file_id; - let root = self.db.parse_or_expand(file_id).unwrap(); + let root = self.db.parse_or_expand(file_id)?; self.imp.cache(root, file_id); d.fix_source(self.db.upcast()) } -- cgit v1.2.3 From 29fbc8e02180aac1f4d7819a9626206aa64028a0 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 11 Aug 2020 00:37:23 +0300 Subject: Move the DiagnosticsWithFix trait on the ide level --- crates/ra_hir/src/diagnostics.rs | 4 +--- crates/ra_hir/src/semantics.rs | 12 +++--------- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 564f6a5db..363164b9b 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs @@ -1,8 +1,6 @@ //! FIXME: write short doc here pub use hir_def::diagnostics::UnresolvedModule; -pub use hir_expand::diagnostics::{ - Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, DiagnosticWithFix, -}; +pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder}; pub use hir_ty::diagnostics::{ MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, }; diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index c5bc2baff..e9f7a033c 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -8,7 +8,7 @@ use hir_def::{ resolver::{self, HasResolver, Resolver}, AsMacroCall, FunctionId, TraitId, VariantId, }; -use hir_expand::{diagnostics::DiagnosticWithFix, hygiene::Hygiene, name::AsName, ExpansionInfo}; +use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; use hir_ty::associated_type_shorthand_candidates; use itertools::Itertools; use ra_db::{FileId, FileRange}; @@ -109,14 +109,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.parse(file_id) } - pub fn diagnostic_fix_source( - &self, - d: &T, - ) -> Option<::AST> { - let file_id = d.presentation().file_id; - let root = self.db.parse_or_expand(file_id)?; - self.imp.cache(root, file_id); - d.fix_source(self.db.upcast()) + pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { + self.imp.cache(root_node, file_id) } pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { -- cgit v1.2.3 From c8cad76d25f7fab856c9646b70122e0f9f7d7218 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 11 Aug 2020 00:55:57 +0300 Subject: Improve the ide diagnostics trait API --- crates/ra_hir/src/semantics.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index e9f7a033c..2dfe69039 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -109,10 +109,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.parse(file_id) } - pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { - self.imp.cache(root_node, file_id) - } - pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { self.imp.expand(macro_call) } @@ -377,6 +373,7 @@ impl<'db> SemanticsImpl<'db> { let src = diagnostics.presentation(); let root = self.db.parse_or_expand(src.file_id).unwrap(); let node = src.value.to_node(&root); + self.cache(root, src.file_id); original_range(self.db, src.with_value(&node)) } -- cgit v1.2.3 From db12ccee96bf37367b39ad99638d06da7123c088 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 11 Aug 2020 17:15:11 +0300 Subject: Better naming and docs --- crates/ra_hir/src/semantics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 2dfe69039..e3c417b41 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -138,8 +138,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.original_range(node) } - pub fn diagnostics_presentation_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - self.imp.diagnostics_presentation_range(diagnostics) + pub fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + self.imp.diagnostics_display_range(diagnostics) } pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { @@ -369,8 +369,8 @@ impl<'db> SemanticsImpl<'db> { original_range(self.db, node.as_ref()) } - fn diagnostics_presentation_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - let src = diagnostics.presentation(); + fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + let src = diagnostics.display_source(); let root = self.db.parse_or_expand(src.file_id).unwrap(); let node = src.value.to_node(&root); self.cache(root, src.file_id); -- cgit v1.2.3 From 96001921fc1a00fe4f13dbe140e2df01430d11ea Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Aug 2020 12:21:03 +0200 Subject: Minor --- crates/ra_hir/src/source_analyzer.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index d0cb62ef0..d3d62debf 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -265,8 +265,7 @@ impl SourceAnalyzer { } // This must be a normal source file rather than macro file. - let hir_path = - crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; + let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we // trying to resolve foo::bar. @@ -451,7 +450,7 @@ fn adjust( pub(crate) fn resolve_hir_path( db: &dyn HirDatabase, resolver: &Resolver, - path: &crate::Path, + path: &Path, ) -> Option { let types = resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { @@ -512,7 +511,7 @@ pub(crate) fn resolve_hir_path( pub(crate) fn resolve_hir_path_qualifier( db: &dyn HirDatabase, resolver: &Resolver, - path: &crate::Path, + path: &Path, ) -> Option { let items = resolver .resolve_module_path_in_items(db.upcast(), path.mod_path()) -- cgit v1.2.3