Add lint groups; define built-in lint groups `bad_style` and `unused`
This adds support for lint groups to the compiler. Lint groups are a way of grouping a number of lints together under one name. For example, this also defines a default lint for naming conventions, named `bad_style`. Writing `#[allow(bad_style)]` is equivalent to writing `#[allow(non_camel_case_types, non_snake_case, non_uppercase_statics)]`. These lint groups can also be defined as a compiler plugin using the new `Registry::register_lint_group` method. This also adds two built-in lint groups, `bad_style` and `unused`. The contents of these groups can be seen by running `rustc -W help`.
This commit is contained in:
parent
de7abd8824
commit
ed2aad8b43
|
@ -157,7 +157,6 @@ macro_rules! impl_hash_tuple(
|
||||||
|
|
||||||
( $($name:ident)+) => (
|
( $($name:ident)+) => (
|
||||||
impl<S: Writer, $($name: Hash<S>),*> Hash<S> for ($($name,)*) {
|
impl<S: Writer, $($name: Hash<S>),*> Hash<S> for ($($name,)*) {
|
||||||
#[allow(uppercase_variables)]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hash(&self, state: &mut S) {
|
fn hash(&self, state: &mut S) {
|
||||||
|
|
|
@ -775,7 +775,7 @@ macro_rules! def_fn_mut(
|
||||||
FnMut<($($args,)*),Result>
|
FnMut<($($args,)*),Result>
|
||||||
for extern "Rust" fn($($args: $args,)*) -> Result {
|
for extern "Rust" fn($($args: $args,)*) -> Result {
|
||||||
#[rust_call_abi_hack]
|
#[rust_call_abi_hack]
|
||||||
#[allow(uppercase_variables)]
|
#[allow(non_snake_case)]
|
||||||
fn call_mut(&mut self, args: ($($args,)*)) -> Result {
|
fn call_mut(&mut self, args: ($($args,)*)) -> Result {
|
||||||
let ($($args,)*) = args;
|
let ($($args,)*) = args;
|
||||||
(*self)($($args,)*)
|
(*self)($($args,)*)
|
||||||
|
|
|
@ -242,13 +242,17 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let Registry { syntax_exts, lint_passes, .. } = registry;
|
let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut ls = sess.lint_store.borrow_mut();
|
let mut ls = sess.lint_store.borrow_mut();
|
||||||
for pass in lint_passes.move_iter() {
|
for pass in lint_passes.move_iter() {
|
||||||
ls.register_pass(Some(sess), true, pass);
|
ls.register_pass(Some(sess), true, pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (name, to) in lint_groups.move_iter() {
|
||||||
|
ls.register_group(Some(sess), true, name, to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lint plugins are registered; now we can process command line flags.
|
// Lint plugins are registered; now we can process command line flags.
|
||||||
|
|
|
@ -180,14 +180,26 @@ Available lint options:
|
||||||
lints
|
lints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
|
||||||
|
-> Vec<(&'static str, Vec<lint::LintId>)> {
|
||||||
|
let mut lints: Vec<_> = lints.move_iter().map(|(x, y, _)| (x, y)).collect();
|
||||||
|
lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
|
||||||
|
&(y, _): &(&'static str, Vec<lint::LintId>)| {
|
||||||
|
x.cmp(&y)
|
||||||
|
});
|
||||||
|
lints
|
||||||
|
}
|
||||||
|
|
||||||
let (plugin, builtin) = lint_store.get_lints().partitioned(|&(_, p)| p);
|
let (plugin, builtin) = lint_store.get_lints().partitioned(|&(_, p)| p);
|
||||||
let plugin = sort_lints(plugin);
|
let plugin = sort_lints(plugin);
|
||||||
let builtin = sort_lints(builtin);
|
let builtin = sort_lints(builtin);
|
||||||
|
|
||||||
// FIXME (#7043): We should use the width in character cells rather than
|
let (plugin_groups, builtin_groups) = lint_store.get_lint_groups().partitioned(|&(_, _, p)| p);
|
||||||
// the number of codepoints.
|
let plugin_groups = sort_lint_groups(plugin_groups);
|
||||||
|
let builtin_groups = sort_lint_groups(builtin_groups);
|
||||||
|
|
||||||
let max_name_len = plugin.iter().chain(builtin.iter())
|
let max_name_len = plugin.iter().chain(builtin.iter())
|
||||||
.map(|&s| s.name.char_len())
|
.map(|&s| s.name.width(true))
|
||||||
.max().unwrap_or(0);
|
.max().unwrap_or(0);
|
||||||
let padded = |x: &str| {
|
let padded = |x: &str| {
|
||||||
" ".repeat(max_name_len - x.char_len()).append(x)
|
" ".repeat(max_name_len - x.char_len()).append(x)
|
||||||
|
@ -208,16 +220,48 @@ Available lint options:
|
||||||
|
|
||||||
print_lints(builtin);
|
print_lints(builtin);
|
||||||
|
|
||||||
match (loaded_plugins, plugin.len()) {
|
|
||||||
(false, 0) => {
|
|
||||||
println!("Compiler plugins can provide additional lints. To see a listing of these, \
|
let max_name_len = plugin_groups.iter().chain(builtin_groups.iter())
|
||||||
re-run `rustc -W help` with a crate filename.");
|
.map(|&(s, _)| s.width(true))
|
||||||
|
.max().unwrap_or(0);
|
||||||
|
let padded = |x: &str| {
|
||||||
|
" ".repeat(max_name_len - x.char_len()).append(x)
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Lint groups provided by rustc:\n");
|
||||||
|
println!(" {} {}", padded("name"), "sub-lints");
|
||||||
|
println!(" {} {}", padded("----"), "---------");
|
||||||
|
|
||||||
|
let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
|
||||||
|
for (name, to) in lints.move_iter() {
|
||||||
|
let name = name.chars().map(|x| x.to_lowercase())
|
||||||
|
.collect::<String>().replace("_", "-");
|
||||||
|
let desc = to.move_iter().map(|x| x.as_str()).collect::<Vec<String>>().connect(", ");
|
||||||
|
println!(" {} {}",
|
||||||
|
padded(name.as_slice()), desc);
|
||||||
}
|
}
|
||||||
(false, _) => fail!("didn't load lint plugins but got them anyway!"),
|
println!("\n");
|
||||||
(true, 0) => println!("This crate does not load any lint plugins."),
|
};
|
||||||
(true, _) => {
|
|
||||||
println!("Lint checks provided by plugins loaded by this crate:\n");
|
print_lint_groups(builtin_groups);
|
||||||
print_lints(plugin);
|
|
||||||
|
match (loaded_plugins, plugin.len(), plugin_groups.len()) {
|
||||||
|
(false, 0, _) | (false, _, 0) => {
|
||||||
|
println!("Compiler plugins can provide additional lints and lint groups. To see a \
|
||||||
|
listing of these, re-run `rustc -W help` with a crate filename.");
|
||||||
|
}
|
||||||
|
(false, _, _) => fail!("didn't load lint plugins but got them anyway!"),
|
||||||
|
(true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
|
||||||
|
(true, l, g) => {
|
||||||
|
if l > 0 {
|
||||||
|
println!("Lint checks provided by plugins loaded by this crate:\n");
|
||||||
|
print_lints(plugin);
|
||||||
|
}
|
||||||
|
if g > 0 {
|
||||||
|
println!("Lint groups provided by plugins loaded by this crate:\n");
|
||||||
|
print_lint_groups(plugin_groups);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -736,7 +736,7 @@ impl LintPass for UnusedResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(NON_CAMEL_CASE_TYPES, Warn,
|
declare_lint!(pub NON_CAMEL_CASE_TYPES, Warn,
|
||||||
"types, variants, traits and type parameters should have camel case names")
|
"types, variants, traits and type parameters should have camel case names")
|
||||||
|
|
||||||
pub struct NonCamelCaseTypes;
|
pub struct NonCamelCaseTypes;
|
||||||
|
@ -844,7 +844,7 @@ fn method_context(cx: &Context, m: &ast::Method) -> MethodContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(NON_SNAKE_CASE, Warn,
|
declare_lint!(pub NON_SNAKE_CASE, Warn,
|
||||||
"methods, functions, lifetime parameters and modules should have snake case names")
|
"methods, functions, lifetime parameters and modules should have snake case names")
|
||||||
|
|
||||||
pub struct NonSnakeCase;
|
pub struct NonSnakeCase;
|
||||||
|
@ -930,8 +930,8 @@ impl LintPass for NonSnakeCase {
|
||||||
self.check_snake_case(cx, "trait method", t.ident, t.span);
|
self.check_snake_case(cx, "trait method", t.ident, t.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lifetime_decl(&mut self, cx: &Context, t: &ast::Lifetime) {
|
fn check_lifetime_decl(&mut self, cx: &Context, t: &ast::LifetimeDef) {
|
||||||
self.check_snake_case(cx, "lifetime", t.name.ident(), t.span);
|
self.check_snake_case(cx, "lifetime", t.lifetime.name.ident(), t.lifetime.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||||
|
@ -962,7 +962,7 @@ impl LintPass for NonSnakeCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(NON_UPPERCASE_STATICS, Allow,
|
declare_lint!(pub NON_UPPERCASE_STATICS, Allow,
|
||||||
"static constants should have uppercase identifiers")
|
"static constants should have uppercase identifiers")
|
||||||
|
|
||||||
pub struct NonUppercaseStatics;
|
pub struct NonUppercaseStatics;
|
||||||
|
@ -1143,7 +1143,7 @@ impl LintPass for UnsafeBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(UNUSED_MUT, Warn,
|
declare_lint!(pub UNUSED_MUT, Warn,
|
||||||
"detect mut variables which don't need to be mutable")
|
"detect mut variables which don't need to be mutable")
|
||||||
|
|
||||||
pub struct UnusedMut;
|
pub struct UnusedMut;
|
||||||
|
|
|
@ -66,6 +66,10 @@ pub struct LintStore {
|
||||||
|
|
||||||
/// Current levels of each lint, and where they were set.
|
/// Current levels of each lint, and where they were set.
|
||||||
levels: HashMap<LintId, LevelSource>,
|
levels: HashMap<LintId, LevelSource>,
|
||||||
|
|
||||||
|
/// Map of registered lint groups to what lints they expand to. The bool
|
||||||
|
/// is true if the lint group was added by a plugin.
|
||||||
|
lint_groups: HashMap<&'static str, (Vec<LintId>, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintStore {
|
impl LintStore {
|
||||||
|
@ -90,6 +94,7 @@ impl LintStore {
|
||||||
passes: Some(vec!()),
|
passes: Some(vec!()),
|
||||||
by_name: HashMap::new(),
|
by_name: HashMap::new(),
|
||||||
levels: HashMap::new(),
|
levels: HashMap::new(),
|
||||||
|
lint_groups: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +102,10 @@ impl LintStore {
|
||||||
self.lints.as_slice()
|
self.lints.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
|
||||||
|
self.lint_groups.iter().map(|(k, &(ref v, b))| (*k, v.clone(), b)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register_pass(&mut self, sess: Option<&Session>,
|
pub fn register_pass(&mut self, sess: Option<&Session>,
|
||||||
from_plugin: bool, pass: LintPassObject) {
|
from_plugin: bool, pass: LintPassObject) {
|
||||||
for &lint in pass.get_lints().iter() {
|
for &lint in pass.get_lints().iter() {
|
||||||
|
@ -123,6 +132,25 @@ impl LintStore {
|
||||||
self.passes.get_mut_ref().push(pass);
|
self.passes.get_mut_ref().push(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn register_group(&mut self, sess: Option<&Session>,
|
||||||
|
from_plugin: bool, name: &'static str,
|
||||||
|
to: Vec<LintId>) {
|
||||||
|
let new = self.lint_groups.insert(name, (to, from_plugin));
|
||||||
|
|
||||||
|
if !new {
|
||||||
|
let msg = format!("duplicate specification of lint group {}", name);
|
||||||
|
match (sess, from_plugin) {
|
||||||
|
// We load builtin lints first, so a duplicate is a compiler bug.
|
||||||
|
// Use early_error when handling -W help with no crate.
|
||||||
|
(None, _) => early_error(msg.as_slice()),
|
||||||
|
(Some(sess), false) => sess.bug(msg.as_slice()),
|
||||||
|
|
||||||
|
// A duplicate name from a plugin is a user error.
|
||||||
|
(Some(sess), true) => sess.err(msg.as_slice()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register_builtin(&mut self, sess: Option<&Session>) {
|
pub fn register_builtin(&mut self, sess: Option<&Session>) {
|
||||||
macro_rules! add_builtin ( ( $sess:ident, $($name:ident),*, ) => (
|
macro_rules! add_builtin ( ( $sess:ident, $($name:ident),*, ) => (
|
||||||
{$(
|
{$(
|
||||||
|
@ -136,6 +164,10 @@ impl LintStore {
|
||||||
)*}
|
)*}
|
||||||
))
|
))
|
||||||
|
|
||||||
|
macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => (
|
||||||
|
self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
|
||||||
|
))
|
||||||
|
|
||||||
add_builtin!(sess,
|
add_builtin!(sess,
|
||||||
HardwiredLints,
|
HardwiredLints,
|
||||||
WhileTrue,
|
WhileTrue,
|
||||||
|
@ -162,6 +194,13 @@ impl LintStore {
|
||||||
MissingDoc,
|
MissingDoc,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_lint_group!(sess, "bad_style",
|
||||||
|
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPERCASE_STATICS)
|
||||||
|
|
||||||
|
add_lint_group!(sess, "unused",
|
||||||
|
UNUSED_IMPORTS, UNUSED_VARIABLE, DEAD_ASSIGNMENT, DEAD_CODE,
|
||||||
|
UNUSED_MUT, UNREACHABLE_CODE)
|
||||||
|
|
||||||
// We have one lint pass defined in this module.
|
// We have one lint pass defined in this module.
|
||||||
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
|
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
|
||||||
}
|
}
|
||||||
|
@ -170,8 +209,20 @@ impl LintStore {
|
||||||
for &(ref lint_name, level) in sess.opts.lint_opts.iter() {
|
for &(ref lint_name, level) in sess.opts.lint_opts.iter() {
|
||||||
match self.by_name.find_equiv(&lint_name.as_slice()) {
|
match self.by_name.find_equiv(&lint_name.as_slice()) {
|
||||||
Some(&lint_id) => self.set_level(lint_id, (level, CommandLine)),
|
Some(&lint_id) => self.set_level(lint_id, (level, CommandLine)),
|
||||||
None => sess.err(format!("unknown {} flag: {}",
|
None => {
|
||||||
level.as_str(), lint_name).as_slice()),
|
match self.lint_groups.iter().map(|(&x, &(ref y, _))| (x, y.clone()))
|
||||||
|
.collect::<HashMap<&'static str, Vec<LintId>>>()
|
||||||
|
.find_equiv(&lint_name.as_slice()) {
|
||||||
|
Some(v) => {
|
||||||
|
v.iter()
|
||||||
|
.map(|lint_id: &LintId|
|
||||||
|
self.set_level(*lint_id, (level, CommandLine)))
|
||||||
|
.collect::<Vec<()>>();
|
||||||
|
}
|
||||||
|
None => sess.err(format!("unknown {} flag: {}",
|
||||||
|
level.as_str(), lint_name).as_slice()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,7 +356,7 @@ impl<'a> Context<'a> {
|
||||||
krate: krate,
|
krate: krate,
|
||||||
exported_items: exported_items,
|
exported_items: exported_items,
|
||||||
lints: lint_store,
|
lints: lint_store,
|
||||||
level_stack: vec!(),
|
level_stack: vec![],
|
||||||
node_levels: RefCell::new(HashMap::new()),
|
node_levels: RefCell::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,35 +410,46 @@ impl<'a> Context<'a> {
|
||||||
let mut pushed = 0u;
|
let mut pushed = 0u;
|
||||||
|
|
||||||
for result in gather_attrs(attrs).move_iter() {
|
for result in gather_attrs(attrs).move_iter() {
|
||||||
let (lint_id, level, span) = match result {
|
let v = match result {
|
||||||
Err(span) => {
|
Err(span) => {
|
||||||
self.tcx.sess.span_err(span, "malformed lint attribute");
|
self.tcx.sess.span_err(span, "malformed lint attribute");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Ok((lint_name, level, span)) => {
|
Ok((lint_name, level, span)) => {
|
||||||
match self.lints.by_name.find_equiv(&lint_name.get()) {
|
match self.lints.by_name.find_equiv(&lint_name.get()) {
|
||||||
Some(&lint_id) => (lint_id, level, span),
|
Some(&lint_id) => vec![(lint_id, level, span)],
|
||||||
None => {
|
None => {
|
||||||
self.span_lint(builtin::UNRECOGNIZED_LINT, span,
|
match self.lints.lint_groups.find_equiv(&lint_name.get()) {
|
||||||
format!("unknown `{}` attribute: `{}`",
|
Some(&(ref v, _)) => v.iter()
|
||||||
level.as_str(), lint_name).as_slice());
|
.map(|lint_id: &LintId|
|
||||||
continue;
|
(*lint_id, level, span))
|
||||||
|
.collect(),
|
||||||
|
None => {
|
||||||
|
self.span_lint(builtin::UNRECOGNIZED_LINT, span,
|
||||||
|
format!("unknown `{}` attribute: `{}`",
|
||||||
|
level.as_str(), lint_name).as_slice());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let now = self.lints.get_level_source(lint_id).val0();
|
for (lint_id, level, span) in v.move_iter() {
|
||||||
if now == Forbid && level != Forbid {
|
let now = self.lints.get_level_source(lint_id).val0();
|
||||||
let lint_name = lint_id.as_str();
|
if now == Forbid && level != Forbid {
|
||||||
self.tcx.sess.span_err(span,
|
let lint_name = lint_id.as_str();
|
||||||
format!("{}({}) overruled by outer forbid({})",
|
self.tcx.sess.span_err(span,
|
||||||
level.as_str(), lint_name, lint_name).as_slice());
|
format!("{}({}) overruled by outer forbid({})",
|
||||||
} else if now != level {
|
level.as_str(), lint_name,
|
||||||
let src = self.lints.get_level_source(lint_id).val1();
|
lint_name).as_slice());
|
||||||
self.level_stack.push((lint_id, (now, src)));
|
} else if now != level {
|
||||||
pushed += 1;
|
let src = self.lints.get_level_source(lint_id).val1();
|
||||||
self.lints.set_level(lint_id, (level, Node(span)));
|
self.level_stack.push((lint_id, (now, src)));
|
||||||
|
pushed += 1;
|
||||||
|
self.lints.set_level(lint_id, (level, Node(span)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub struct Equate<'f> {
|
||||||
fields: CombineFields<'f>
|
fields: CombineFields<'f>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case_functions)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Equate<'f>(cf: CombineFields<'f>) -> Equate<'f> {
|
pub fn Equate<'f>(cf: CombineFields<'f>) -> Equate<'f> {
|
||||||
Equate { fields: cf }
|
Equate { fields: cf }
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub struct Glb<'f> {
|
||||||
fields: CombineFields<'f>
|
fields: CombineFields<'f>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case_functions)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Glb<'f>(cf: CombineFields<'f>) -> Glb<'f> {
|
pub fn Glb<'f>(cf: CombineFields<'f>) -> Glb<'f> {
|
||||||
Glb { fields: cf }
|
Glb { fields: cf }
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub struct Lub<'f> {
|
||||||
fields: CombineFields<'f>
|
fields: CombineFields<'f>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case_functions)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Lub<'f>(cf: CombineFields<'f>) -> Lub<'f> {
|
pub fn Lub<'f>(cf: CombineFields<'f>) -> Lub<'f> {
|
||||||
Lub { fields: cf }
|
Lub { fields: cf }
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub struct Sub<'f> {
|
||||||
fields: CombineFields<'f>
|
fields: CombineFields<'f>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case_functions)]
|
#[allow(non_snake_case)]
|
||||||
pub fn Sub<'f>(cf: CombineFields<'f>) -> Sub<'f> {
|
pub fn Sub<'f>(cf: CombineFields<'f>) -> Sub<'f> {
|
||||||
Sub { fields: cf }
|
Sub { fields: cf }
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
//! Used by plugin crates to tell `rustc` about the plugins they provide.
|
//! Used by plugin crates to tell `rustc` about the plugins they provide.
|
||||||
|
|
||||||
use lint::LintPassObject;
|
use lint::{LintPassObject, LintId, Lint};
|
||||||
|
|
||||||
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
||||||
use syntax::ext::base::{IdentTT, LetSyntaxTT, ItemDecorator, ItemModifier, BasicMacroExpander};
|
use syntax::ext::base::{IdentTT, LetSyntaxTT, ItemDecorator, ItemModifier, BasicMacroExpander};
|
||||||
|
@ -19,6 +19,8 @@ use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Structure used to register plugins.
|
/// Structure used to register plugins.
|
||||||
///
|
///
|
||||||
/// A plugin registrar function takes an `&mut Registry` and should call
|
/// A plugin registrar function takes an `&mut Registry` and should call
|
||||||
|
@ -36,6 +38,9 @@ pub struct Registry {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub lint_passes: Vec<LintPassObject>,
|
pub lint_passes: Vec<LintPassObject>,
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registry {
|
impl Registry {
|
||||||
|
@ -45,6 +50,7 @@ impl Registry {
|
||||||
krate_span: krate.span,
|
krate_span: krate.span,
|
||||||
syntax_exts: vec!(),
|
syntax_exts: vec!(),
|
||||||
lint_passes: vec!(),
|
lint_passes: vec!(),
|
||||||
|
lint_groups: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,4 +86,9 @@ impl Registry {
|
||||||
pub fn register_lint_pass(&mut self, lint_pass: LintPassObject) {
|
pub fn register_lint_pass(&mut self, lint_pass: LintPassObject) {
|
||||||
self.lint_passes.push(lint_pass);
|
self.lint_passes.push(lint_pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a lint group.
|
||||||
|
pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) {
|
||||||
|
self.lint_groups.insert(name, to.move_iter().map(|x| LintId::of(x)).collect());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,10 +218,10 @@ impl<T: 'static> KeyValue<T> {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
(0, Some(newValue)) => {
|
(0, Some(new_value)) => {
|
||||||
// The current value is uninitialized and we're storing a new value.
|
// The current value is uninitialized and we're storing a new value.
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::write(&mut (*value_box).value, newValue);
|
ptr::write(&mut (*value_box).value, new_value);
|
||||||
*(*value_box).refcount.get() = 1;
|
*(*value_box).refcount.get() = 1;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -234,10 +234,10 @@ impl<T: 'static> KeyValue<T> {
|
||||||
Some(ret)
|
Some(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(1, Some(newValue)) => {
|
(1, Some(new_value)) => {
|
||||||
// We have an initialized value and we're replacing it.
|
// We have an initialized value and we're replacing it.
|
||||||
let value_ref = unsafe { &mut (*value_box).value };
|
let value_ref = unsafe { &mut (*value_box).value };
|
||||||
let ret = mem::replace(value_ref, newValue);
|
let ret = mem::replace(value_ref, new_value);
|
||||||
// Refcount is already 1, leave it as that.
|
// Refcount is already 1, leave it as that.
|
||||||
Some(ret)
|
Some(ret)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// force-host
|
||||||
|
|
||||||
|
#![feature(phase, plugin_registrar)]
|
||||||
|
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
// Load rustc as a plugin to get macros
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate rustc;
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::parse::token;
|
||||||
|
use rustc::lint::{Context, LintPass, LintPassObject, LintArray};
|
||||||
|
use rustc::plugin::Registry;
|
||||||
|
|
||||||
|
declare_lint!(TEST_LINT, Warn,
|
||||||
|
"Warn about items named 'lintme'")
|
||||||
|
|
||||||
|
declare_lint!(PLEASE_LINT, Warn,
|
||||||
|
"Warn about items named 'pleaselintme'")
|
||||||
|
|
||||||
|
struct Pass;
|
||||||
|
|
||||||
|
impl LintPass for Pass {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(TEST_LINT, PLEASE_LINT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
|
||||||
|
let name = token::get_ident(it.ident);
|
||||||
|
if name.get() == "lintme" {
|
||||||
|
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
|
||||||
|
} else if name.get() == "pleaselintme" {
|
||||||
|
cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[plugin_registrar]
|
||||||
|
pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
|
reg.register_lint_pass(box Pass as LintPassObject);
|
||||||
|
reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:lint_group_plugin_test.rs
|
||||||
|
// ignore-stage1
|
||||||
|
// compile-flags: -D lint-me
|
||||||
|
|
||||||
|
#![feature(phase)]
|
||||||
|
|
||||||
|
#[phase(plugin)]
|
||||||
|
extern crate lint_group_plugin_test;
|
||||||
|
|
||||||
|
fn lintme() { } //~ ERROR item is named 'lintme'
|
||||||
|
|
||||||
|
fn pleaselintme() { } //~ ERROR item is named 'pleaselintme'
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
lintme();
|
||||||
|
pleaselintme();
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![deny(bad_style)]
|
||||||
|
//~^ NOTE lint level defined here
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name
|
||||||
|
|
||||||
|
#[allow(bad_style)]
|
||||||
|
mod test {
|
||||||
|
fn CamelCase() {}
|
||||||
|
|
||||||
|
#[forbid(bad_style)]
|
||||||
|
//~^ NOTE lint level defined here
|
||||||
|
//~^^ NOTE lint level defined here
|
||||||
|
mod bad {
|
||||||
|
fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name
|
||||||
|
|
||||||
|
static bad: int = 1; //~ ERROR static constant `bad` should have an uppercase name
|
||||||
|
}
|
||||||
|
|
||||||
|
mod warn {
|
||||||
|
#![warn(bad_style)]
|
||||||
|
//~^ NOTE lint level defined here
|
||||||
|
|
||||||
|
fn CamelCase() {} //~ WARN function `CamelCase` should have a snake case name
|
||||||
|
|
||||||
|
struct snake_case; //~ WARN type `snake_case` should have a camel case name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:lint_group_plugin_test.rs
|
||||||
|
// ignore-stage1
|
||||||
|
// ignore-pretty
|
||||||
|
|
||||||
|
#![feature(phase)]
|
||||||
|
|
||||||
|
#[phase(plugin)]
|
||||||
|
extern crate lint_group_plugin_test;
|
||||||
|
|
||||||
|
fn lintme() { } //~ WARNING item is named 'lintme'
|
||||||
|
fn pleaselintme() { } //~ WARNING item is named 'pleaselintme'
|
||||||
|
|
||||||
|
#[allow(lint_me)]
|
||||||
|
pub fn main() {
|
||||||
|
fn lintme() { }
|
||||||
|
|
||||||
|
fn pleaselintme() { }
|
||||||
|
}
|
Loading…
Reference in New Issue