aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorPaul Daniel Faria <[email protected]>2020-06-04 04:38:25 +0100
committerPaul Daniel Faria <[email protected]>2020-08-10 13:44:54 +0100
commit263f9a7f231a474dd56d02adbcd7c57d079e88fd (patch)
tree125391657a69cb05ac14fadee37e6138dc0daae7 /crates
parentf3336509e52187a7a70a8043557a7317872e3a2f (diff)
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.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/code_model.rs18
-rw-r--r--crates/ra_hir_def/src/adt.rs56
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs24
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs11
4 files changed, 105 insertions, 4 deletions
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};
4use arrayvec::ArrayVec; 4use arrayvec::ArrayVec;
5use either::Either; 5use either::Either;
6use hir_def::{ 6use hir_def::{
7 adt::ReprKind,
7 adt::StructKind, 8 adt::StructKind,
8 adt::VariantData, 9 adt::VariantData,
9 builtin_type::BuiltinType, 10 builtin_type::BuiltinType,
@@ -431,6 +432,10 @@ impl Struct {
431 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) 432 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id)
432 } 433 }
433 434
435 pub fn is_packed(self, db: &dyn HirDatabase) -> bool {
436 matches!(db.struct_data(self.id).repr, Some(ReprKind::Packed))
437 }
438
434 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { 439 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
435 db.struct_data(self.id).variant_data.clone() 440 db.struct_data(self.id).variant_data.clone()
436 } 441 }
@@ -1253,6 +1258,19 @@ impl Type {
1253 ) 1258 )
1254 } 1259 }
1255 1260
1261 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1262 let adt_id = match self.ty.value {
1263 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_id), .. }) => adt_id,
1264 _ => return false,
1265 };
1266
1267 let adt = adt_id.into();
1268 match adt {
1269 Adt::Struct(s) => s.is_packed(db),
1270 _ => false,
1271 }
1272 }
1273
1256 pub fn is_raw_ptr(&self) -> bool { 1274 pub fn is_raw_ptr(&self) -> bool {
1257 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) 1275 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }))
1258 } 1276 }
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::{
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; 11use ra_syntax::ast::{self, NameOwner, VisibilityOwner};
12use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
12 13
13use crate::{ 14use crate::{
15 attr::AttrInput,
14 body::{CfgExpander, LowerCtx}, 16 body::{CfgExpander, LowerCtx},
15 db::DefDatabase, 17 db::DefDatabase,
16 item_tree::{Field, Fields, ItemTree}, 18 item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem},
17 src::HasChildSource, 19 src::HasChildSource,
18 src::HasSource, 20 src::HasSource,
19 trace::Trace, 21 trace::Trace,
@@ -29,6 +31,7 @@ use ra_cfg::CfgOptions;
29pub struct StructData { 31pub struct StructData {
30 pub name: Name, 32 pub name: Name,
31 pub variant_data: Arc<VariantData>, 33 pub variant_data: Arc<VariantData>,
34 pub repr: Option<ReprKind>,
32} 35}
33 36
34#[derive(Debug, Clone, PartialEq, Eq)] 37#[derive(Debug, Clone, PartialEq, Eq)]
@@ -58,26 +61,71 @@ pub struct FieldData {
58 pub visibility: RawVisibility, 61 pub visibility: RawVisibility,
59} 62}
60 63
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub enum ReprKind {
66 Packed,
67 Other,
68}
69
70fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option<ReprKind> {
71 item_tree.attrs(of).iter().find_map(|a| {
72 if a.path.segments[0].to_string() == "repr" {
73 if let Some(AttrInput::TokenTree(subtree)) = &a.input {
74 parse_repr_tt(subtree)
75 } else {
76 None
77 }
78 } else {
79 None
80 }
81 })
82}
83
84fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
85 match tt.delimiter {
86 Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
87 _ => return None,
88 }
89
90 let mut it = tt.token_trees.iter();
91 match it.next() {
92 None => None,
93 Some(TokenTree::Leaf(Leaf::Ident(ident))) if ident.text == "packed" => {
94 Some(ReprKind::Packed)
95 }
96 _ => Some(ReprKind::Other),
97 }
98}
99
61impl StructData { 100impl StructData {
62 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { 101 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
63 let loc = id.lookup(db); 102 let loc = id.lookup(db);
64 let item_tree = db.item_tree(loc.id.file_id); 103 let item_tree = db.item_tree(loc.id.file_id);
104 let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into());
65 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 105 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
66 106
67 let strukt = &item_tree[loc.id.value]; 107 let strukt = &item_tree[loc.id.value];
68 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); 108 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);
69 109 Arc::new(StructData {
70 Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) 110 name: strukt.name.clone(),
111 variant_data: Arc::new(variant_data),
112 repr,
113 })
71 } 114 }
72 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { 115 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
73 let loc = id.lookup(db); 116 let loc = id.lookup(db);
74 let item_tree = db.item_tree(loc.id.file_id); 117 let item_tree = db.item_tree(loc.id.file_id);
118 let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into());
75 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 119 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
76 120
77 let union = &item_tree[loc.id.value]; 121 let union = &item_tree[loc.id.value];
78 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); 122 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);
79 123
80 Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) 124 Arc::new(StructData {
125 name: union.name.clone(),
126 variant_data: Arc::new(variant_data),
127 repr,
128 })
81 } 129 }
82} 130}
83 131
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 6b7874460..0cab684eb 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -565,6 +565,30 @@ fn highlight_element(
565 _ => h, 565 _ => h,
566 } 566 }
567 } 567 }
568 REF_EXPR => {
569 let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?;
570 let expr = ref_expr.expr()?;
571 let field_expr = match expr {
572 ast::Expr::FieldExpr(fe) => fe,
573 _ => return None,
574 };
575
576 let expr = field_expr.expr()?;
577 let ty = match sema.type_of_expr(&expr) {
578 Some(ty) => ty,
579 None => {
580 println!("No type :(");
581 return None;
582 }
583 };
584 if !ty.is_packed(db) {
585 return None;
586 }
587
588 // FIXME account for alignment... somehow
589
590 Highlight::new(HighlightTag::Operator) | HighlightModifier::Unsafe
591 }
568 p if p.is_punct() => match p { 592 p if p.is_punct() => match p {
569 T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { 593 T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => {
570 HighlightTag::Operator.into() 594 HighlightTag::Operator.into()
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 09062c38e..f2c078d34 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -292,6 +292,13 @@ struct TypeForStaticMut {
292 292
293static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 }; 293static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 };
294 294
295#[repr(packed)]
296struct Packed {
297 a: u16,
298 b: u8,
299 c: u32,
300}
301
295fn main() { 302fn main() {
296 let x = &5 as *const usize; 303 let x = &5 as *const usize;
297 let u = Union { b: 0 }; 304 let u = Union { b: 0 };
@@ -306,6 +313,10 @@ fn main() {
306 let y = *(x); 313 let y = *(x);
307 let z = -x; 314 let z = -x;
308 let a = global_mut.a; 315 let a = global_mut.a;
316 let packed = Packed { a: 0, b: 0, c: 0 };
317 let a = &packed.a;
318 let b = &packed.b;
319 let c = &packed.c;
309 } 320 }
310} 321}
311"# 322"#