/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #![feature(macro_rules, plugin_registrar, quote, phase)] #![deny(unused_imports, unused_variable)] //! Exports macros for use in other Servo crates. extern crate syntax; #[phase(plugin, link)] extern crate rustc; #[cfg(test)] extern crate sync; use syntax::ast; use rustc::lint::{Context, LintPass, LintPassObject, LintArray}; use rustc::plugin::Registry; use rustc::middle::ty::expr_ty; use rustc::middle::typeck::astconv::AstConv; use rustc::util::ppaux::Repr; declare_lint!(TRANSMUTE_TYPE_LINT, Allow, "Warn and report types being transmuted") struct Pass; impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(TRANSMUTE_TYPE_LINT) } fn check_expr(&mut self, cx: &Context, ex: &ast::Expr) { match ex.node { ast::ExprCall(ref expr, ref args) => { match expr.node { ast::ExprPath(ref path) => { if path.segments.last() .map_or(false, |ref segment| segment.identifier.name.as_str() == "transmute") && args.len() == 1 { let tcx = cx.tcx(); cx.span_lint(TRANSMUTE_TYPE_LINT, ex.span, format!("Transmute from {} to {} detected", expr_ty(tcx, ex).repr(tcx), expr_ty(tcx, &**args.get(0)).repr(tcx) ).as_slice()); } } _ => {} } } _ => {} } } } #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box Pass as LintPassObject); } #[macro_export] macro_rules! bitfield( ($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => ( impl $bitfieldname { #[inline] pub fn $getter(self) -> bool { let $bitfieldname(this) = self; (this & $value) != 0 } #[inline] pub fn $setter(&mut self, value: bool) { let $bitfieldname(this) = *self; *self = $bitfieldname((this & !$value) | (if value { $value } else { 0 })) } } ) ) #[macro_export] macro_rules! lazy_init( ($(static ref $N:ident : $T:ty = $e:expr;)*) => ( $( #[allow(non_camel_case_types)] struct $N {__unit__: ()} static $N: $N = $N {__unit__: ()}; impl Deref<$T> for $N { fn deref<'a>(&'a self) -> &'a $T { unsafe { static mut s: *const $T = 0 as *const $T; static mut ONCE: ::sync::one::Once = ::sync::one::ONCE_INIT; ONCE.doit(|| { s = ::std::mem::transmute::, *const $T>(box () ($e)); }); &*s } } } )* ) ) #[cfg(test)] mod tests { use std::collections::hashmap::HashMap; lazy_init! { static ref NUMBER: uint = times_two(3); static ref VEC: [Box, ..3] = [box 1, box 2, box 3]; static ref OWNED_STRING: String = "hello".to_string(); static ref HASHMAP: HashMap = { let mut m = HashMap::new(); m.insert(0u, "abc"); m.insert(1, "def"); m.insert(2, "ghi"); m }; } fn times_two(n: uint) -> uint { n * 2 } #[test] fn test_basic() { assert_eq!(*OWNED_STRING, "hello".to_string()); assert_eq!(*NUMBER, 6); assert!(HASHMAP.find(&1).is_some()); assert!(HASHMAP.find(&3).is_none()); assert_eq!(VEC.as_slice(), &[box 1, box 2, box 3]); } #[test] fn test_repeat() { assert_eq!(*NUMBER, 6); assert_eq!(*NUMBER, 6); assert_eq!(*NUMBER, 6); } }