2012-01-19 16:50:51 +08:00
|
|
|
import driver::session::session;
|
|
|
|
import middle::ty::ctxt;
|
|
|
|
import syntax::{ast, visit};
|
2012-03-22 18:16:22 -07:00
|
|
|
import syntax::attr;
|
2012-03-07 16:48:57 -08:00
|
|
|
import std::map::hashmap;
|
2012-01-22 01:20:22 +08:00
|
|
|
import io::writer_util;
|
2012-01-19 16:50:51 +08:00
|
|
|
|
|
|
|
enum option {
|
2012-01-19 17:56:05 -08:00
|
|
|
ctypes,
|
2012-01-19 16:50:51 +08:00
|
|
|
}
|
|
|
|
|
2012-01-22 01:20:22 +08:00
|
|
|
impl opt_ for option {
|
|
|
|
fn desc() -> str {
|
|
|
|
"lint: " + alt self {
|
|
|
|
ctypes { "ctypes usage checking" }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn run(tcx: ty::ctxt, crate: @ast::crate, time_pass: bool) {
|
|
|
|
let checker = alt self {
|
|
|
|
ctypes {
|
|
|
|
bind check_ctypes(tcx, crate)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
time(time_pass, self.desc(), checker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Copied from driver.rs, to work around a bug(#1566)
|
2012-01-23 14:59:00 -08:00
|
|
|
fn time(do_it: bool, what: str, thunk: fn()) {
|
2012-01-22 01:20:22 +08:00
|
|
|
if !do_it{ ret thunk(); }
|
|
|
|
let start = std::time::precise_time_s();
|
|
|
|
thunk();
|
|
|
|
let end = std::time::precise_time_s();
|
|
|
|
io::stdout().write_str(#fmt("time: %3.3f s\t%s\n",
|
|
|
|
end - start, what));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge lint options specified by crate attributes and rustc command
|
|
|
|
// line. Precedence: cmdline > attribute > default
|
|
|
|
fn merge_opts(attrs: [ast::attribute], cmd_opts: [(option, bool)]) ->
|
|
|
|
[(option, bool)] {
|
|
|
|
fn str_to_option(name: str) -> (option, bool) {
|
2012-02-15 09:40:42 +01:00
|
|
|
ret alt check name {
|
2012-01-22 01:20:22 +08:00
|
|
|
"ctypes" { (ctypes, true) }
|
|
|
|
"no_ctypes" { (ctypes, false) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn meta_to_option(meta: @ast::meta_item) -> (option, bool) {
|
|
|
|
ret alt meta.node {
|
|
|
|
ast::meta_word(name) {
|
|
|
|
str_to_option(name)
|
|
|
|
}
|
2012-01-30 21:00:57 -08:00
|
|
|
_ { fail "meta_to_option: meta_list contains a non-meta-word"; }
|
2012-01-22 01:20:22 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn default() -> [(option, bool)] {
|
|
|
|
[(ctypes, true)]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn contains(xs: [(option, bool)], x: option) -> bool {
|
2012-04-06 20:01:43 +02:00
|
|
|
for xs.each {|c|
|
|
|
|
let (o, _) = c;
|
2012-01-22 01:20:22 +08:00
|
|
|
if o == x { ret true; }
|
|
|
|
}
|
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut result = cmd_opts;
|
2012-01-22 01:20:22 +08:00
|
|
|
|
|
|
|
let lint_metas =
|
|
|
|
attr::attr_metas(attr::find_attrs_by_name(attrs, "lint"));
|
|
|
|
|
|
|
|
vec::iter(lint_metas) {|mi|
|
|
|
|
alt mi.node {
|
|
|
|
ast::meta_list(_, list) {
|
|
|
|
vec::iter(list) {|e|
|
|
|
|
let (o, v) = meta_to_option(e);
|
|
|
|
if !contains(cmd_opts, o) {
|
|
|
|
result += [(o, v)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-04-06 20:01:43 +02:00
|
|
|
for default().each {|c|
|
|
|
|
let (o, v) = c;
|
2012-01-22 01:20:22 +08:00
|
|
|
if !contains(result, o) {
|
|
|
|
result += [(o, v)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2012-01-19 20:29:50 +08:00
|
|
|
fn check_ctypes(tcx: ty::ctxt, crate: @ast::crate) {
|
|
|
|
fn check_native_fn(tcx: ty::ctxt, decl: ast::fn_decl) {
|
2012-01-19 16:50:51 +08:00
|
|
|
let tys = vec::map(decl.inputs) {|a| a.ty };
|
2012-04-06 20:01:43 +02:00
|
|
|
for vec::each(tys + [decl.output]) {|ty|
|
2012-01-19 16:50:51 +08:00
|
|
|
alt ty.node {
|
2012-02-06 15:29:56 +01:00
|
|
|
ast::ty_path(_, id) {
|
|
|
|
alt tcx.def_map.get(id) {
|
|
|
|
ast::def_prim_ty(ast::ty_int(ast::ty_i)) {
|
|
|
|
tcx.sess.span_warn(
|
|
|
|
ty.span,
|
|
|
|
"found rust type `int` in native module, while \
|
2012-03-12 20:04:27 -07:00
|
|
|
libc::c_int or libc::c_long should be used");
|
2012-02-06 15:29:56 +01:00
|
|
|
}
|
|
|
|
ast::def_prim_ty(ast::ty_uint(ast::ty_u)) {
|
|
|
|
tcx.sess.span_warn(
|
|
|
|
ty.span,
|
|
|
|
"found rust type `uint` in native module, while \
|
2012-03-12 20:04:27 -07:00
|
|
|
libc::c_uint or libc::c_ulong should be used");
|
2012-02-06 15:29:56 +01:00
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
2012-01-19 16:50:51 +08:00
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-19 20:29:50 +08:00
|
|
|
fn check_item(tcx: ty::ctxt, it: @ast::item) {
|
2012-01-19 16:50:51 +08:00
|
|
|
alt it.node {
|
2012-03-21 15:42:20 +01:00
|
|
|
ast::item_native_mod(nmod) if attr::native_abi(it.attrs) !=
|
2012-03-23 15:05:16 +01:00
|
|
|
either::right(ast::native_abi_rust_intrinsic) {
|
2012-04-06 20:01:43 +02:00
|
|
|
for nmod.items.each {|ni|
|
2012-01-19 16:50:51 +08:00
|
|
|
alt ni.node {
|
|
|
|
ast::native_item_fn(decl, tps) {
|
2012-01-19 20:29:50 +08:00
|
|
|
check_native_fn(tcx, decl);
|
2012-01-19 16:50:51 +08:00
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ {/* nothing to do */ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let visit = visit::mk_simple_visitor(@{
|
2012-01-19 20:29:50 +08:00
|
|
|
visit_item: bind check_item(tcx, _)
|
2012-01-19 16:50:51 +08:00
|
|
|
with *visit::default_simple_visitor()
|
|
|
|
});
|
|
|
|
visit::visit_crate(*crate, (), visit);
|
|
|
|
}
|
2012-01-22 01:20:22 +08:00
|
|
|
|
|
|
|
fn check_crate(tcx: ty::ctxt, crate: @ast::crate,
|
|
|
|
opts: [(option, bool)], time: bool) {
|
|
|
|
let lint_opts = lint::merge_opts(crate.node.attrs, opts);
|
2012-04-06 20:01:43 +02:00
|
|
|
for lint_opts.each {|opt|
|
|
|
|
let (lopt, switch) = opt;
|
2012-01-22 01:20:22 +08:00
|
|
|
if switch == true {
|
|
|
|
lopt.run(tcx, crate, time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-19 16:50:51 +08:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|