Skip to content

Commit b7e4402

Browse files
committed
Auto merge of #53762 - flip1995:tool_lints, r=Manishearth
Backwards compatibility for tool/clippy lints cc #44690 cc rust-lang/rust-clippy#2977 (comment) This is the next step towards `tool_lints`. This makes Clippy lints still work without scoping, but will warn and suggest the new scoped name. This warning will only appear if the code is checked with Clippy itself. There is still an issue with using the old lint name in inner attributes. For inner attributes the warning gets emitted twice. I'm currently not really sure why this happens, but will try to fix this ASAP. r? @Manishearth
2 parents 06a59da + 9cbe518 commit b7e4402

File tree

11 files changed

+231
-51
lines changed

11 files changed

+231
-51
lines changed

Diff for: src/librustc/lint/context.rs

+81-19
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@ pub struct LintStore {
6767
/// Lints indexed by name.
6868
by_name: FxHashMap<String, TargetLint>,
6969

70-
/// Map of registered lint groups to what lints they expand to. The bool
71-
/// is true if the lint group was added by a plugin.
72-
lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool)>,
70+
/// Map of registered lint groups to what lints they expand to. The first
71+
/// bool is true if the lint group was added by a plugin. The optional string
72+
/// is used to store the new names of deprecated lint group names.
73+
lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool, Option<&'static str>)>,
7374

7475
/// Extra info for future incompatibility lints, describing the
7576
/// issue or RFC that caused the incompatibility.
@@ -138,7 +139,7 @@ pub enum CheckLintNameResult<'a> {
138139
/// compiled with the tool and therefore the lint was never
139140
/// added to the `LintStore`. Otherwise the `LintId` will be
140141
/// returned as if it where a rustc lint.
141-
Tool(Option<&'a [LintId]>),
142+
Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>),
142143
}
143144

144145
impl LintStore {
@@ -221,7 +222,7 @@ impl LintStore {
221222
let lints = lints.iter().filter(|f| f.edition == Some(*edition)).map(|f| f.id)
222223
.collect::<Vec<_>>();
223224
if !lints.is_empty() {
224-
self.register_group(sess, false, edition.lint_name(), lints)
225+
self.register_group(sess, false, edition.lint_name(), None, lints)
225226
}
226227
}
227228

@@ -231,19 +232,35 @@ impl LintStore {
231232
self.future_incompatible.insert(lint.id, lint);
232233
}
233234

234-
self.register_group(sess, false, "future_incompatible", future_incompatible);
235-
236-
235+
self.register_group(
236+
sess,
237+
false,
238+
"future_incompatible",
239+
None,
240+
future_incompatible,
241+
);
237242
}
238243

239244
pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
240245
self.future_incompatible.get(&id)
241246
}
242247

243-
pub fn register_group(&mut self, sess: Option<&Session>,
244-
from_plugin: bool, name: &'static str,
245-
to: Vec<LintId>) {
246-
let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
248+
pub fn register_group(
249+
&mut self,
250+
sess: Option<&Session>,
251+
from_plugin: bool,
252+
name: &'static str,
253+
deprecated_name: Option<&'static str>,
254+
to: Vec<LintId>,
255+
) {
256+
let new = self
257+
.lint_groups
258+
.insert(name, (to, from_plugin, None))
259+
.is_none();
260+
if let Some(deprecated) = deprecated_name {
261+
self.lint_groups
262+
.insert(deprecated, (vec![], from_plugin, Some(name)));
263+
}
247264

248265
if !new {
249266
let msg = format!("duplicate specification of lint group {}", name);
@@ -336,34 +353,79 @@ impl LintStore {
336353
} else {
337354
lint_name.to_string()
338355
};
356+
// If the lint was scoped with `tool::` check if the tool lint exists
339357
if let Some(_) = tool_name {
340358
match self.by_name.get(&complete_name) {
341359
None => match self.lint_groups.get(&*complete_name) {
342-
None => return CheckLintNameResult::Tool(None),
343-
Some(ids) => return CheckLintNameResult::Tool(Some(&ids.0)),
360+
None => return CheckLintNameResult::Tool(Err((None, String::new()))),
361+
Some(ids) => return CheckLintNameResult::Tool(Ok(&ids.0)),
344362
},
345-
Some(&Id(ref id)) => return CheckLintNameResult::Tool(Some(slice::from_ref(id))),
363+
Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
346364
// If the lint was registered as removed or renamed by the lint tool, we don't need
347365
// to treat tool_lints and rustc lints different and can use the code below.
348366
_ => {}
349367
}
350368
}
351369
match self.by_name.get(&complete_name) {
352370
Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
353-
format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
371+
format!(
372+
"lint `{}` has been renamed to `{}`",
373+
complete_name, new_name
374+
),
354375
Some(new_name.to_owned()),
355376
),
356377
Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
357-
format!("lint `{}` has been removed: `{}`", lint_name, reason),
378+
format!("lint `{}` has been removed: `{}`", complete_name, reason),
358379
None,
359380
),
360381
None => match self.lint_groups.get(&*complete_name) {
361-
None => CheckLintNameResult::NoLint,
362-
Some(ids) => CheckLintNameResult::Ok(&ids.0),
382+
// If neither the lint, nor the lint group exists check if there is a `clippy::`
383+
// variant of this lint
384+
None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
385+
Some(ids) => {
386+
// Check if the lint group name is deprecated
387+
if let Some(new_name) = ids.2 {
388+
let lint_ids = self.lint_groups.get(new_name).unwrap();
389+
return CheckLintNameResult::Tool(Err((
390+
Some(&lint_ids.0),
391+
new_name.to_string(),
392+
)));
393+
}
394+
CheckLintNameResult::Ok(&ids.0)
395+
}
363396
},
364397
Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
365398
}
366399
}
400+
401+
fn check_tool_name_for_backwards_compat(
402+
&self,
403+
lint_name: &str,
404+
tool_name: &str,
405+
) -> CheckLintNameResult {
406+
let complete_name = format!("{}::{}", tool_name, lint_name);
407+
match self.by_name.get(&complete_name) {
408+
None => match self.lint_groups.get(&*complete_name) {
409+
// Now we are sure, that this lint exists nowhere
410+
None => CheckLintNameResult::NoLint,
411+
Some(ids) => {
412+
// Reaching this would be weird, but lets cover this case anyway
413+
if let Some(new_name) = ids.2 {
414+
let lint_ids = self.lint_groups.get(new_name).unwrap();
415+
return CheckLintNameResult::Tool(Err((
416+
Some(&lint_ids.0),
417+
new_name.to_string(),
418+
)));
419+
}
420+
CheckLintNameResult::Tool(Err((Some(&ids.0), complete_name)))
421+
}
422+
},
423+
Some(&Id(ref id)) => {
424+
CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
425+
}
426+
_ => CheckLintNameResult::NoLint,
427+
}
428+
}
367429
}
368430

369431
/// Context for lint checking after type checking.

Diff for: src/librustc/lint/levels.rs

+52-16
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,13 @@ impl<'a> LintLevelsBuilder<'a> {
231231
let gate_feature = !self.sess.features_untracked().tool_lints;
232232
let known_tool = attr::is_known_lint_tool(lint_tool);
233233
if gate_feature {
234-
feature_gate::emit_feature_err(&sess.parse_sess,
235-
"tool_lints",
236-
word.span,
237-
feature_gate::GateIssue::Language,
238-
&format!("scoped lint `{}` is experimental",
239-
word.ident));
234+
feature_gate::emit_feature_err(
235+
&sess.parse_sess,
236+
"tool_lints",
237+
word.span,
238+
feature_gate::GateIssue::Language,
239+
&format!("scoped lint `{}` is experimental", word.ident),
240+
);
240241
}
241242
if !known_tool {
242243
span_err!(
@@ -249,7 +250,7 @@ impl<'a> LintLevelsBuilder<'a> {
249250
}
250251

251252
if gate_feature || !known_tool {
252-
continue
253+
continue;
253254
}
254255

255256
Some(lint_tool.as_str())
@@ -266,17 +267,52 @@ impl<'a> LintLevelsBuilder<'a> {
266267
}
267268

268269
CheckLintNameResult::Tool(result) => {
269-
if let Some(ids) = result {
270-
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
271-
let src = LintSource::Node(Symbol::intern(complete_name), li.span);
272-
for id in ids {
273-
specs.insert(*id, (level, src));
270+
match result {
271+
Ok(ids) => {
272+
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
273+
let src = LintSource::Node(Symbol::intern(complete_name), li.span);
274+
for id in ids {
275+
specs.insert(*id, (level, src));
276+
}
277+
}
278+
Err((Some(ids), new_lint_name)) => {
279+
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
280+
let (lvl, src) =
281+
self.sets
282+
.get_lint_level(lint, self.cur, Some(&specs), &sess);
283+
let msg = format!(
284+
"lint name `{}` is deprecated \
285+
and may not have an effect in the future. \
286+
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
287+
name
288+
);
289+
let mut err = lint::struct_lint_level(
290+
self.sess,
291+
lint,
292+
lvl,
293+
src,
294+
Some(li.span.into()),
295+
&msg,
296+
);
297+
err.span_suggestion_with_applicability(
298+
li.span,
299+
"change it to",
300+
new_lint_name.to_string(),
301+
Applicability::MachineApplicable,
302+
).emit();
303+
304+
let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span);
305+
for id in ids {
306+
specs.insert(*id, (level, src));
307+
}
308+
}
309+
Err((None, _)) => {
310+
// If Tool(Err(None, _)) is returned, then either the lint does not
311+
// exist in the tool or the code was not compiled with the tool and
312+
// therefore the lint was never added to the `LintStore`. To detect
313+
// this is the responsibility of the lint tool.
274314
}
275315
}
276-
// If Tool(None) is returned, then either the lint does not exist in the
277-
// tool or the code was not compiled with the tool and therefore the lint
278-
// was never added to the `LintStore`. To detect this is the responsibility
279-
// of the lint tool.
280316
}
281317

282318
_ if !self.warn_about_weird_lints => {}

Diff for: src/librustc_driver/driver.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -924,8 +924,8 @@ where
924924
ls.register_late_pass(Some(sess), true, pass);
925925
}
926926

927-
for (name, to) in lint_groups {
928-
ls.register_group(Some(sess), true, name, to);
927+
for (name, (to, deprecated_name)) in lint_groups {
928+
ls.register_group(Some(sess), true, name, deprecated_name, to);
929929
}
930930

931931
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;

Diff for: src/librustc_lint/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
105105

106106
macro_rules! add_lint_group {
107107
($sess:ident, $name:expr, $($lint:ident),*) => (
108-
store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
108+
store.register_group($sess, false, $name, None, vec![$(LintId::of($lint)),*]);
109109
)
110110
}
111111

Diff for: src/librustc_plugin/registry.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub struct Registry<'a> {
5353
pub late_lint_passes: Vec<LateLintPassObject>,
5454

5555
#[doc(hidden)]
56-
pub lint_groups: FxHashMap<&'static str, Vec<LintId>>,
56+
pub lint_groups: FxHashMap<&'static str, (Vec<LintId>, Option<&'static str>)>,
5757

5858
#[doc(hidden)]
5959
pub llvm_passes: Vec<String>,
@@ -170,8 +170,15 @@ impl<'a> Registry<'a> {
170170
self.late_lint_passes.push(lint_pass);
171171
}
172172
/// Register a lint group.
173-
pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) {
174-
self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect());
173+
pub fn register_lint_group(
174+
&mut self,
175+
name: &'static str,
176+
deprecated_name: Option<&'static str>,
177+
to: Vec<&'static Lint>
178+
) {
179+
self.lint_groups.insert(name,
180+
(to.into_iter().map(|x| LintId::of(x)).collect(),
181+
deprecated_name));
175182
}
176183

177184
/// Register an LLVM pass.

Diff for: src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
4949
#[plugin_registrar]
5050
pub fn plugin_registrar(reg: &mut Registry) {
5151
reg.register_late_lint_pass(box Pass);
52-
reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
52+
reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]);
5353
}

Diff for: src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
4949
#[plugin_registrar]
5050
pub fn plugin_registrar(reg: &mut Registry) {
5151
reg.register_late_lint_pass(box Pass);
52-
reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
52+
reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]);
5353
}

Diff for: src/test/ui-fulldeps/auxiliary/lint_tool_test.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
2525
use rustc_plugin::Registry;
2626
use syntax::ast;
2727
declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
28+
declare_tool_lint!(pub clippy::TEST_GROUP, Warn, "Warn about other stuff");
2829

2930
struct Pass;
3031

3132
impl LintPass for Pass {
3233
fn get_lints(&self) -> LintArray {
33-
lint_array!(TEST_LINT)
34+
lint_array!(TEST_LINT, TEST_GROUP)
3435
}
3536
}
3637

@@ -39,10 +40,14 @@ impl EarlyLintPass for Pass {
3940
if it.ident.name == "lintme" {
4041
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
4142
}
43+
if it.ident.name == "lintmetoo" {
44+
cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'");
45+
}
4246
}
4347
}
4448

4549
#[plugin_registrar]
4650
pub fn plugin_registrar(reg: &mut Registry) {
4751
reg.register_early_lint_pass(box Pass);
52+
reg.register_lint_group("clippy::group", Some("clippy_group"), vec![TEST_LINT, TEST_GROUP]);
4853
}

Diff for: src/test/ui-fulldeps/lint_tool_test.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,33 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// run-pass
1211
// aux-build:lint_tool_test.rs
1312
// ignore-stage1
13+
// compile-flags: --cfg foo
1414
#![feature(plugin)]
1515
#![feature(tool_lints)]
1616
#![plugin(lint_tool_test)]
1717
#![allow(dead_code)]
18+
#![cfg_attr(foo, warn(test_lint))]
19+
//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
20+
//~^^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
21+
#![deny(clippy_group)]
22+
//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
1823

19-
fn lintme() { } //~ WARNING item is named 'lintme'
24+
fn lintme() { } //~ ERROR item is named 'lintme'
25+
26+
#[allow(clippy::group)]
27+
fn lintmetoo() {}
2028

2129
#[allow(clippy::test_lint)]
2230
pub fn main() {
2331
fn lintme() { }
32+
fn lintmetoo() { } //~ ERROR item is named 'lintmetoo'
33+
}
34+
35+
#[allow(test_group)]
36+
//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
37+
#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
38+
fn hello() {
39+
fn lintmetoo() { }
2440
}

0 commit comments

Comments
 (0)