Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/semantics.rs')
| -rw-r--r-- | crates/hir/src/semantics.rs | 134 |
1 files changed, 106 insertions, 28 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 2e1f88ba09..e0d2610391 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -2,14 +2,17 @@ mod source_to_def; -use std::{cell::RefCell, fmt, iter, ops}; +use std::{cell::RefCell, fmt, iter, mem, ops}; use base_db::{FileId, FileRange}; +use either::Either; use hir_def::{ - body, macro_id_to_def_id, + body, + expr::Expr, + macro_id_to_def_id, resolver::{self, HasResolver, Resolver, TypeNs}, type_ref::Mutability, - AsMacroCall, FunctionId, MacroId, TraitId, VariantId, + AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, }; use hir_expand::{ db::AstDatabase, @@ -29,7 +32,7 @@ use crate::{ db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, SourceAnalyzer}, - Access, Adjust, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, + Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef, @@ -334,7 +337,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_trait(trait_) } - pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> { + pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> { self.imp.expr_adjustments(expr) } @@ -438,8 +441,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { } pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { - let src = self.imp.find_file(src.syntax()).with_value(src).cloned(); - T::to_def(&self.imp, src) + self.imp.to_def(src) } pub fn to_module_def(&self, file: FileId) -> Option<Module> { @@ -481,6 +483,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool { self.imp.is_unsafe_ident_pat(ident_pat) } + + /// Returns `true` if the `node` is inside an `unsafe` context. + pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool { + self.imp.is_inside_unsafe(expr) + } } impl<'db> SemanticsImpl<'db> { @@ -788,7 +795,7 @@ impl<'db> SemanticsImpl<'db> { // requeue the tokens we got from mapping our current token down stack.extend(mapped_tokens); // if the length changed we have found a mapping for the token - (stack.len() != len).then(|| ()) + (stack.len() != len).then_some(()) }; // Remap the next token in the queue into a macro call its in, if it is not being remapped @@ -840,7 +847,7 @@ impl<'db> SemanticsImpl<'db> { } }; process_expansion_for_token(&mut stack, file_id, None, token.as_ref()) - } else if let Some(meta) = ast::Meta::cast(parent.clone()) { + } else if let Some(meta) = ast::Meta::cast(parent) { // attribute we failed expansion for earlier, this might be a derive invocation // or derive helper attribute let attr = meta.parent_attr()?; @@ -1067,26 +1074,42 @@ impl<'db> SemanticsImpl<'db> { } } - fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> { + fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> { let mutability = |m| match m { hir_ty::Mutability::Not => Mutability::Shared, hir_ty::Mutability::Mut => Mutability::Mut, }; - self.analyze(expr.syntax())?.expr_adjustments(self.db, expr).map(|it| { + + let analyzer = self.analyze(expr.syntax())?; + + let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?; + + analyzer.expr_adjustments(self.db, expr).map(|it| { it.iter() - .map(|adjust| match adjust.kind { - hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, - hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { - Adjust::Deref(Some(OverloadedDeref(mutability(m)))) - } - hir_ty::Adjust::Deref(None) => Adjust::Deref(None), - hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => { - Adjust::Borrow(AutoBorrow::RawPtr(mutability(m))) - } - hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => { - Adjust::Borrow(AutoBorrow::Ref(mutability(m))) - } - hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc), + .map(|adjust| { + let target = + Type::new_with_resolver(self.db, &analyzer.resolver, adjust.target.clone()); + let kind = match adjust.kind { + hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, + hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { + Adjust::Deref(Some(OverloadedDeref(mutability(m)))) + } + hir_ty::Adjust::Deref(None) => Adjust::Deref(None), + hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => { + Adjust::Borrow(AutoBorrow::RawPtr(mutability(m))) + } + hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => { + Adjust::Borrow(AutoBorrow::Ref(mutability(m))) + } + hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc), + }; + + // Update `source_ty` for the next adjustment + let source = mem::replace(&mut source_ty, target.clone()); + + let adjustment = Adjustment { source, target, kind }; + + adjustment }) .collect() }) @@ -1198,7 +1221,7 @@ impl<'db> SemanticsImpl<'db> { krate .dependencies(self.db) .into_iter() - .find_map(|dep| (dep.name == name).then(|| dep.krate)) + .find_map(|dep| (dep.name == name).then_some(dep.krate)) } fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { @@ -1223,10 +1246,15 @@ impl<'db> SemanticsImpl<'db> { fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'_, '_>) -> T, T>(&self, f: F) -> T { let mut cache = self.s2d_cache.borrow_mut(); - let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; + let mut ctx = SourceToDefCtx { db: self.db, cache: &mut cache }; f(&mut ctx) } + fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { + let src = self.find_file(src.syntax()).with_value(src).cloned(); + T::to_def(self, src) + } + fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> { self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from) } @@ -1350,7 +1378,7 @@ impl<'db> SemanticsImpl<'db> { self.cache .borrow() .keys() - .map(|it| format!("{:?}", it)) + .map(|it| format!("{it:?}")) .collect::<Vec<_>>() .join(", ") ) @@ -1442,6 +1470,56 @@ impl<'db> SemanticsImpl<'db> { .map(|ty| ty.original.is_packed(self.db)) .unwrap_or(false) } + + fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool { + let item_or_variant = |ancestor: SyntaxNode| { + if ast::Item::can_cast(ancestor.kind()) { + ast::Item::cast(ancestor).map(Either::Left) + } else { + ast::Variant::cast(ancestor).map(Either::Right) + } + }; + let Some(enclosing_item) = expr.syntax().ancestors().find_map(item_or_variant) else { return false }; + + let def = match &enclosing_item { + Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true, + Either::Left(ast::Item::Fn(it)) => { + self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId) + } + Either::Left(ast::Item::Const(it)) => { + self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId) + } + Either::Left(ast::Item::Static(it)) => { + self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId) + } + Either::Left(_) => None, + Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId), + }; + let Some(def) = def else { return false }; + let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax()); + + let (body, source_map) = self.db.body_with_source_map(def); + + let file_id = self.find_file(expr.syntax()).file_id; + + let Some(mut parent) = expr.syntax().parent() else { return false }; + loop { + if &parent == enclosing_node { + break false; + } + + if let Some(parent) = ast::Expr::cast(parent.clone()) { + if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) { + if let Expr::Unsafe { .. } = body[expr_id] { + break true; + } + } + } + + let Some(parent_) = parent.parent() else { break false }; + parent = parent_; + } + } } fn macro_call_to_macro_id( @@ -1600,7 +1678,7 @@ impl<'a> SemanticsScope<'a> { self.db, def, resolution.in_type_ns()?, - |name, _, id| cb(name, id.into()), + |name, id| cb(name, id.into()), ) } } |