Implement support for indicating the stability of items.

There are 6 new compiler recognised attributes: deprecated, experimental,
unstable, stable, frozen, locked (these levels are taken directly from
Node's "stability index"[1]). These indicate the stability of the
item to which they are attached; e.g. `#[deprecated] fn foo() { .. }`
says that `foo` is deprecated.

This comes with 3 lints for the first 3 levels (with matching names) that
will detect the use of items marked with them (the `unstable` lint
includes items with no stability attribute). The attributes can be given
a short text note that will be displayed by the lint. An example:

    #[warn(unstable)]; // `allow` by default

    #[deprecated="use `bar`"]
    fn foo() { }

    #[stable]
    fn bar() { }

    fn baz() { }

    fn main() {
        foo(); // "warning: use of deprecated item: use `bar`"

        bar(); // all fine

        baz(); // "warning: use of unmarked item"
    }

The lints currently only check the "edges" of the AST: i.e. functions,
methods[2], structs and enum variants. Any stability attributes on modules,
enums, traits and impls are not checked.

[1]: http://nodejs.org/api/documentation.html
[2]: the method check is currently incorrect and doesn't work.
This commit is contained in:
Huon Wilson 2013-08-31 17:13:57 +10:00
parent 7048e05d5f
commit 506f69aed7
8 changed files with 745 additions and 3 deletions

View file

@ -80,6 +80,26 @@ pub enum ast_node {
node_callee_scope(@Expr)
}
impl ast_node {
pub fn with_attrs<T>(&self, f: &fn(Option<&[Attribute]>) -> T) -> T {
let attrs = match *self {
node_item(i, _) => Some(i.attrs.as_slice()),
node_foreign_item(fi, _, _, _) => Some(fi.attrs.as_slice()),
node_trait_method(tm, _, _) => match *tm {
required(ref type_m) => Some(type_m.attrs.as_slice()),
provided(m) => Some(m.attrs.as_slice())
},
node_method(m, _, _) => Some(m.attrs.as_slice()),
node_variant(ref v, _, _) => Some(v.node.attrs.as_slice()),
// unit/tuple structs take the attributes straight from
// the struct definition.
node_struct_ctor(_, strct, _) => Some(strct.attrs.as_slice()),
_ => None
};
f(attrs)
}
}
pub type map = @mut HashMap<NodeId, ast_node>;
pub struct Ctx {

View file

@ -313,6 +313,44 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>>
no_cfgs || some_cfg_matches
}
/// Represents the #[deprecated="foo"] (etc) attributes.
pub struct Stability {
level: StabilityLevel,
text: Option<@str>
}
/// The available stability levels.
#[deriving(Eq,Ord,Clone)]
pub enum StabilityLevel {
Deprecated,
Experimental,
Unstable,
Stable,
Frozen,
Locked
}
/// Find the first stability attribute. `None` if none exists.
pub fn find_stability<AM: AttrMetaMethods, It: Iterator<AM>>(mut metas: It) -> Option<Stability> {
for m in metas {
let level = match m.name().as_slice() {
"deprecated" => Deprecated,
"experimental" => Experimental,
"unstable" => Unstable,
"stable" => Stable,
"frozen" => Frozen,
"locked" => Locked,
_ => loop // not a stability level
};
return Some(Stability {
level: level,
text: m.value_str()
});
}
None
}
pub fn require_unique_names(diagnostic: @mut span_handler,
metas: &[@MetaItem]) {
let mut set = HashSet::new();