lint: extend #[must_use] to handle a message.

Similar to the stability attributes, a type annotated with `#[must_use =
"informative snippet"]` will print the normal warning message along with
"informative snippet". This allows the type author to provide some
guidance about why the type should be used.
This commit is contained in:
Huon Wilson 2014-07-09 22:02:19 +10:00
parent 66e1f11ef4
commit b9e35a1644
2 changed files with 29 additions and 11 deletions

View file

@ -669,22 +669,13 @@ impl LintPass for UnusedResult {
if ast_util::is_local(did) {
match cx.tcx.map.get(did.node) {
ast_map::NodeItem(it) => {
if attr::contains_name(it.attrs.as_slice(),
"must_use") {
cx.span_lint(UNUSED_MUST_USE, s.span,
"unused result which must be used");
warned = true;
}
warned |= check_must_use(cx, it.attrs.as_slice(), s.span);
}
_ => {}
}
} else {
csearch::get_item_attrs(&cx.sess().cstore, did, |attrs| {
if attr::contains_name(attrs.as_slice(), "must_use") {
cx.span_lint(UNUSED_MUST_USE, s.span,
"unused result which must be used");
warned = true;
}
warned |= check_must_use(cx, attrs.as_slice(), s.span);
});
}
}
@ -693,6 +684,25 @@ impl LintPass for UnusedResult {
if !warned {
cx.span_lint(UNUSED_RESULT, s.span, "unused result");
}
fn check_must_use(cx: &Context, attrs: &[ast::Attribute], sp: Span) -> bool {
for attr in attrs.iter() {
if attr.check_name("must_use") {
let mut msg = "unused result which must be used".to_string();
// check for #[must_use="..."]
match attr.value_str() {
None => {}
Some(s) => {
msg.push_str(": ");
msg.push_str(s.get());
}
}
cx.span_lint(UNUSED_MUST_USE, sp, msg.as_slice());
return true;
}
}
false
}
}
}

View file

@ -14,27 +14,35 @@
#[must_use]
enum MustUse { Test }
#[must_use = "some message"]
enum MustUseMsg { Test2 }
fn foo<T>() -> T { fail!() }
fn bar() -> int { return foo::<int>(); }
fn baz() -> MustUse { return foo::<MustUse>(); }
fn qux() -> MustUseMsg { return foo::<MustUseMsg>(); }
#[allow(unused_result)]
fn test() {
foo::<int>();
foo::<MustUse>(); //~ ERROR: unused result which must be used
foo::<MustUseMsg>(); //~ ERROR: unused result which must be used: some message
}
#[allow(unused_result, unused_must_use)]
fn test2() {
foo::<int>();
foo::<MustUse>();
foo::<MustUseMsg>();
}
fn main() {
foo::<int>(); //~ ERROR: unused result
foo::<MustUse>(); //~ ERROR: unused result which must be used
foo::<MustUseMsg>(); //~ ERROR: unused result which must be used: some message
let _ = foo::<int>();
let _ = foo::<MustUse>();
let _ = foo::<MustUseMsg>();
}