diff options
Diffstat (limited to 'components/macros/lib.rs')
-rw-r--r-- | components/macros/lib.rs | 74 |
1 files changed, 71 insertions, 3 deletions
diff --git a/components/macros/lib.rs b/components/macros/lib.rs index 554d9833c98..9191af72ce8 100644 --- a/components/macros/lib.rs +++ b/components/macros/lib.rs @@ -16,18 +16,23 @@ extern crate rustc; extern crate sync; use syntax::ast; +use syntax::attr::AttrMetaMethods; use rustc::lint::{Context, LintPass, LintPassObject, LintArray}; use rustc::plugin::Registry; use rustc::middle::ty::expr_ty; +use rustc::middle::{ty, def}; use rustc::middle::typeck::astconv::AstConv; use rustc::util::ppaux::Repr; declare_lint!(TRANSMUTE_TYPE_LINT, Allow, "Warn and report types being transmuted") +declare_lint!(UNROOTED_MUST_ROOT, Deny, + "Warn and report usage of unrooted jsmanaged objects") -struct Pass; +struct TransmutePass; +struct UnrootedPass; -impl LintPass for Pass { +impl LintPass for TransmutePass { fn get_lints(&self) -> LintArray { lint_array!(TRANSMUTE_TYPE_LINT) } @@ -56,9 +61,72 @@ impl LintPass for Pass { } } +fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) { + match ty.node { + ast::TyPath(_, _, id) => { + match cx.tcx.def_map.borrow().get_copy(&id) { + def::DefTy(def_id) => { + if ty::has_attr(cx.tcx, def_id, "must_root") { + cx.span_lint(UNROOTED_MUST_ROOT, ty.span, warning); + } + } + _ => (), + } + } + _ => (), + } +} + +impl LintPass for UnrootedPass { + fn get_lints(&self) -> LintArray { + lint_array!(UNROOTED_MUST_ROOT) + } + + fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) { + if cx.tcx.map.expect_item(id).attrs.iter().all(|a| !a.check_name("must_root")) { + for ref field in def.fields.iter() { + lint_unrooted_ty(cx, &*field.node.ty, "Type must be rooted, use #[must_root] on the struct definition to propagate"); + } + } + } + + fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) { + let ref map = cx.tcx.map; + if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) { + match var.node.kind { + ast::TupleVariantKind(ref vec) => { + for ty in vec.iter() { + lint_unrooted_ty(cx, &*ty.ty, "Type must be rooted, use #[must_root] on the enum definition to propagate") + } + } + _ => () // Struct variants already caught by check_struct_def + } + } + } + + fn check_fn(&mut self, cx: &Context, kind: &syntax::visit::FnKind, decl: &ast::FnDecl, block: &ast::Block, _span: syntax::codemap::Span, _id: ast::NodeId) { + match *kind { + syntax::visit::FkItemFn(i, _, _, _) | + syntax::visit::FkMethod(i, _, _) if i.as_str() == "new" || i.as_str() == "new_inherited" => { + + } + _ => () + } + match block.rules { + ast::DefaultBlock => { + for arg in decl.inputs.iter() { + lint_unrooted_ty(cx, &*arg.ty, "Type must be rooted, use #[must_root] on the struct definition to propagate") + } + } + _ => () // fn is `unsafe` + } + } +} + #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); + reg.register_lint_pass(box TransmutePass as LintPassObject); + reg.register_lint_pass(box UnrootedPass as LintPassObject); } #[macro_export] |