about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-05-18 03:07:28 -0400
committerAlex Crichton <alex@alexcrichton.com>2013-05-20 16:08:50 -0500
commit074799b4c586c521ba678a4dc3809cad1a872dfe (patch)
tree484319afafafb263fbf39f6b327d68abd087e0f0 /src
parent26babaafcdbcfdf2e842d84dbeabbed0dae6efef (diff)
downloadrust-074799b4c586c521ba678a4dc3809cad1a872dfe.tar.gz
rust-074799b4c586c521ba678a4dc3809cad1a872dfe.zip
Implement a lint mode to detect unnecessary allocations
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/lint.rs70
-rw-r--r--src/libsyntax/ext/env.rs6
2 files changed, 73 insertions, 3 deletions
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 079fb21a4fe..6a1a8940a05 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -79,6 +79,7 @@ pub enum lint {
     unused_variable,
     dead_assignment,
     unused_mut,
+    unnecessary_allocation,
 }
 
 pub fn level_to_str(lv: level) -> &'static str {
@@ -242,6 +243,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
         desc: "detect mut variables which don't need to be mutable",
         default: warn
     }),
+
+    ("unnecessary_allocation",
+     LintSpec {
+        lint: unnecessary_allocation,
+        desc: "detects unnecessary allocations that can be eliminated",
+        default: warn
+    }),
 ];
 
 /*
@@ -881,6 +889,67 @@ fn lint_session(cx: @mut Context) -> visit::vt<()> {
     })
 }
 
+fn lint_unnecessary_allocations(cx: @mut Context) -> visit::vt<()> {
+    // If the expression `e` has an allocated type, but `t` dictates that it's
+    // something like a slice (doesn't need allocation), emit a warning with the
+    // specified span.
+    //
+    // Currently, this only applies to string and vector literals with sigils in
+    // front. Those can have the sigil removed to get a borrowed pointer
+    // automatically.
+    fn check(cx: @mut Context, e: @ast::expr, t: ty::t) {
+        match e.node {
+            ast::expr_vstore(e2, ast::expr_vstore_uniq) |
+            ast::expr_vstore(e2, ast::expr_vstore_box) => {
+                match e2.node {
+                    ast::expr_lit(@codemap::spanned{
+                            node: ast::lit_str(*), _}) |
+                    ast::expr_vec(*) => {}
+                    _ => return
+                }
+            }
+
+            _ => return
+        }
+
+        match ty::get(t).sty {
+            ty::ty_estr(ty::vstore_slice(*)) |
+            ty::ty_evec(_, ty::vstore_slice(*)) => {
+                cx.span_lint(unnecessary_allocation,
+                             e.span, "unnecessary allocation, the sigil can be \
+                                      removed");
+            }
+
+            _ => ()
+        }
+    }
+
+    let visit_expr: @fn(@ast::expr) = |e| {
+        match e.node {
+            ast::expr_call(c, ref args, _) => {
+                let t = ty::node_id_to_type(cx.tcx, c.id);
+                let s = ty::ty_fn_sig(t);
+                for vec::each2(*args, s.inputs) |e, t| {
+                    check(cx, *e, *t);
+                }
+            }
+            ast::expr_method_call(_, _, _, ref args, _) => {
+                let t = ty::node_id_to_type(cx.tcx, e.callee_id);
+                let s = ty::ty_fn_sig(t);
+                for vec::each2(*args, s.inputs) |e, t| {
+                    check(cx, *e, *t);
+                }
+            }
+            _ => {}
+        }
+    };
+
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_expr: visit_expr,
+        .. *visit::default_simple_visitor()
+    })
+}
+
 pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
     let cx = @mut Context {
         dict: @get_lint_dict(),
@@ -908,6 +977,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
     cx.add_lint(lint_unused_unsafe(cx));
     cx.add_lint(lint_unused_mut(cx));
     cx.add_lint(lint_session(cx));
+    cx.add_lint(lint_unnecessary_allocations(cx));
 
     // type inference doesn't like this being declared below, we need to tell it
     // what the type of this first function is...
diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs
index 5b1e3737b23..4be75d9ee5b 100644
--- a/src/libsyntax/ext/env.rs
+++ b/src/libsyntax/ext/env.rs
@@ -18,7 +18,7 @@ use ast;
 use codemap::span;
 use ext::base::*;
 use ext::base;
-use ext::build::mk_uniq_str;
+use ext::build::mk_base_str;
 
 pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
     -> base::MacResult {
@@ -29,8 +29,8 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
     // Option<str> rather than just an maybe-empty string.
 
     let e = match os::getenv(var) {
-      None => mk_uniq_str(cx, sp, ~""),
-      Some(ref s) => mk_uniq_str(cx, sp, copy *s)
+      None => mk_base_str(cx, sp, ~""),
+      Some(ref s) => mk_base_str(cx, sp, copy *s)
     };
     MRExpr(e)
 }