Rollup merge of #86639 - eholk:lint-tool, r=petrochenkov

Support lint tool names in rustc command line options

When rustc is running without a lint tool such as clippy enabled, options for lints such as `clippy::foo` are meant to be ignored. This was already working for those specified by attrs, such as `#![allow(clippy::foo)]`, but this did not work for command line arguments like `-A clippy::foo`. This PR fixes that issue.

Note that we discovered this issue while discussing https://github.com/rust-lang/cargo/issues/5034.

Fixes #86628.
This commit is contained in:
Yuki Okushi 2021-07-08 10:44:29 +09:00 committed by GitHub
commit c2d3f5f772
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 123 additions and 34 deletions

View file

@ -16,7 +16,7 @@
use self::TargetLint::*;
use crate::levels::LintLevelsBuilder;
use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
@ -129,6 +129,8 @@ pub enum CheckLintNameResult<'a> {
Ok(&'a [LintId]),
/// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
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
/// message, and an optional new name (`None` if removed).
Warning(String, Option<String>),
@ -321,9 +323,17 @@ impl LintStore {
}
}
/// Checks the validity of lint names derived from the command line
pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
let db = match self.check_lint_name(lint_name, None) {
/// Checks the validity of lint names derived from the command line.
pub fn check_lint_name_cmdline(
&self,
sess: &Session,
lint_name: &str,
level: Level,
crate_attrs: &[ast::Attribute],
) {
let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
CheckLintNameResult::NoLint(suggestion) => {
@ -345,6 +355,13 @@ impl LintStore {
))),
_ => None,
},
CheckLintNameResult::NoTool => Some(struct_span_err!(
sess,
DUMMY_SP,
E0602,
"unknown lint tool: `{}`",
tool_name.unwrap()
)),
};
if let Some(mut db) = db {
@ -387,9 +404,17 @@ impl LintStore {
/// printing duplicate warnings.
pub fn check_lint_name(
&self,
sess: &Session,
lint_name: &str,
tool_name: Option<Symbol>,
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;
}
}
let complete_name = if let Some(tool_name) = tool_name {
format!("{}::{}", tool_name, lint_name)
} else {
@ -1005,3 +1030,14 @@ impl<'tcx> LayoutOf for LateContext<'tcx> {
self.tcx.layout_of(self.param_env.and(ty))
}
}
pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
match lint_name.split_once("::") {
Some((tool_name, lint_name)) => {
let tool_name = Symbol::intern(tool_name);
(Some(tool_name), lint_name)
}
None => (None, lint_name),
}
}