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_def/src/adt.rs | 56 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_def/src/adt.rs') diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 6cb56a1cd..6d59c8642 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs @@ -9,11 +9,13 @@ use hir_expand::{ }; use ra_arena::{map::ArenaMap, Arena}; use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; +use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; use crate::{ + attr::AttrInput, body::{CfgExpander, LowerCtx}, db::DefDatabase, - item_tree::{Field, Fields, ItemTree}, + item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem}, src::HasChildSource, src::HasSource, trace::Trace, @@ -29,6 +31,7 @@ use ra_cfg::CfgOptions; pub struct StructData { pub name: Name, pub variant_data: Arc, + pub repr: Option, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -58,26 +61,71 @@ pub struct FieldData { pub visibility: RawVisibility, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ReprKind { + Packed, + Other, +} + +fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option { + item_tree.attrs(of).iter().find_map(|a| { + if a.path.segments[0].to_string() == "repr" { + if let Some(AttrInput::TokenTree(subtree)) = &a.input { + parse_repr_tt(subtree) + } else { + None + } + } else { + None + } + }) +} + +fn parse_repr_tt(tt: &Subtree) -> Option { + match tt.delimiter { + Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {} + _ => return None, + } + + let mut it = tt.token_trees.iter(); + match it.next() { + None => None, + Some(TokenTree::Leaf(Leaf::Ident(ident))) if ident.text == "packed" => { + Some(ReprKind::Packed) + } + _ => Some(ReprKind::Other), + } +} + impl StructData { pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc { let loc = id.lookup(db); let item_tree = db.item_tree(loc.id.file_id); + let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); let strukt = &item_tree[loc.id.value]; let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); - - Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) + Arc::new(StructData { + name: strukt.name.clone(), + variant_data: Arc::new(variant_data), + repr, + }) } pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc { let loc = id.lookup(db); let item_tree = db.item_tree(loc.id.file_id); + let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); let union = &item_tree[loc.id.value]; let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); - Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) + Arc::new(StructData { + name: union.name.clone(), + variant_data: Arc::new(variant_data), + repr, + }) } } -- cgit v1.2.3 From 38440d53d8329ac9f3f2013c6e32b3f69b069c72 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Sat, 27 Jun 2020 14:42:42 -0400 Subject: Cleanup repr check, fix packed repr check and test --- crates/ra_hir_def/src/adt.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_def/src/adt.rs') diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 6d59c8642..4ba694480 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs @@ -12,10 +12,11 @@ use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; use crate::{ - attr::AttrInput, + attr::{Attr, AttrInput}, body::{CfgExpander, LowerCtx}, db::DefDatabase, item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem}, + path::{ModPath, PathKind}, src::HasChildSource, src::HasSource, trace::Trace, @@ -69,8 +70,12 @@ pub enum ReprKind { fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option { item_tree.attrs(of).iter().find_map(|a| { - if a.path.segments[0].to_string() == "repr" { - if let Some(AttrInput::TokenTree(subtree)) = &a.input { + if let Attr { + path: ModPath { kind: PathKind::Plain, segments }, + input: Some(AttrInput::TokenTree(subtree)), + } = a + { + if segments.len() == 1 && segments[0].to_string() == "repr" { parse_repr_tt(subtree) } else { None -- 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_def/src/adt.rs | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'crates/ra_hir_def/src/adt.rs') diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 4ba694480..35c3a9140 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs @@ -12,11 +12,9 @@ use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; use crate::{ - attr::{Attr, AttrInput}, body::{CfgExpander, LowerCtx}, db::DefDatabase, item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem}, - path::{ModPath, PathKind}, src::HasChildSource, src::HasSource, trace::Trace, @@ -69,21 +67,7 @@ pub enum ReprKind { } fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option { - item_tree.attrs(of).iter().find_map(|a| { - if let Attr { - path: ModPath { kind: PathKind::Plain, segments }, - input: Some(AttrInput::TokenTree(subtree)), - } = a - { - if segments.len() == 1 && segments[0].to_string() == "repr" { - parse_repr_tt(subtree) - } else { - None - } - } else { - None - } - }) + item_tree.attrs(of).by_key("repr").tt_values().find_map(parse_repr_tt) } fn parse_repr_tt(tt: &Subtree) -> Option { @@ -93,11 +77,8 @@ fn parse_repr_tt(tt: &Subtree) -> Option { } let mut it = tt.token_trees.iter(); - match it.next() { - None => None, - Some(TokenTree::Leaf(Leaf::Ident(ident))) if ident.text == "packed" => { - Some(ReprKind::Packed) - } + match it.next()? { + TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed), _ => Some(ReprKind::Other), } } -- cgit v1.2.3