1
Fork 0

Unify lint tool and lint name checking

This shares a little more code between checking command line and
attribute lint specifications.
This commit is contained in:
Eric Holk 2021-07-06 17:19:20 -07:00
parent 1e0db4cfed
commit 8b4f538320
3 changed files with 73 additions and 40 deletions

View file

@ -16,7 +16,7 @@
use self::TargetLint::*; use self::TargetLint::*;
use crate::levels::LintLevelsBuilder; use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
@ -129,6 +129,8 @@ pub enum CheckLintNameResult<'a> {
Ok(&'a [LintId]), Ok(&'a [LintId]),
/// Lint doesn't exist. Potentially contains a suggestion for a correct lint name. /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
NoLint(Option<Symbol>), NoLint(Option<Symbol>),
/// The lint refers to a tool that has not been registered.
NoTool,
/// The lint is either renamed or removed. This is the warning /// The lint is either renamed or removed. This is the warning
/// message, and an optional new name (`None` if removed). /// message, and an optional new name (`None` if removed).
Warning(String, Option<String>), Warning(String, Option<String>),
@ -334,16 +336,17 @@ impl LintStore {
} }
} }
/// Checks the validity of lint names derived from the command line. Returns /// Checks the validity of lint names derived from the command line.
/// true if the lint is valid, false otherwise.
pub fn check_lint_name_cmdline( pub fn check_lint_name_cmdline(
&self, &self,
sess: &Session, sess: &Session,
lint_name: &str, lint_name: &str,
level: Option<Level>, level: Level,
) -> bool { crate_attrs: &[ast::Attribute],
) {
let (tool_name, lint_name) = parse_lint_and_tool_name(lint_name); let (tool_name, lint_name) = parse_lint_and_tool_name(lint_name);
let db = match self.check_lint_name(lint_name, tool_name) {
let db = match self.check_lint_and_tool_name(sess, tool_name, lint_name, crate_attrs) {
CheckLintNameResult::Ok(_) => None, CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)), CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
CheckLintNameResult::NoLint(suggestion) => { CheckLintNameResult::NoLint(suggestion) => {
@ -365,6 +368,13 @@ impl LintStore {
))), ))),
_ => None, _ => None,
}, },
CheckLintNameResult::NoTool => Some(struct_span_err!(
sess,
DUMMY_SP,
E0602,
"unknown lint tool: `{}`",
tool_name.unwrap()
)),
}; };
if let Some(mut db) = db { if let Some(mut db) = db {
@ -398,6 +408,22 @@ impl LintStore {
} }
} }
pub fn check_lint_and_tool_name(
&self,
sess: &Session,
tool_name: Option<Symbol>,
lint_name: &str,
crate_attrs: &[ast::Attribute],
) -> CheckLintNameResult<'_> {
if let Some(tool_name) = tool_name {
if !is_known_lint_tool(tool_name, sess, crate_attrs) {
return CheckLintNameResult::NoTool;
}
}
self.check_lint_name(lint_name, tool_name)
}
/// Checks the name of a lint for its existence, and whether it was /// Checks the name of a lint for its existence, and whether it was
/// renamed or removed. Generates a DiagnosticBuilder containing a /// renamed or removed. Generates a DiagnosticBuilder containing a
/// warning for renamed and removed lints. This is over both lint /// warning for renamed and removed lints. This is over both lint
@ -1028,7 +1054,11 @@ impl<'tcx> LayoutOf for LateContext<'tcx> {
pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) { pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
match lint_name.split_once("::") { match lint_name.split_once("::") {
Some((tool_name, lint_name)) => (Some(Symbol::intern(tool_name)), lint_name), Some((tool_name, lint_name)) => {
let tool_name = Symbol::intern(tool_name);
(Some(tool_name), lint_name)
}
None => (None, lint_name), None => (None, lint_name),
} }
} }

View file

@ -88,7 +88,7 @@ impl<'s> LintLevelsBuilder<'s> {
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
for &(ref lint_name, level) in &sess.opts.lint_opts { for &(ref lint_name, level) in &sess.opts.lint_opts {
store.check_lint_name_cmdline(sess, &lint_name, level); store.check_lint_name_cmdline(sess, &lint_name, level, self.crate_attrs);
let orig_level = level; let orig_level = level;
// If the cap is less than this specified level, e.g., if we've got // If the cap is less than this specified level, e.g., if we've got
@ -110,7 +110,7 @@ impl<'s> LintLevelsBuilder<'s> {
} }
for lint_name in &sess.opts.force_warns { for lint_name in &sess.opts.force_warns {
store.check_lint_name_cmdline(sess, lint_name, Level::ForceWarn); store.check_lint_name_cmdline(sess, lint_name, Level::ForceWarn, self.crate_attrs);
let lints = store let lints = store
.find_lints(lint_name) .find_lints(lint_name)
.unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids")); .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
@ -321,33 +321,15 @@ impl<'s> LintLevelsBuilder<'s> {
continue; continue;
} }
}; };
let tool_name = if meta_item.path.segments.len() > 1 { let tool_ident = if meta_item.path.segments.len() > 1 {
let tool_ident = meta_item.path.segments[0].ident; Some(meta_item.path.segments.remove(0).ident)
if !is_known_lint_tool(tool_ident.name, sess, &self.crate_attrs) {
let mut err = struct_span_err!(
sess,
tool_ident.span,
E0710,
"unknown tool name `{}` found in scoped lint: `{}`",
tool_ident.name,
pprust::path_to_string(&meta_item.path),
);
if sess.is_nightly_build() {
err.help(&format!(
"add `#![register_tool({})]` to the crate root",
tool_ident.name
));
}
err.emit();
continue;
}
Some(meta_item.path.segments.remove(0).ident.name)
} else { } else {
None None
}; };
let tool_name = tool_ident.map(|ident| ident.name);
let name = pprust::path_to_string(&meta_item.path); let name = pprust::path_to_string(&meta_item.path);
let lint_result = store.check_lint_name(&name, tool_name); let lint_result =
store.check_lint_and_tool_name(sess, tool_name, &name, self.crate_attrs);
match &lint_result { match &lint_result {
CheckLintNameResult::Ok(ids) => { CheckLintNameResult::Ok(ids) => {
let src = LintLevelSource::Node( let src = LintLevelSource::Node(
@ -364,7 +346,8 @@ impl<'s> LintLevelsBuilder<'s> {
CheckLintNameResult::Tool(result) => { CheckLintNameResult::Tool(result) => {
match *result { match *result {
Ok(ids) => { Ok(ids) => {
let complete_name = &format!("{}::{}", tool_name.unwrap(), name); let complete_name =
&format!("{}::{}", tool_ident.unwrap().name, name);
let src = LintLevelSource::Node( let src = LintLevelSource::Node(
Symbol::intern(complete_name), Symbol::intern(complete_name),
sp, sp,
@ -419,6 +402,26 @@ impl<'s> LintLevelsBuilder<'s> {
} }
} }
&CheckLintNameResult::NoTool => {
let mut err = struct_span_err!(
sess,
tool_ident.map_or(DUMMY_SP, |ident| ident.span),
E0710,
"unknown tool name `{}` found in scoped lint: `{}::{}`",
tool_name.unwrap(),
tool_name.unwrap(),
pprust::path_to_string(&meta_item.path),
);
if sess.is_nightly_build() {
err.help(&format!(
"add `#![register_tool({})]` to the crate root",
tool_name.unwrap()
));
}
err.emit();
continue;
}
_ if !self.warn_about_weird_lints => {} _ if !self.warn_about_weird_lints => {}
CheckLintNameResult::Warning(msg, renamed) => { CheckLintNameResult::Warning(msg, renamed) => {
@ -450,8 +453,8 @@ impl<'s> LintLevelsBuilder<'s> {
let (level, src) = let (level, src) =
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| { struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
let name = if let Some(tool_name) = tool_name { let name = if let Some(tool_ident) = tool_ident {
format!("{}::{}", tool_name, name) format!("{}::{}", tool_ident.name, name)
} else { } else {
name.to_string() name.to_string()
}; };
@ -578,7 +581,7 @@ impl<'s> LintLevelsBuilder<'s> {
} }
} }
fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool { pub fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool {
if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) { if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) {
return true; return true;
} }

View file

@ -1,10 +1,10 @@
error[E0602]: unknown lint: `unknown_tool::foo` error[E0602]: unknown lint tool: `unknown_tool`
| |
= note: requested on the command line with `-A unknown_tool::foo` = note: requested on the command line with `-A foo`
error[E0602]: unknown lint: `unknown_tool::foo` error[E0602]: unknown lint tool: `unknown_tool`
| |
= note: requested on the command line with `-A unknown_tool::foo` = note: requested on the command line with `-A foo`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors