aboutsummaryrefslogtreecommitdiffstats
path: root/components/plugins/lints/unrooted_must_root.rs
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-07-21 21:09:18 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-07-22 00:00:14 +0530
commitf6f0a7e4aaaa3c1ec7aca3876b0b0fe9e5fca9aa (patch)
tree1affaf3d3bff8cc1ef9dc3c2090fc88bb3dfa698 /components/plugins/lints/unrooted_must_root.rs
parent126f5ae8f0a1041aa881b5b8d9396d0957b16036 (diff)
downloadservo-f6f0a7e4aaaa3c1ec7aca3876b0b0fe9e5fca9aa.tar.gz
servo-f6f0a7e4aaaa3c1ec7aca3876b0b0fe9e5fca9aa.zip
Make stmt part of unrooted_must_root handle type parameters (fixes #6651)
Diffstat (limited to 'components/plugins/lints/unrooted_must_root.rs')
-rw-r--r--components/plugins/lints/unrooted_must_root.rs56
1 files changed, 42 insertions, 14 deletions
diff --git a/components/plugins/lints/unrooted_must_root.rs b/components/plugins/lints/unrooted_must_root.rs
index 38473305c17..be6175c2cce 100644
--- a/components/plugins/lints/unrooted_must_root.rs
+++ b/components/plugins/lints/unrooted_must_root.rs
@@ -7,7 +7,7 @@ use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::{ty, def};
-use utils::unsafe_context;
+use utils::{match_def_path, unsafe_context};
declare_lint!(UNROOTED_MUST_ROOT, Deny,
"Warn and report usage of unrooted jsmanaged objects");
@@ -25,8 +25,17 @@ declare_lint!(UNROOTED_MUST_ROOT, Deny,
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
-pub struct UnrootedPass;
+pub struct UnrootedPass {
+ in_new_function: bool
+}
+impl UnrootedPass {
+ pub fn new() -> UnrootedPass {
+ UnrootedPass {
+ in_new_function: true
+ }
+ }
+}
// Checks if a type has the #[must_root] annotation.
// Unwraps pointers as well
// TODO (#3874, sort of): unwrap other types like Vec/Option/HashMap/etc
@@ -90,7 +99,10 @@ impl LintPass for UnrootedPass {
block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
match kind {
visit::FkItemFn(i, _, _, _, _, _) |
- visit::FkMethod(i, _, _) if i.as_str() == "new" || i.as_str() == "new_inherited" => {
+ visit::FkMethod(i, _, _) if i.as_str() == "new"
+ || i.as_str() == "new_inherited"
+ || i.as_str() == "new_initialized" => {
+ self.in_new_function = true;
return;
},
visit::FkItemFn(_, _, style, _, _, _) => match style {
@@ -99,6 +111,7 @@ impl LintPass for UnrootedPass {
},
_ => ()
}
+ self.in_new_function = false;
if unsafe_context(&cx.tcx.map, id) {
return;
@@ -120,7 +133,6 @@ impl LintPass for UnrootedPass {
// Expressions which return out of blocks eventually end up in a `let` or assignment
// statement or a function return (which will be caught when it is used elsewhere)
fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
-
match s.node {
ast::StmtDecl(_, id) |
ast::StmtExpr(_, id) |
@@ -155,16 +167,32 @@ impl LintPass for UnrootedPass {
_ => return
};
- let t = cx.tcx.expr_ty(&*expr);
- match t.sty {
- ty::TyStruct(did, _) |
- ty::TyEnum(did, _) => {
- if cx.tcx.has_attr(did, "must_root") {
- cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
- &format!("Expression of type {:?} must be rooted", t));
- }
+ let ty = cx.tcx.expr_ty(&*expr);
+ ty.maybe_walk(|t| {
+ match t.sty {
+ ty::TyStruct(did, _) |
+ ty::TyEnum(did, _) => {
+ if cx.tcx.has_attr(did, "must_root") {
+ cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
+ &format!("Expression of type {:?} in type {:?} must be rooted", t, ty));
+ false
+ } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
+ false
+ } else if match_def_path(cx, did, &["core", "cell", "Ref"])
+ || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
+ // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
+ // since it will be rooted elsewhere
+ false
+ } else {
+ true
+ }
+ },
+ ty::TyBox(..) if self.in_new_function => false, // box in new() is okay
+ ty::TyRef(..) => false, // don't recurse down &ptrs
+ ty::TyRawPtr(..) => false, // don't recurse down *ptrs
+ _ => true
}
- _ => {}
- }
+ })
+
}
}