diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index ad3b077ec4b9..8fbfef07b86c 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -33,6 +33,7 @@ semver = "0.9.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } +bytecount = "0.6.0" [features] deny-warnings = [] diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 89a68990c87e..284953cec232 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint}; +use crate::utils::{implements_trait, is_entrypoint_fn, match_type, paths, return_ty, snippet_opt, span_lint}; +use bytecount::count; use if_chain::if_chain; use itertools::Itertools; use rustc::lint::in_external_macro; @@ -227,7 +228,7 @@ fn lint_for_missing_headers<'a, 'tcx>( } else { if_chain! { if let Some(body_id) = body_id; - if let Some(future) = get_trait_def_id(cx, &paths::FUTURE); + if let Some(future) = cx.tcx.lang_items().future_trait(); let def_id = cx.tcx.hir().body_owner_def_id(body_id); let mir = cx.tcx.optimized_mir(def_id); let ret_ty = mir.return_ty(); @@ -357,9 +358,9 @@ fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet, a match (previous.0, current.0) { (Text(previous), Text(current)) => { - let mut previous = previous.to_string(); - previous.push_str(¤t); - Ok((Text(previous.into()), previous_range)) + let text = (previous.to_string() + ¤t).into(); + let range = previous_range.start..current_range.end; + Ok((Text(text), range)) }, (previous, current) => Err(((previous, previous_range), (current, current_range))), } @@ -413,6 +414,16 @@ fn check_doc<'a, Events: Iterator, Range, Range, text: &str, span: Span) { - if text.contains("fn main() {") && !LEAVE_MAIN_PATTERNS.iter().any(|p| text.contains(p)) { - span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); + if let Some(comment) = snippet_opt(cx, span) { + if let Some(offset) = comment.find("fn main() {") { + if !LEAVE_MAIN_PATTERNS.iter().any(|p| text.contains(p)) { + let lo = span.lo() + BytePos::from_usize(offset); + let span = Span::new(lo, lo + BytePos::from_usize("fn main()".len()), span.ctxt()); + span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); + } + } } } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 10fe8f28eaba..24c0b1cb80e6 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -120,8 +120,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InherentToString { } fn show_lint(cx: &LateContext<'_, '_>, item: &ImplItem<'_>) { - let display_trait_id = - get_trait_def_id(cx, &["core", "fmt", "Display"]).expect("Failed to get trait ID of `Display`!"); + let display_trait_id = get_trait_def_id(cx, &paths::DISPLAY_TRAIT).expect("Failed to get trait ID of `Display`!"); // Get the real type of 'self' let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id); diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 65643d89df57..2c4c29913cff 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd { }; let implements_partial_ord = { - if let Some(id) = utils::get_trait_def_id(cx, &paths::PARTIAL_ORD) { + if let Some(id) = cx.tcx.lang_items().partial_ord_trait() { utils::implements_trait(cx, ty, id, &[]) } else { return; diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 96337e42b544..5ec04d965c86 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -24,6 +24,7 @@ pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "defa pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"]; +pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"]; @@ -36,7 +37,6 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; -pub const FUTURE: [&str; 3] = ["std", "future", "Future"]; pub const HASH: [&str; 2] = ["hash", "Hash"]; pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; @@ -69,7 +69,6 @@ pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; -pub const PARTIAL_ORD: [&str; 3] = ["core", "cmp", "PartialOrd"]; pub const PATH: [&str; 3] = ["std", "path", "Path"]; pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; diff --git a/tests/ui/needless_doc_main.rs b/tests/ui/needless_doc_main.rs index 813d2606153b..6f74bc69a875 100644 --- a/tests/ui/needless_doc_main.rs +++ b/tests/ui/needless_doc_main.rs @@ -8,6 +8,17 @@ /// unimplemented!(); /// } /// ``` +/// +/// This should also lint, and have correct span +/// +/// ``` +/// use std::io::Write as _; +/// +/// fn main() { +/// let x = String::new(); +/// write!(x, "Hallo"); +/// } +/// ``` fn bad_doctest() {} /// # Examples diff --git a/tests/ui/needless_doc_main.stderr b/tests/ui/needless_doc_main.stderr index 22d145aad585..414819e92a3f 100644 --- a/tests/ui/needless_doc_main.stderr +++ b/tests/ui/needless_doc_main.stderr @@ -1,10 +1,16 @@ error: needless `fn main` in doctest - --> $DIR/needless_doc_main.rs:7:4 + --> $DIR/needless_doc_main.rs:7:5 | LL | /// fn main() { - | ^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: `-D clippy::needless-doctest-main` implied by `-D warnings` -error: aborting due to previous error +error: needless `fn main` in doctest + --> $DIR/needless_doc_main.rs:17:5 + | +LL | /// fn main() { + | ^^^^^^^^^ + +error: aborting due to 2 previous errors