Skip to content

Commit 5833e4d

Browse files
committed
Auto merge of #3810 - phansch:refactor/extract_module, r=flip1995
Extract diagnostics module and document some functions This moves the lint building functions from `utils/mod.rs` to their own `utils/diagnostics.rs` file. Also adds documentation for three of them.
2 parents 1ce961f + 7d883cd commit 5833e4d

File tree

2 files changed

+208
-143
lines changed

2 files changed

+208
-143
lines changed

clippy_lints/src/utils/diagnostics.rs

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
//! Clippy wrappers around rustc's diagnostic functions.
2+
3+
use crate::reexport::*;
4+
use rustc::lint::{LateContext, Lint, LintContext};
5+
use rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart, SuggestionStyle};
6+
use std::env;
7+
use syntax::errors::DiagnosticBuilder;
8+
use syntax::source_map::Span;
9+
10+
/// Wrapper around `DiagnosticBuilder` that adds a link to Clippy documentation for the emitted lint
11+
pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>);
12+
13+
impl<'a> Drop for DiagnosticWrapper<'a> {
14+
fn drop(&mut self) {
15+
self.0.emit();
16+
}
17+
}
18+
19+
impl<'a> DiagnosticWrapper<'a> {
20+
fn docs_link(&mut self, lint: &'static Lint) {
21+
if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
22+
self.0.help(&format!(
23+
"for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
24+
&option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
25+
// extract just major + minor version and ignore patch versions
26+
format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
27+
}),
28+
lint.name_lower().replacen("clippy::", "", 1)
29+
));
30+
}
31+
}
32+
}
33+
34+
/// Emit a basic lint message with a `msg` and a `span`.
35+
///
36+
/// This is the most primitive of our lint emission methods and can
37+
/// be a good way to get a new lint started.
38+
///
39+
/// Usually it's nicer to provide more context for lint messages.
40+
/// Be sure the output is understandable when you use this method.
41+
///
42+
/// # Example
43+
///
44+
/// ```ignore
45+
/// error: usage of mem::forget on Drop type
46+
/// --> $DIR/mem_forget.rs:17:5
47+
/// |
48+
/// 17 | std::mem::forget(seven);
49+
/// | ^^^^^^^^^^^^^^^^^^^^^^^
50+
/// ```
51+
pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) {
52+
DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)).docs_link(lint);
53+
}
54+
55+
/// Same as `span_lint` but with an extra `help` message.
56+
///
57+
/// Use this if you want to provide some general help but
58+
/// can't provide a specific machine applicable suggestion.
59+
///
60+
/// The `help` message is not attached to any `Span`.
61+
///
62+
/// # Example
63+
///
64+
/// ```ignore
65+
/// error: constant division of 0.0 with 0.0 will always result in NaN
66+
/// --> $DIR/zero_div_zero.rs:6:25
67+
/// |
68+
/// 6 | let other_f64_nan = 0.0f64 / 0.0;
69+
/// | ^^^^^^^^^^^^
70+
/// |
71+
/// = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
72+
/// ```
73+
pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
74+
cx: &'a T,
75+
lint: &'static Lint,
76+
span: Span,
77+
msg: &str,
78+
help: &str,
79+
) {
80+
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
81+
db.0.help(help);
82+
db.docs_link(lint);
83+
}
84+
85+
/// Like `span_lint` but with a `note` section instead of a `help` message.
86+
///
87+
/// The `note` message is presented separately from the main lint message
88+
/// and is attached to a specific span:
89+
///
90+
/// # Example
91+
///
92+
/// ```ignore
93+
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
94+
/// --> $DIR/drop_forget_ref.rs:10:5
95+
/// |
96+
/// 10 | forget(&SomeStruct);
97+
/// | ^^^^^^^^^^^^^^^^^^^
98+
/// |
99+
/// = note: `-D clippy::forget-ref` implied by `-D warnings`
100+
/// note: argument has type &SomeStruct
101+
/// --> $DIR/drop_forget_ref.rs:10:12
102+
/// |
103+
/// 10 | forget(&SomeStruct);
104+
/// | ^^^^^^^^^^^
105+
/// ```
106+
pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
107+
cx: &'a T,
108+
lint: &'static Lint,
109+
span: Span,
110+
msg: &str,
111+
note_span: Span,
112+
note: &str,
113+
) {
114+
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
115+
if note_span == span {
116+
db.0.note(note);
117+
} else {
118+
db.0.span_note(note_span, note);
119+
}
120+
db.docs_link(lint);
121+
}
122+
123+
pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(
124+
cx: &'a T,
125+
lint: &'static Lint,
126+
sp: Span,
127+
msg: &str,
128+
f: F,
129+
) where
130+
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
131+
{
132+
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
133+
f(&mut db.0);
134+
db.docs_link(lint);
135+
}
136+
137+
pub fn span_lint_node(cx: &LateContext<'_, '_>, lint: &'static Lint, node: NodeId, sp: Span, msg: &str) {
138+
DiagnosticWrapper(cx.tcx.struct_span_lint_node(lint, node, sp, msg)).docs_link(lint);
139+
}
140+
141+
pub fn span_lint_node_and_then(
142+
cx: &LateContext<'_, '_>,
143+
lint: &'static Lint,
144+
node: NodeId,
145+
sp: Span,
146+
msg: &str,
147+
f: impl FnOnce(&mut DiagnosticBuilder<'_>),
148+
) {
149+
let mut db = DiagnosticWrapper(cx.tcx.struct_span_lint_node(lint, node, sp, msg));
150+
f(&mut db.0);
151+
db.docs_link(lint);
152+
}
153+
154+
/// Add a span lint with a suggestion on how to fix it.
155+
///
156+
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
157+
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
158+
/// 2)"`.
159+
///
160+
/// ```ignore
161+
/// error: This `.fold` can be more succinctly expressed as `.any`
162+
/// --> $DIR/methods.rs:390:13
163+
/// |
164+
/// 390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);
165+
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
166+
/// |
167+
/// = note: `-D fold-any` implied by `-D warnings`
168+
/// ```
169+
pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
170+
cx: &'a T,
171+
lint: &'static Lint,
172+
sp: Span,
173+
msg: &str,
174+
help: &str,
175+
sugg: String,
176+
applicability: Applicability,
177+
) {
178+
span_lint_and_then(cx, lint, sp, msg, |db| {
179+
db.span_suggestion(sp, help, sugg, applicability);
180+
});
181+
}
182+
183+
/// Create a suggestion made from several `span → replacement`.
184+
///
185+
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
186+
/// appear once per
187+
/// replacement. In human-readable format though, it only appears once before
188+
/// the whole suggestion.
189+
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
190+
where
191+
I: IntoIterator<Item = (Span, String)>,
192+
{
193+
let sugg = CodeSuggestion {
194+
substitutions: vec![Substitution {
195+
parts: sugg
196+
.into_iter()
197+
.map(|(span, snippet)| SubstitutionPart { snippet, span })
198+
.collect(),
199+
}],
200+
msg: help_msg,
201+
style: SuggestionStyle::ShowCode,
202+
applicability: Applicability::Unspecified,
203+
};
204+
db.suggestions.push(sugg);
205+
}

clippy_lints/src/utils/mod.rs

Lines changed: 3 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@ use rustc::ty::{
1717
Binder, Ty, TyCtxt,
1818
};
1919
use rustc_data_structures::sync::Lrc;
20-
use rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart, SuggestionStyle};
20+
use rustc_errors::Applicability;
2121
use std::borrow::Cow;
22-
use std::env;
2322
use std::mem;
2423
use std::str::FromStr;
2524
use syntax::ast::{self, LitKind};
2625
use syntax::attr;
27-
use syntax::errors::DiagnosticBuilder;
2826
use syntax::source_map::{Span, DUMMY_SP};
2927
use syntax::symbol;
3028
use syntax::symbol::{keywords, Symbol};
@@ -35,13 +33,15 @@ pub mod author;
3533
pub mod comparisons;
3634
pub mod conf;
3735
pub mod constants;
36+
mod diagnostics;
3837
mod hir_utils;
3938
pub mod inspector;
4039
pub mod internal_lints;
4140
pub mod paths;
4241
pub mod ptr;
4342
pub mod sugg;
4443
pub mod usage;
44+
pub use self::diagnostics::*;
4545
pub use self::hir_utils::{SpanlessEq, SpanlessHash};
4646

4747
pub mod higher;
@@ -611,146 +611,6 @@ pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeI
611611
}
612612
}
613613

614-
pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>);
615-
616-
impl<'a> Drop for DiagnosticWrapper<'a> {
617-
fn drop(&mut self) {
618-
self.0.emit();
619-
}
620-
}
621-
622-
impl<'a> DiagnosticWrapper<'a> {
623-
fn docs_link(&mut self, lint: &'static Lint) {
624-
if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
625-
self.0.help(&format!(
626-
"for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
627-
&option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
628-
// extract just major + minor version and ignore patch versions
629-
format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
630-
}),
631-
lint.name_lower().replacen("clippy::", "", 1)
632-
));
633-
}
634-
}
635-
}
636-
637-
pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) {
638-
DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)).docs_link(lint);
639-
}
640-
641-
pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
642-
cx: &'a T,
643-
lint: &'static Lint,
644-
span: Span,
645-
msg: &str,
646-
help: &str,
647-
) {
648-
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
649-
db.0.help(help);
650-
db.docs_link(lint);
651-
}
652-
653-
pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
654-
cx: &'a T,
655-
lint: &'static Lint,
656-
span: Span,
657-
msg: &str,
658-
note_span: Span,
659-
note: &str,
660-
) {
661-
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
662-
if note_span == span {
663-
db.0.note(note);
664-
} else {
665-
db.0.span_note(note_span, note);
666-
}
667-
db.docs_link(lint);
668-
}
669-
670-
pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(
671-
cx: &'a T,
672-
lint: &'static Lint,
673-
sp: Span,
674-
msg: &str,
675-
f: F,
676-
) where
677-
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
678-
{
679-
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
680-
f(&mut db.0);
681-
db.docs_link(lint);
682-
}
683-
684-
pub fn span_lint_node(cx: &LateContext<'_, '_>, lint: &'static Lint, node: NodeId, sp: Span, msg: &str) {
685-
DiagnosticWrapper(cx.tcx.struct_span_lint_node(lint, node, sp, msg)).docs_link(lint);
686-
}
687-
688-
pub fn span_lint_node_and_then(
689-
cx: &LateContext<'_, '_>,
690-
lint: &'static Lint,
691-
node: NodeId,
692-
sp: Span,
693-
msg: &str,
694-
f: impl FnOnce(&mut DiagnosticBuilder<'_>),
695-
) {
696-
let mut db = DiagnosticWrapper(cx.tcx.struct_span_lint_node(lint, node, sp, msg));
697-
f(&mut db.0);
698-
db.docs_link(lint);
699-
}
700-
701-
/// Add a span lint with a suggestion on how to fix it.
702-
///
703-
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
704-
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
705-
/// 2)"`.
706-
///
707-
/// ```ignore
708-
/// error: This `.fold` can be more succinctly expressed as `.any`
709-
/// --> $DIR/methods.rs:390:13
710-
/// |
711-
/// 390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);
712-
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
713-
/// |
714-
/// = note: `-D fold-any` implied by `-D warnings`
715-
/// ```
716-
pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
717-
cx: &'a T,
718-
lint: &'static Lint,
719-
sp: Span,
720-
msg: &str,
721-
help: &str,
722-
sugg: String,
723-
applicability: Applicability,
724-
) {
725-
span_lint_and_then(cx, lint, sp, msg, |db| {
726-
db.span_suggestion(sp, help, sugg, applicability);
727-
});
728-
}
729-
730-
/// Create a suggestion made from several `span → replacement`.
731-
///
732-
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
733-
/// appear once per
734-
/// replacement. In human-readable format though, it only appears once before
735-
/// the whole suggestion.
736-
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
737-
where
738-
I: IntoIterator<Item = (Span, String)>,
739-
{
740-
let sugg = CodeSuggestion {
741-
substitutions: vec![Substitution {
742-
parts: sugg
743-
.into_iter()
744-
.map(|(span, snippet)| SubstitutionPart { snippet, span })
745-
.collect(),
746-
}],
747-
msg: help_msg,
748-
style: SuggestionStyle::ShowCode,
749-
applicability: Applicability::Unspecified,
750-
};
751-
db.suggestions.push(sugg);
752-
}
753-
754614
/// Return the base type for HIR references and pointers.
755615
pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty {
756616
match ty.node {

0 commit comments

Comments
 (0)