Skip to content

Implement lint plugins #15024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jun 24, 2014
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
75bfeda
Move lint.rs out of middle
kmcallister Jun 1, 2014
3144614
Move lint infrastructure and individual lints into separate files
kmcallister Jun 1, 2014
5d4c96a
Rename lint::Lint to lint::LintId
kmcallister Jun 1, 2014
69b6bc5
Convert lints to a trait-based infrastructure
kmcallister Jun 2, 2014
442fbc4
Replace enum LintId with an extensible alternative
kmcallister Jun 4, 2014
819f76c
Store the registered lints in the Session
kmcallister Jun 10, 2014
c7af606
Clean up and document the public lint API
kmcallister Jun 6, 2014
c1898b9
Stop using Default for initializing builtin lints
kmcallister Jun 13, 2014
609552e
Run lint passes using the Option dance instead of RefCells
kmcallister Jun 13, 2014
21e7b93
Use names in Lint structs in an ASCII-case-insensitive way
kmcallister Jun 13, 2014
b5542f7
Convert builtin lints to uppercase names for style consistency
kmcallister Jun 13, 2014
a813a37
Rework lint attr parsing and use it in middle::dead
kmcallister Jun 13, 2014
6fede93
Make the crate and its exported items available in the lint context
kmcallister Jun 17, 2014
ba1c0c4
Drop the ExportedItems argument from LintPass::check_crate
kmcallister Jun 18, 2014
c747626
Reindent function call continuations, and other style fixes
kmcallister Jun 18, 2014
e67e6e6
List builtin lints one per line for better diffs
kmcallister Jun 18, 2014
51d438e
Incorporate upstream changes to old lint code
kmcallister Jun 18, 2014
2f274d1
Implement lint plugins
kmcallister Jun 19, 2014
7dc724b
Test lint plugins
kmcallister Jun 18, 2014
7e694e7
More upstream lint changes
kmcallister Jun 24, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Replace enum LintId with an extensible alternative
  • Loading branch information
Keegan McAllister committed Jun 24, 2014
commit 442fbc473e10d1efe3359b19f342d11097259fc4
38 changes: 13 additions & 25 deletions src/librustc/driver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ pub struct Options {
pub gc: bool,
pub optimize: OptLevel,
pub debuginfo: DebugInfoLevel,
pub lint_opts: Vec<(lint::LintId, lint::Level)> ,
pub lint_opts: Vec<(String, lint::Level)>,
pub describe_lints: bool,
pub output_types: Vec<back::link::OutputType> ,
// This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use
Expand Down Expand Up @@ -104,6 +105,7 @@ pub fn basic_options() -> Options {
optimize: No,
debuginfo: NoDebugInfo,
lint_opts: Vec::new(),
describe_lints: false,
output_types: Vec::new(),
addl_lib_search_paths: RefCell::new(HashSet::new()),
maybe_sysroot: None,
Expand Down Expand Up @@ -585,30 +587,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let no_trans = matches.opt_present("no-trans");
let no_analysis = matches.opt_present("no-analysis");

let lint_levels = [lint::Allow, lint::Warn,
lint::Deny, lint::Forbid];
let mut lint_opts = Vec::new();
let lint_dict = lint::get_lint_dict();
for level in lint_levels.iter() {
let level_name = lint::level_to_str(*level);

let level_short = level_name.slice_chars(0, 1);
let level_short = level_short.to_ascii().to_upper().into_str();
let flags = matches.opt_strs(level_short.as_slice())
.move_iter()
.collect::<Vec<_>>()
.append(matches.opt_strs(level_name).as_slice());
for lint_name in flags.iter() {
let lint_name = lint_name.replace("-", "_").into_string();
match lint_dict.find_equiv(&lint_name) {
None => {
early_error(format!("unknown {} flag: {}",
level_name,
lint_name).as_slice());
}
Some(lint) => {
lint_opts.push((lint.lint, *level));
}
let mut lint_opts = vec!();
let mut describe_lints = false;

for &level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid].iter() {
for lint_name in matches.opt_strs(level.as_str()).move_iter() {
if lint_name.as_slice() == "help" {
describe_lints = true;
} else {
lint_opts.push((lint_name.replace("-", "_").into_string(), level));
}
}
}
Expand Down Expand Up @@ -752,6 +739,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
optimize: opt_level,
debuginfo: debuginfo,
lint_opts: lint_opts,
describe_lints: describe_lints,
output_types: output_types,
addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
maybe_sysroot: sysroot_opt,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,15 +767,15 @@ pub fn collect_crate_types(session: &Session,
}
Some(ref n) if n.equiv(&("bin")) => Some(config::CrateTypeExecutable),
Some(_) => {
session.add_lint(lint::UnknownCrateType,
session.add_lint(lint::builtin::unknown_crate_type,
ast::CRATE_NODE_ID,
a.span,
"invalid `crate_type` \
value".to_string());
None
}
_ => {
session.add_lint(lint::UnknownCrateType,
session.add_lint(lint::builtin::unknown_crate_type,
ast::CRATE_NODE_ID,
a.span,
"`crate_type` requires a \
Expand Down
61 changes: 31 additions & 30 deletions src/librustc/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use lint;
use metadata;

use std::any::AnyRefExt;
use std::cmp;
use std::io;
use std::os;
use std::str;
Expand Down Expand Up @@ -50,6 +49,12 @@ fn run_compiler(args: &[String]) {
None => return
};

let sopts = config::build_session_options(&matches);
if sopts.describe_lints {
describe_lints();
return;
}

let (input, input_file_path) = match matches.free.len() {
0u => early_error("no input filename given"),
1u => {
Expand All @@ -66,7 +71,6 @@ fn run_compiler(args: &[String]) {
_ => early_error("multiple input filenames provided")
};

let sopts = config::build_session_options(&matches);
let sess = build_session(sopts, input_file_path);
let cfg = config::build_configuration(&sess);
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
Expand Down Expand Up @@ -124,7 +128,7 @@ Additional help:
config::optgroups().as_slice()));
}

fn describe_warnings() {
fn describe_lints() {
println!("
Available lint options:
-W <foo> Warn about <foo>
Expand All @@ -133,30 +137,32 @@ Available lint options:
-F <foo> Forbid <foo> (deny, and deny all overrides)
");

let lint_dict = lint::get_lint_dict();
let mut lint_dict = lint_dict.move_iter()
.map(|(k, v)| (v, k))
.collect::<Vec<(lint::LintSpec, &'static str)> >();
lint_dict.as_mut_slice().sort();
let mut builtin_specs = lint::builtin_lint_specs();
builtin_specs.sort_by(|x, y| {
match x.default_level.cmp(&y.default_level) {
Equal => x.name.cmp(&y.name),
r => r,
}
});

// FIXME: What if someone uses combining characters or East Asian fullwidth
// characters in a lint name?!?!?
let max_name_len = builtin_specs.iter()
.map(|&s| s.name.char_len())
.max().unwrap_or(0);
let padded = |x: &str| {
format!("{}{}", " ".repeat(max_name_len - x.char_len()), x)
};

let mut max_key = 0;
for &(_, name) in lint_dict.iter() {
max_key = cmp::max(name.len(), max_key);
}
fn padded(max: uint, s: &str) -> String {
format!("{}{}", " ".repeat(max - s.len()), s)
}
println!("\nAvailable lint checks:\n");
println!(" {} {:7.7s} {}",
padded(max_key, "name"), "default", "meaning");
println!(" {} {:7.7s} {}\n",
padded(max_key, "----"), "-------", "-------");
for (spec, name) in lint_dict.move_iter() {
let name = name.replace("_", "-");
println!(" {} {:7.7s} {}", padded("name"), "default", "meaning");
println!(" {} {:7.7s} {}", padded("----"), "-------", "-------");
println!("");

for spec in builtin_specs.move_iter() {
let name = spec.name.replace("_", "-");
println!(" {} {:7.7s} {}",
padded(max_key, name.as_slice()),
lint::level_to_str(spec.default),
spec.desc);
padded(name.as_slice()), spec.default_level.as_str(), spec.desc);
}
println!("");
}
Expand Down Expand Up @@ -214,12 +220,7 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
return None;
}

let lint_flags = matches.opt_strs("W").move_iter().collect::<Vec<_>>().append(
matches.opt_strs("warn").as_slice());
if lint_flags.iter().any(|x| x.as_slice() == "help") {
describe_warnings();
return None;
}
// Don't handle -W help here, because we might first load plugins.

let r = matches.opt_strs("Z");
if r.iter().any(|x| x.as_slice() == "help") {
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,17 @@ impl Session {
self.diagnostic().handler().unimpl(msg)
}
pub fn add_lint(&self,
lint: lint::LintId,
lint: &'static lint::Lint,
id: ast::NodeId,
sp: Span,
msg: String) {
let lint_id = lint::LintId::of(lint);
let mut lints = self.lints.borrow_mut();
match lints.find_mut(&id) {
Some(arr) => { arr.push((lint, sp, msg)); return; }
Some(arr) => { arr.push((lint_id, sp, msg)); return; }
None => {}
}
lints.insert(id, vec!((lint, sp, msg)));
lints.insert(id, vec!((lint_id, sp, msg)));
}
pub fn next_node_id(&self) -> ast::NodeId {
self.reserve_node_ids(1)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
directive not necessary");
}
None => {
sess.add_lint(lint::UnknownFeatures,
sess.add_lint(lint::builtin::unknown_features,
ast::CRATE_NODE_ID,
mi.span,
"unknown feature".to_string());
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ pub mod lib {
pub mod llvmdeps;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
pub use lint;
}

pub fn main() {
let args = std::os::args().iter()
.map(|x| x.to_string())
Expand Down
Loading