diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2013-05-18 03:07:28 -0400 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2013-05-20 16:08:50 -0500 |
| commit | 074799b4c586c521ba678a4dc3809cad1a872dfe (patch) | |
| tree | 484319afafafb263fbf39f6b327d68abd087e0f0 /src | |
| parent | 26babaafcdbcfdf2e842d84dbeabbed0dae6efef (diff) | |
| download | rust-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.rs | 70 | ||||
| -rw-r--r-- | src/libsyntax/ext/env.rs | 6 |
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) } |
