diff --git a/ioreg/Cargo.toml b/ioreg/Cargo.toml index c6ac7c9d..fa12c93e 100644 --- a/ioreg/Cargo.toml +++ b/ioreg/Cargo.toml @@ -9,3 +9,6 @@ plugin = true [dev-dependencies.volatile_cell] path = "../volatile_cell" + +[dependencies] +syntaxext_lint = "*" diff --git a/ioreg/src/builder/accessors.rs b/ioreg/src/builder/accessors.rs index 7e61b611..3976d198 100644 --- a/ioreg/src/builder/accessors.rs +++ b/ioreg/src/builder/accessors.rs @@ -15,7 +15,6 @@ use syntax::ast; use syntax::ptr::P; -use syntax::codemap::DUMMY_SP; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::quote::rt::ToTokens; @@ -33,7 +32,7 @@ pub struct BuildAccessors<'a> { impl<'a> node::RegVisitor for BuildAccessors<'a> { fn visit_prim_reg(&mut self, path: &Vec, reg: &node::Reg, - _width: &node::RegWidth, fields: &Vec) { + fields: &Vec) { if fields.iter().any(|f| f.access != node::Access::WriteOnly) { let item = build_get_fn(self.cx, path, reg); self.builder.push_item(item); @@ -60,7 +59,7 @@ fn build_field_accessors(cx: &ExtCtxt, path: &Vec, -> Option> { let reg_ty: P = - cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let items = match field.access { node::Access::ReadWrite => vec!(build_field_set_fn(cx, path, reg, field), @@ -103,7 +102,7 @@ fn build_get_fn(cx: &ExtCtxt, path: &Vec, reg: &node::Reg) -> P { let reg_ty: P = - cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let getter_ty = utils::getter_name(cx, path); let docstring = format!("Fetch the value of the `{}` register", @@ -126,7 +125,7 @@ fn build_field_set_fn(cx: &ExtCtxt, path: &Vec, reg: &node::Reg, field: &node::Field) -> P { - let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + let reg_ty = cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let fn_name = cx.ident_of((String::from_str("set_")+field.name.node.as_str()).as_str()); let field_ty: P = @@ -161,7 +160,7 @@ fn build_field_get_fn(cx: &ExtCtxt, path: &Vec, reg: &node::Reg, field: &node::Field) -> P { - let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + let reg_ty = cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); utils::unwrap_impl_item({ let fn_name = cx.ident_of(field.name.node.as_str()); let field_ty: P = @@ -190,10 +189,10 @@ fn build_field_get_fn(cx: &ExtCtxt, path: &Vec, } fn build_field_clear_fn(cx: &ExtCtxt, path: &Vec, - _reg: &node::Reg, field: &node::Field) + reg: &node::Reg, field: &node::Field) -> P { - let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + let reg_ty = cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let fn_name = cx.ident_of((String::from_str("clear_")+field.name.node.as_str()).as_str()); let setter_ty = utils::setter_name(cx, path); diff --git a/ioreg/src/builder/getter.rs b/ioreg/src/builder/getter.rs index c6a26252..58ebf075 100644 --- a/ioreg/src/builder/getter.rs +++ b/ioreg/src/builder/getter.rs @@ -19,7 +19,7 @@ use std::ops::Deref; use syntax::ast; use syntax::ptr::P; use syntax::ext::base::ExtCtxt; -use syntax::codemap::DUMMY_SP; +use syntax::codemap::{respan, Span}; use syntax::ext::build::AstBuilder; use syntax::ext::quote::rt::ToTokens; use syntax::parse::token; @@ -43,7 +43,7 @@ impl<'a> BuildGetters<'a> { impl<'a> node::RegVisitor for BuildGetters<'a> { fn visit_prim_reg(&mut self, path: &Vec, - reg: &node::Reg, _width: &node::RegWidth, + reg: &node::Reg, fields: &Vec) { if fields.iter().any(|f| f.access != node::Access::WriteOnly) { let it = build_type(self.cx, path, reg); @@ -61,6 +61,13 @@ impl<'a> node::RegVisitor for BuildGetters<'a> { } } +fn reg_ty_span(reg: &node::Reg) -> Span { + match reg.ty { + node::RegType::RegPrim(ref width, _) => width.span, + _ => reg.name.span, + } +} + fn build_type(cx: &ExtCtxt, path: &Vec, reg: &node::Reg) -> P { @@ -87,11 +94,12 @@ fn build_type(cx: &ExtCtxt, path: &Vec, P(item) } -fn build_new(cx: &ExtCtxt, path: &Vec) -> P { +fn build_new(cx: &ExtCtxt, path: &Vec, + reg: &node::Reg) -> P { let reg_ty: P = - cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let getter_ident = utils::getter_name(cx, path); - let getter_ty: P = cx.ty_ident(DUMMY_SP, + let getter_ty: P = cx.ty_ident(reg_ty_span(reg), getter_ident); let item = quote_item!(cx, impl $getter_ty { @@ -111,11 +119,13 @@ fn build_new(cx: &ExtCtxt, path: &Vec) -> P { fn from_primitive(cx: &ExtCtxt, path: &Vec, _: &node::Reg, field: &node::Field, prim: P) -> P { + // Use bit_range_field for the span because it is to blame for the + // type of the register match field.ty.node { node::FieldType::UIntField => prim, node::FieldType::BoolField => - cx.expr_binary(DUMMY_SP, ast::BiNe, - prim, utils::expr_int(cx, 0)), + cx.expr_binary(field.bit_range_span, ast::BiNe, + prim, utils::expr_int(cx, respan(field.bit_range_span, 0))), node::FieldType::EnumField {opt_name: _, variants: ref vars} => { let mut arms: Vec = Vec::new(); for v in vars.iter() { @@ -124,38 +134,38 @@ fn from_primitive(cx: &ExtCtxt, path: &Vec, _: &node::Reg, let enum_ident = cx.ident_of(name.connect("_").as_str()); let val_ident = cx.ident_of(v.name.node.as_str()); let body = cx.expr_path( - cx.path(DUMMY_SP, vec!(enum_ident, val_ident))); + cx.path(v.name.span, vec!(enum_ident, val_ident))); let val: u64 = v.value.node; let lit = cx.expr_lit( - DUMMY_SP, + v.value.span, ast::LitInt(val, ast::UnsuffixedIntLit(ast::Plus))); let arm = ast::Arm { attrs: vec!(), pats: vec!( P(ast::Pat { id: ast::DUMMY_NODE_ID, - span: DUMMY_SP, + span: lit.span, node: ast::PatLit(lit), }) ), guard: None, - body: cx.expr_some(DUMMY_SP, body), + body: cx.expr_some(body.span, body), }; arms.push(arm); } let wild_arm = ast::Arm { attrs: vec!(), - pats: vec!(cx.pat_wild(DUMMY_SP)), + pats: vec!(cx.pat_wild(field.name.span)), guard: None, - body: cx.expr_none(DUMMY_SP), + body: cx.expr_none(field.name.span), }; arms.push(wild_arm); let opt_expr = cx.expr_match( - DUMMY_SP, + field.name.span, prim, arms); cx.expr_method_call( - DUMMY_SP, + field.name.span, opt_expr, cx.ident_of("unwrap"), Vec::new()) @@ -166,7 +176,7 @@ fn from_primitive(cx: &ExtCtxt, path: &Vec, _: &node::Reg, fn build_impl(cx: &ExtCtxt, path: &Vec, reg: &node::Reg, fields: &Vec) -> P { let getter_ty = utils::getter_name(cx, path); - let new = build_new(cx, path); + let new = build_new(cx, path, reg); let getters: Vec> = FromIterator::from_iter( fields.iter() diff --git a/ioreg/src/builder/register.rs b/ioreg/src/builder/register.rs index 3e59c6a8..d334ac49 100644 --- a/ioreg/src/builder/register.rs +++ b/ioreg/src/builder/register.rs @@ -37,14 +37,18 @@ pub struct BuildRegStructs<'a> { impl<'a> node::RegVisitor for BuildRegStructs<'a> { fn visit_prim_reg(&mut self, path: &Vec, reg: &node::Reg, - width: &node::RegWidth, fields: &Vec) { + fields: &Vec) { + let width = match reg.ty { + node::RegType::RegPrim(ref width, _) => width.node, + _ => panic!("visit_prim_reg called with non-primitive register"), + }; for field in fields.iter() { for item in build_field_type(self.cx, path, reg, field).into_iter() { self.builder.push_item(item); } } - for item in build_reg_struct(self.cx, path, reg, width).into_iter() { + for item in build_reg_struct(self.cx, path, reg, &width).into_iter() { self.builder.push_item(item); } } @@ -76,7 +80,8 @@ fn build_field_type(cx: &ExtCtxt, path: &Vec, utils::list_attribute(cx, "allow", vec!("dead_code", "non_camel_case_types", - "missing_docs"))); + "missing_docs"), + field.name.span)); let ty_item: P = P(ast::Item { ident: name, id: ast::DUMMY_NODE_ID, @@ -144,7 +149,8 @@ fn build_enum_variant(cx: &ExtCtxt, variant: &node::Variant) attrs: vec!(doc_attr), kind: ast::TupleVariantKind(Vec::new()), id: ast::DUMMY_NODE_ID, - disr_expr: Some(utils::expr_int(cx, variant.value.node as i64)), + disr_expr: Some(utils::expr_int(cx, respan(variant.value.span, + variant.value.node as i64))), vis: ast::Inherited, } ) diff --git a/ioreg/src/builder/setter.rs b/ioreg/src/builder/setter.rs index bdb70008..d8623938 100644 --- a/ioreg/src/builder/setter.rs +++ b/ioreg/src/builder/setter.rs @@ -19,7 +19,6 @@ use std::ops::Deref; use syntax::ast; use syntax::ptr::P; use syntax::ext::base::ExtCtxt; -use syntax::codemap::DUMMY_SP; use syntax::ext::build::AstBuilder; use syntax::ext::quote::rt::ToTokens; use syntax::parse::token; @@ -43,7 +42,7 @@ impl<'a> BuildSetters<'a> { impl<'a> node::RegVisitor for BuildSetters<'a> { fn visit_prim_reg<'b>(&'b mut self, path: &Vec, - reg: &'b node::Reg, _width: &node::RegWidth, fields: &Vec) + reg: &'b node::Reg, fields: &Vec) { if fields.iter().any(|f| f.access != node::Access::ReadOnly) { let it = build_type(self.cx, path, reg, fields); @@ -64,7 +63,7 @@ fn build_type(cx: &ExtCtxt, path: &Vec, let packed_ty = utils::reg_primitive_type(cx, reg) .expect("Unexpected non-primitive register"); let name = utils::setter_name(cx, path); - let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + let reg_ty = cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let reg_doc = match reg.docstring { Some(d) => token::get_ident(d.node).to_string(), @@ -89,10 +88,10 @@ fn build_type(cx: &ExtCtxt, path: &Vec, P(item) } -fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec) +fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec, reg: &node::Reg) -> P { let reg_ty: P = - cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path)); + cx.ty_ident(reg.name.span, utils::path_ident(cx, path)); let setter_ident = utils::setter_name(cx, path); utils::unwrap_impl_item(quote_item!(cx, impl<'a> $setter_ident<'a> { @@ -164,7 +163,7 @@ fn build_done(ctx: &ExtCtxt, path: &Vec) -> P { fn build_impl(cx: &ExtCtxt, path: &Vec, reg: &node::Reg, fields: &Vec) -> P { - let new = build_new(cx, path); + let new = build_new(cx, path, reg); let setter_ident = utils::setter_name(cx, path); let methods: Vec> = FromIterator::from_iter( diff --git a/ioreg/src/builder/union.rs b/ioreg/src/builder/union.rs index 5a2f6851..2efd49e5 100644 --- a/ioreg/src/builder/union.rs +++ b/ioreg/src/builder/union.rs @@ -18,7 +18,7 @@ use std::iter::FromIterator; use syntax::ast; use syntax::ptr::P; use syntax::ast_util::empty_generics; -use syntax::codemap::{DUMMY_SP, dummy_spanned}; +use syntax::codemap::{DUMMY_SP, dummy_spanned, respan, Spanned}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::parse::token; @@ -86,21 +86,21 @@ impl<'a> BuildUnionTypes<'a> { } } -fn expr_u64(cx: &ExtCtxt, n: u64) -> P { - cx.expr_lit(DUMMY_SP, ast::LitInt(n as u64, ast::UnsignedIntLit(ast::TyUs))) +fn expr_u64(cx: &ExtCtxt, n: Spanned) -> P { + cx.expr_lit(n.span, ast::LitInt(n.node as u64, ast::UnsignedIntLit(ast::TyUs))) } /// Returns the type of the field representing the given register /// within a `RegGroup` struct fn reg_struct_type(cx: &ExtCtxt, path: &Vec, reg: &node::Reg) -> P { - let base_ty_path = cx.path_ident(DUMMY_SP, utils::path_ident(cx, path)); + let base_ty_path = cx.path_ident(reg.name.span, utils::path_ident(cx, path)); let base_ty: P = cx.ty_path(base_ty_path); match reg.count.node { 1 => base_ty, n => - cx.ty(DUMMY_SP, - ast::TyFixedLengthVec(base_ty, expr_u64(cx, n as u64))), + cx.ty(reg.count.span, + ast::TyFixedLengthVec(base_ty, expr_u64(cx, respan(reg.count.span, n as u64)))), } } @@ -138,6 +138,8 @@ impl<'a> BuildUnionTypes<'a> { } /// Build field for padding or a register + // Dummy spans allowed here because u8 doesn't come from anywhere + #[allow(dummy_span)] fn build_pad_or_reg(&self, path: &Vec, reg_or_pad: RegOrPadding, index: usize) -> ast::StructField { match reg_or_pad { @@ -150,7 +152,7 @@ impl<'a> BuildUnionTypes<'a> { let ty: P = self.cx.ty( DUMMY_SP, - ast::TyFixedLengthVec(u8_ty, expr_u64(self.cx, length))); + ast::TyFixedLengthVec(u8_ty, expr_u64(self.cx, respan(DUMMY_SP, length)))); dummy_spanned( ast::StructField_ { kind: ast::NamedField( @@ -183,7 +185,8 @@ impl<'a> BuildUnionTypes<'a> { utils::list_attribute(self.cx, "allow", vec!("non_camel_case_types", "dead_code", - "missing_docs")), + "missing_docs"), + reg.name.span), ); match reg.docstring { Some(docstring) => diff --git a/ioreg/src/builder/utils.rs b/ioreg/src/builder/utils.rs index a7ef798e..6fcf7c45 100644 --- a/ioreg/src/builder/utils.rs +++ b/ioreg/src/builder/utils.rs @@ -18,16 +18,16 @@ use std::iter::FromIterator; use syntax::ext::base::ExtCtxt; use syntax::ast; use syntax::ptr::P; -use syntax::codemap::DUMMY_SP; +use syntax::codemap::{respan, Span, Spanned}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use super::super::node; /// Generate an unsuffixed integer literal expression with a dummy span -pub fn expr_int(cx: &ExtCtxt, n: i64) -> P { - let sign = if n < 0 {ast::Minus} else {ast::Plus}; - cx.expr_lit(DUMMY_SP, ast::LitInt(n as u64, ast::UnsuffixedIntLit(sign))) +pub fn expr_int(cx: &ExtCtxt, n: Spanned) -> P { + let sign = if n.node < 0 {ast::Minus} else {ast::Plus}; + cx.expr_lit(n.span, ast::LitInt(n.node as u64, ast::UnsuffixedIntLit(sign))) } /// The name of the structure representing a register @@ -39,32 +39,45 @@ pub fn path_ident(cx: &ExtCtxt, path: &Vec) /// Generate a `#[name(...)]` attribute of the given type pub fn list_attribute(cx: &ExtCtxt, name: &'static str, - list: Vec<&'static str>) -> ast::Attribute { + list: Vec<&'static str>, + span: Span) -> ast::Attribute { + let spanned_name = respan(span, name); + let spanned_list: Vec> = list.into_iter() + .map(|word| respan(span, word)) + .collect(); + list_attribute_spanned(cx, spanned_name, spanned_list) +} + +fn list_attribute_spanned(cx: &ExtCtxt, name: Spanned<&'static str>, + list: Vec>) -> ast::Attribute { let words = list.into_iter() - .map(|word| cx.meta_word(DUMMY_SP, token::InternedString::new(word))); - let allow = cx.meta_list(DUMMY_SP, token::InternedString::new(name), + .map(|word| cx.meta_word(word.span, token::InternedString::new(word.node))); + let allow = cx.meta_list(name.span, token::InternedString::new(name.node), FromIterator::from_iter(words)); - cx.attribute(DUMMY_SP, allow) + cx.attribute(name.span, allow) } /// Generate a `#[doc="..."]` attribute of the given type +#[allow(dummy_span)] pub fn doc_attribute(cx: &ExtCtxt, docstring: token::InternedString) -> ast::Attribute { + use syntax::codemap::DUMMY_SP; + let s: ast::Lit_ = ast::LitStr(docstring, ast::CookedStr); let attr = cx.meta_name_value(DUMMY_SP, token::InternedString::new("doc"), s); cx.attribute(DUMMY_SP, attr) } -pub fn primitive_type_path(cx: &ExtCtxt, width: &node::RegWidth) +pub fn primitive_type_path(cx: &ExtCtxt, width: &Spanned) -> ast::Path { - let name = match width { - &node::RegWidth::Reg8 => "u8", - &node::RegWidth::Reg16 => "u16", - &node::RegWidth::Reg32 => "u32", + let name = match width.node { + node::RegWidth::Reg8 => "u8", + node::RegWidth::Reg16 => "u16", + node::RegWidth::Reg32 => "u32", }; - cx.path_ident(DUMMY_SP, cx.ident_of(name)) + cx.path_ident(width.span, cx.ident_of(name)) } /// The `Path` to the type corresponding to the primitive type of @@ -89,7 +102,8 @@ pub fn field_type_path(cx: &ExtCtxt, path: &Vec, match field.ty.node { node::FieldType::UIntField => { match reg.ty { - node::RegType::RegPrim(ref width, _) => primitive_type_path(cx, width), + node::RegType::RegPrim(ref width, _) => primitive_type_path(cx, + width), _ => panic!("The impossible happened: a union register with fields"), } }, @@ -119,17 +133,19 @@ pub fn unwrap_impl_item(item: P) -> P { /// Build an expression for the mask of a field pub fn mask(cx: &ExtCtxt, field: &node::Field) -> P { - expr_int(cx, ((1 << field.width as u64) - 1)) + expr_int(cx, respan(field.bit_range_span, + ((1 << field.width as u64) - 1))) } /// Build an expression for the shift of a field (including the array /// index if necessary) pub fn shift(cx: &ExtCtxt, idx: Option>, field: &node::Field) -> P { - let low = expr_int(cx, field.low_bit as i64); + let low = expr_int(cx, respan(field.bit_range_span, field.low_bit as i64)); match idx { Some(idx) => { - let width = expr_int(cx, field.width as i64); + let width = expr_int(cx, respan(field.bit_range_span, + field.width as i64)); quote_expr!(cx, $low + $idx * $width) }, None => low, diff --git a/ioreg/src/lib.rs b/ioreg/src/lib.rs index 7f63425a..527ab647 100644 --- a/ioreg/src/lib.rs +++ b/ioreg/src/lib.rs @@ -329,6 +329,9 @@ N => NAME #![feature(quote, plugin_registrar, rustc_private, collections, core)] #![feature(convert)] +#![feature(plugin)] + +#![plugin(syntaxext_lint)] extern crate rustc; extern crate syntax; diff --git a/ioreg/src/node.rs b/ioreg/src/node.rs index 4da8e0b9..356c1548 100644 --- a/ioreg/src/node.rs +++ b/ioreg/src/node.rs @@ -95,7 +95,7 @@ impl RegWidth { #[derive(Clone)] pub enum RegType { /// A primitive bitfield - RegPrim(RegWidth, Vec), + RegPrim(Spanned, Vec), /// A group RegUnion(Rc>), } @@ -104,7 +104,7 @@ impl RegType { /// Size of register type in bytes pub fn size(&self) -> u64 { match self { - &RegType::RegPrim(ref width, _) => width.size() as u64, + &RegType::RegPrim(ref width, _) => width.node.size() as u64, &RegType::RegUnion(ref regs) => regs_size(regs.deref()), } } @@ -142,7 +142,7 @@ pub fn regs_size(regs: &Vec) -> u64 { pub trait RegVisitor { /// Path includes name of `Reg` being visited fn visit_prim_reg<'a>(&'a mut self, _path: &Vec, _reg: &'a Reg, - _width: &RegWidth, _fields: &Vec) {} + _fields: &Vec) {} fn visit_union_reg<'a>(&'a mut self, _path: &Vec, _reg: &'a Reg, _subregs: Rc>) {} } @@ -161,7 +161,7 @@ fn visit_reg_(reg: &Reg, visitor: &mut T, path: Vec) { visit_reg_(r, visitor, new_path); } }, - RegType::RegPrim(ref width, ref fields) => - visitor.visit_prim_reg(&path, reg, width, fields) + RegType::RegPrim(_, ref fields) => + visitor.visit_prim_reg(&path, reg, fields) } } diff --git a/ioreg/src/parser.rs b/ioreg/src/parser.rs index edd39b31..4a0fc42e 100644 --- a/ioreg/src/parser.rs +++ b/ioreg/src/parser.rs @@ -174,9 +174,15 @@ impl<'a> Parser<'a> { } let ty = match self.expect_ident() { - Some(ref i) if i.eq(&"reg32") => RegType::RegPrim(node::RegWidth::Reg32, Vec::new()), - Some(ref i) if i.eq(&"reg16") => RegType::RegPrim(node::RegWidth::Reg16, Vec::new()), - Some(ref i) if i.eq(&"reg8") => RegType::RegPrim(node::RegWidth::Reg8, Vec::new()), + Some(ref i) if i.eq(&"reg32") => RegType::RegPrim(respan(self.last_span, + node::RegWidth::Reg32), + Vec::new()), + Some(ref i) if i.eq(&"reg16") => RegType::RegPrim(respan(self.last_span, + node::RegWidth::Reg16), + Vec::new()), + Some(ref i) if i.eq(&"reg8") => RegType::RegPrim(respan(self.last_span, + node::RegWidth::Reg8), + Vec::new()), Some(ref i) if i.eq(&"group") => { // registers will get filled in later RegType::RegUnion(Rc::new(Vec::new())) @@ -208,7 +214,7 @@ impl<'a> Parser<'a> { let ty = match ty { RegType::RegPrim(width, _) => { - match self.parse_fields(width) { + match self.parse_fields(width.node) { None => return None, Some(mut fields) => { // Check for overlapping fields @@ -226,11 +232,11 @@ impl<'a> Parser<'a> { // Verify fields fit in register match fields.last().map(|f| f.high_bit()) { - Some(last_bit) if last_bit >= 8*width.size() as u8 => { + Some(last_bit) if last_bit >= 8*width.node.size() as u8 => { self.sess.span_diagnostic.span_err( name.span, format!("Width of fields ({} bits) exceeds access size of register ({} bits)", - last_bit+1, 8*width.size()).as_str()); + last_bit+1, 8*width.node.size()).as_str()); return None; }, _ => {}