mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #129531 - Jarcho:clippyup, r=Manishearth
Clippy subtree update r? `@Manishearth`
This commit is contained in:
commit
89103466d7
11
Cargo.lock
11
Cargo.lock
@ -536,6 +536,7 @@ name = "clippy"
|
||||
version = "0.1.82"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
"clippy_utils",
|
||||
@ -549,6 +550,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc_tools_util",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.75",
|
||||
"tempfile",
|
||||
"termize",
|
||||
@ -563,7 +565,6 @@ name = "clippy_config"
|
||||
version = "0.1.82"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc-semver",
|
||||
"serde",
|
||||
"toml 0.7.8",
|
||||
"walkdir",
|
||||
@ -595,7 +596,6 @@ dependencies = [
|
||||
"quine-mc_cluskey",
|
||||
"regex",
|
||||
"regex-syntax 0.8.4",
|
||||
"rustc-semver",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -614,7 +614,6 @@ dependencies = [
|
||||
"arrayvec",
|
||||
"clippy_config",
|
||||
"itertools",
|
||||
"rustc-semver",
|
||||
"rustc_apfloat",
|
||||
]
|
||||
|
||||
@ -3199,12 +3198,6 @@ dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-semver"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-stable-hash"
|
||||
version = "0.1.0"
|
||||
|
@ -1,10 +1,10 @@
|
||||
[alias]
|
||||
bless = "test --config env.RUSTC_BLESS='1'"
|
||||
uitest = "test --test compile-test"
|
||||
uibless = "test --test compile-test -- -- --bless"
|
||||
bless = "test -- -- --bless"
|
||||
uibless = "bless --test compile-test"
|
||||
dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
|
||||
lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
|
||||
collect-metadata = "test --test dogfood --features internal -- collect_metadata"
|
||||
collect-metadata = "test --test compile-test --config env.COLLECT_METADATA='1'"
|
||||
|
||||
[build]
|
||||
# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
|
||||
|
1
src/tools/clippy/.github/deploy.sh
vendored
1
src/tools/clippy/.github/deploy.sh
vendored
@ -10,6 +10,7 @@ mkdir out/master/
|
||||
cp util/gh-pages/index.html out/master
|
||||
cp util/gh-pages/script.js out/master
|
||||
cp util/gh-pages/lints.json out/master
|
||||
cp util/gh-pages/style.css out/master
|
||||
|
||||
if [[ -n $TAG_NAME ]]; then
|
||||
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
|
||||
|
@ -136,11 +136,6 @@ jobs:
|
||||
- name: Test metadata collection
|
||||
run: cargo collect-metadata
|
||||
|
||||
- name: Test lint_configuration.md is up-to-date
|
||||
run: |
|
||||
echo "run \`cargo collect-metadata\` if this fails"
|
||||
git update-index --refresh
|
||||
|
||||
integration_build:
|
||||
needs: changelog
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -5914,6 +5914,7 @@ Released 2018-09-13
|
||||
[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
|
||||
[`to_string_trait_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_trait_impl
|
||||
[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
|
||||
[`too_long_first_doc_paragraph`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_long_first_doc_paragraph
|
||||
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
|
||||
[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
|
||||
[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
|
||||
|
@ -30,8 +30,11 @@ color-print = "0.3.4"
|
||||
anstream = "0.6.0"
|
||||
|
||||
[dev-dependencies]
|
||||
cargo_metadata = "0.18.1"
|
||||
ui_test = "0.25"
|
||||
regex = "1.5.5"
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
serde_json = "1.0.122"
|
||||
toml = "0.7.3"
|
||||
walkdir = "2.3"
|
||||
filetime = "0.2.9"
|
||||
@ -41,7 +44,6 @@ itertools = "0.12"
|
||||
clippy_utils = { path = "clippy_utils" }
|
||||
if_chain = "1.0"
|
||||
quote = "1.0.25"
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
syn = { version = "2.0", features = ["full"] }
|
||||
futures = "0.3"
|
||||
parking_lot = "0.12"
|
||||
|
@ -739,7 +739,7 @@ for some users. Adding a configuration is done in the following steps:
|
||||
|
||||
5. Update [Lint Configuration](../lint_configuration.md)
|
||||
|
||||
Run `cargo collect-metadata` to generate documentation changes for the book.
|
||||
Run `cargo bless --test config-metadata` to generate documentation changes for the book.
|
||||
|
||||
[`clippy_config::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_config/src/conf.rs
|
||||
[`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
This file is generated by `cargo collect-metadata`.
|
||||
This file is generated by `cargo bless --test config-metadata`.
|
||||
Please use that command to update the file and do not edit it by hand.
|
||||
-->
|
||||
|
||||
@ -199,7 +199,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used
|
||||
the list to indicate, that the configured values should be appended to the default
|
||||
configuration of Clippy. By default, any configuration will replace the default value.
|
||||
|
||||
**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]`
|
||||
**Default Value:** `["i", "j", "x", "y", "z", "w", "n"]`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the
|
||||
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
||||
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
||||
|
||||
**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]`
|
||||
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
@ -949,5 +949,3 @@ Whether to also emit warnings for unsafe blocks with metavariable expansions in
|
||||
---
|
||||
**Affected lints:**
|
||||
* [`macro_metavars_in_unsafe`](https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe)
|
||||
|
||||
|
||||
|
@ -7,7 +7,6 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.12"
|
||||
rustc-semver = "1.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
toml = "0.7.3"
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::msrvs::Msrv;
|
||||
use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename};
|
||||
use crate::ClippyConfiguration;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edit_distance::edit_distance;
|
||||
@ -218,7 +217,7 @@ macro_rules! define_Conf {
|
||||
define_Conf! {
|
||||
/// Which crates to allow absolute paths from
|
||||
#[lints(absolute_paths)]
|
||||
absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default(),
|
||||
absolute_paths_allowed_crates: Vec<String> = Vec::new(),
|
||||
/// The maximum number of segments a path can have before being linted, anything above this will
|
||||
/// be linted.
|
||||
#[lints(absolute_paths)]
|
||||
@ -280,12 +279,12 @@ define_Conf! {
|
||||
allowed_dotfiles: Vec<String> = Vec::default(),
|
||||
/// A list of crate names to allow duplicates of
|
||||
#[lints(multiple_crate_versions)]
|
||||
allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default(),
|
||||
allowed_duplicate_crates: Vec<String> = Vec::new(),
|
||||
/// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
|
||||
/// the list to indicate, that the configured values should be appended to the default
|
||||
/// configuration of Clippy. By default, any configuration will replace the default value.
|
||||
#[lints(min_ident_chars)]
|
||||
allowed_idents_below_min_chars: FxHashSet<String> =
|
||||
allowed_idents_below_min_chars: Vec<String> =
|
||||
DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(),
|
||||
/// List of prefixes to allow when determining whether an item's name ends with the module's name.
|
||||
/// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
|
||||
@ -323,7 +322,7 @@ define_Conf! {
|
||||
/// 2. Paths with any segment that containing the word 'prelude'
|
||||
/// are already allowed by default.
|
||||
#[lints(wildcard_imports)]
|
||||
allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default(),
|
||||
allowed_wildcard_imports: Vec<String> = Vec::new(),
|
||||
/// Suppress checking of the passed type names in all types of operations.
|
||||
///
|
||||
/// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
|
||||
@ -355,7 +354,7 @@ define_Conf! {
|
||||
/// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
|
||||
/// ```
|
||||
#[lints(arithmetic_side_effects)]
|
||||
arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(),
|
||||
arithmetic_side_effects_allowed_binary: Vec<(String, String)> = <_>::default(),
|
||||
/// Suppress checking of the passed type names in unary operations like "negation" (`-`).
|
||||
///
|
||||
/// #### Example
|
||||
@ -431,7 +430,7 @@ define_Conf! {
|
||||
/// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
||||
/// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
||||
#[lints(doc_markdown)]
|
||||
doc_valid_idents: FxHashSet<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(),
|
||||
doc_valid_idents: Vec<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(),
|
||||
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
|
||||
#[lints(non_send_fields_in_send_ty)]
|
||||
enable_raw_pointer_heuristic_for_send: bool = true,
|
||||
@ -706,12 +705,12 @@ fn deserialize(file: &SourceFile) -> TryConf {
|
||||
DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS,
|
||||
);
|
||||
// TODO: THIS SHOULD BE TESTED, this comment will be gone soon
|
||||
if conf.conf.allowed_idents_below_min_chars.contains("..") {
|
||||
if conf.conf.allowed_idents_below_min_chars.iter().any(|e| e == "..") {
|
||||
conf.conf
|
||||
.allowed_idents_below_min_chars
|
||||
.extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string));
|
||||
}
|
||||
if conf.conf.doc_valid_idents.contains("..") {
|
||||
if conf.conf.doc_valid_idents.iter().any(|e| e == "..") {
|
||||
conf.conf
|
||||
.doc_valid_idents
|
||||
.extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string));
|
||||
@ -890,14 +889,14 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use serde::de::IgnoredAny;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[test]
|
||||
fn configs_are_tested() {
|
||||
let mut names: FxHashSet<String> = crate::get_configuration_metadata()
|
||||
let mut names: HashSet<String> = crate::get_configuration_metadata()
|
||||
.into_iter()
|
||||
.map(|meta| meta.name.replace('_', "-"))
|
||||
.collect();
|
||||
@ -910,7 +909,7 @@ mod tests {
|
||||
for entry in toml_files {
|
||||
let file = fs::read_to_string(entry.path()).unwrap();
|
||||
#[allow(clippy::zero_sized_map_values)]
|
||||
if let Ok(map) = toml::from_str::<FxHashMap<String, IgnoredAny>>(&file) {
|
||||
if let Ok(map) = toml::from_str::<HashMap<String, IgnoredAny>>(&file) {
|
||||
for name in map.keys() {
|
||||
names.remove(name.as_str());
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
)]
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_attr;
|
||||
#[allow(unused_extern_crates)]
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::Session;
|
||||
use rustc_attr::parse_version;
|
||||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::{sym, Symbol};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
@ -10,7 +10,7 @@ macro_rules! msrv_aliases {
|
||||
$($name:ident),* $(,)?
|
||||
})*) => {
|
||||
$($(
|
||||
pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch);
|
||||
pub const $name: RustcVersion = RustcVersion { major: $major, minor :$minor, patch: $patch };
|
||||
)*)*
|
||||
};
|
||||
}
|
||||
@ -18,6 +18,7 @@ macro_rules! msrv_aliases {
|
||||
// names may refer to stabilized feature flags or library items
|
||||
msrv_aliases! {
|
||||
1,81,0 { LINT_REASONS_STABILIZATION }
|
||||
1,80,0 { BOX_INTO_ITER}
|
||||
1,77,0 { C_STR_LITERALS }
|
||||
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
|
||||
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
|
||||
@ -81,9 +82,9 @@ impl<'de> Deserialize<'de> for Msrv {
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let v = String::deserialize(deserializer)?;
|
||||
RustcVersion::parse(&v)
|
||||
parse_version(Symbol::intern(&v))
|
||||
.map(|v| Msrv { stack: vec![v] })
|
||||
.map_err(|_| serde::de::Error::custom("not a valid Rust version"))
|
||||
.ok_or_else(|| serde::de::Error::custom("not a valid Rust version"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +96,7 @@ impl Msrv {
|
||||
pub fn read_cargo(&mut self, sess: &Session) {
|
||||
let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
|
||||
.ok()
|
||||
.and_then(|v| RustcVersion::parse(&v).ok());
|
||||
.and_then(|v| parse_version(Symbol::intern(&v)));
|
||||
|
||||
match (self.current(), cargo_msrv) {
|
||||
(None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv],
|
||||
@ -115,7 +116,7 @@ impl Msrv {
|
||||
}
|
||||
|
||||
pub fn meets(&self, required: RustcVersion) -> bool {
|
||||
self.current().map_or(true, |version| version.meets(required))
|
||||
self.current().map_or(true, |msrv| msrv >= required)
|
||||
}
|
||||
|
||||
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
|
||||
@ -131,7 +132,7 @@ impl Msrv {
|
||||
}
|
||||
|
||||
if let Some(msrv) = msrv_attr.value_str() {
|
||||
if let Ok(version) = RustcVersion::parse(msrv.as_str()) {
|
||||
if let Some(version) = parse_version(msrv) {
|
||||
return Some(version);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![feature(rustc_private)]
|
||||
// warn on lints, that are included in `rust-lang/rust`s bootstrap
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
|
||||
|
@ -604,7 +604,7 @@ fn gen_declared_lints<'a>(
|
||||
details.sort_unstable();
|
||||
|
||||
let mut output = GENERATED_FILE_COMMENT.to_string();
|
||||
output.push_str("pub(crate) static LINTS: &[&crate::LintInfo] = &[\n");
|
||||
output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
|
||||
|
||||
for (is_public, module_name, lint_name) in details {
|
||||
if !is_public {
|
||||
|
@ -25,7 +25,6 @@ regex = { version = "1.5", optional = true }
|
||||
unicode-normalization = "0.1"
|
||||
unicode-script = { version = "0.5", default-features = false }
|
||||
semver = "1.0"
|
||||
rustc-semver = "1.1"
|
||||
url = "2.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
@ -8,6 +8,7 @@ use rustc_hir::{HirId, ItemKind, Node, Path};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -24,6 +25,13 @@ declare_clippy_lint! {
|
||||
/// Note: One exception to this is code from macro expansion - this does not lint such cases, as
|
||||
/// using absolute paths is the proper way of referencing items in one.
|
||||
///
|
||||
/// ### Known issues
|
||||
///
|
||||
/// There are currently a few cases which are not caught by this lint:
|
||||
/// * Macro calls. e.g. `path::to::macro!()`
|
||||
/// * Derive macros. e.g. `#[derive(path::to::macro)]`
|
||||
/// * Attribute macros. e.g. `#[path::to::macro]`
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// let x = std::f64::consts::PI;
|
||||
@ -48,63 +56,66 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
|
||||
|
||||
pub struct AbsolutePaths {
|
||||
pub absolute_paths_max_segments: u64,
|
||||
pub absolute_paths_allowed_crates: &'static FxHashSet<String>,
|
||||
pub absolute_paths_allowed_crates: FxHashSet<Symbol>,
|
||||
}
|
||||
|
||||
impl AbsolutePaths {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
absolute_paths_max_segments: conf.absolute_paths_max_segments,
|
||||
absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates,
|
||||
absolute_paths_allowed_crates: conf
|
||||
.absolute_paths_allowed_crates
|
||||
.iter()
|
||||
.map(|x| Symbol::intern(x))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for AbsolutePaths {
|
||||
impl<'tcx> LateLintPass<'tcx> for AbsolutePaths {
|
||||
// We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath`
|
||||
// we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't
|
||||
// a `Use`
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
|
||||
let Self {
|
||||
absolute_paths_max_segments,
|
||||
absolute_paths_allowed_crates,
|
||||
} = self;
|
||||
|
||||
if !path.span.from_expansion()
|
||||
&& let node = cx.tcx.hir_node(hir_id)
|
||||
&& !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
|
||||
&& let [first, rest @ ..] = path.segments
|
||||
// Handle `::std`
|
||||
&& let (segment, len) = if first.ident.name == kw::PathRoot {
|
||||
// Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1`
|
||||
// is fine here for the same reason
|
||||
(&rest[0], path.segments.len() - 1)
|
||||
} else {
|
||||
(first, path.segments.len())
|
||||
}
|
||||
&& len > *absolute_paths_max_segments as usize
|
||||
&& let Some(segment_snippet) = snippet_opt(cx, segment.ident.span)
|
||||
&& segment_snippet == segment.ident.as_str()
|
||||
{
|
||||
let is_abs_external =
|
||||
matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX);
|
||||
let is_abs_crate = segment.ident.name == kw::Crate;
|
||||
|
||||
if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str())
|
||||
|| is_abs_crate && absolute_paths_allowed_crates.contains("crate")
|
||||
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, hir_id: HirId) {
|
||||
let segments = match path.segments {
|
||||
[] | [_] => return,
|
||||
// Don't count enum variants and trait items as part of the length.
|
||||
[rest @ .., _]
|
||||
if let [.., s] = rest
|
||||
&& matches!(s.res, Res::Def(DefKind::Enum | DefKind::Trait | DefKind::TraitAlias, _)) =>
|
||||
{
|
||||
rest
|
||||
},
|
||||
path => path,
|
||||
};
|
||||
if let [s1, s2, ..] = segments
|
||||
&& let has_root = s1.ident.name == kw::PathRoot
|
||||
&& let first = if has_root { s2 } else { s1 }
|
||||
&& let len = segments.len() - usize::from(has_root)
|
||||
&& len as u64 > self.absolute_paths_max_segments
|
||||
&& let crate_name = if let Res::Def(DefKind::Mod, DefId { index, .. }) = first.res
|
||||
&& index == CRATE_DEF_INDEX
|
||||
{
|
||||
// `other_crate::foo` or `::other_crate::foo`
|
||||
first.ident.name
|
||||
} else if first.ident.name == kw::Crate || has_root {
|
||||
// `::foo` or `crate::foo`
|
||||
kw::Crate
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if is_abs_external || is_abs_crate {
|
||||
span_lint(
|
||||
cx,
|
||||
ABSOLUTE_PATHS,
|
||||
path.span,
|
||||
"consider bringing this path into scope with the `use` keyword",
|
||||
);
|
||||
}
|
||||
&& !path.span.from_expansion()
|
||||
&& let node = cx.tcx.hir_node(hir_id)
|
||||
&& !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(..)))
|
||||
&& !self.absolute_paths_allowed_crates.contains(&crate_name)
|
||||
&& !is_from_proc_macro(cx, path)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
ABSOLUTE_PATHS,
|
||||
path.span,
|
||||
"consider bringing this path into scope with the `use` keyword",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_session::{impl_lint_pass, RustcVersion};
|
||||
use rustc_span::symbol;
|
||||
use std::f64::consts as f64;
|
||||
|
||||
|
@ -3,7 +3,7 @@ use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local};
|
||||
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -118,6 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
|
||||
}
|
||||
)
|
||||
&& !clone_source_borrows_from_dest(cx, lhs, rhs.span)
|
||||
&& !is_in_test(cx.tcx, e.hir_id)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::source::{is_present_in_source, snippet_opt, without_block_comments};
|
||||
use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt};
|
||||
use rustc_ast::{AttrKind, AttrStyle};
|
||||
use rustc_lint::EarlyContext;
|
||||
use rustc_span::Span;
|
||||
@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
|
||||
item.span.parent(),
|
||||
);
|
||||
|
||||
if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) {
|
||||
if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) {
|
||||
let lines = snippet.split('\n').collect::<Vec<_>>();
|
||||
let lines = without_block_comments(lines);
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! checks for attributes
|
||||
|
||||
mod allow_attributes;
|
||||
mod allow_attributes_without_reason;
|
||||
mod blanket_clippy_restriction_lints;
|
||||
@ -310,8 +308,8 @@ declare_clippy_lint! {
|
||||
/// ```rust,ignore
|
||||
/// #[allow(unused_mut)]
|
||||
/// fn foo() -> usize {
|
||||
/// let mut a = Vec::new();
|
||||
/// a.len()
|
||||
/// let mut a = Vec::new();
|
||||
/// a.len()
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{Attribute, NON_MINIMAL_CFG};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_ast::{MetaItemKind, NestedMetaItem};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::EarlyContext;
|
||||
@ -29,8 +29,13 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
|
||||
meta.span,
|
||||
"unneeded sub `cfg` when there is only one condition",
|
||||
|diag| {
|
||||
if let Some(snippet) = snippet_opt(cx, list[0].span()) {
|
||||
diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect);
|
||||
if let Some(snippet) = list[0].span().get_source_text(cx) {
|
||||
diag.span_suggestion(
|
||||
meta.span,
|
||||
"try",
|
||||
snippet.to_owned(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::{Attribute, UNNECESSARY_CLIPPY_CFG};
|
||||
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::AttrStyle;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, Level};
|
||||
@ -31,7 +32,7 @@ pub(super) fn check(
|
||||
return;
|
||||
}
|
||||
if nb_items == clippy_lints.len() {
|
||||
if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) {
|
||||
if let Some(snippet) = behind_cfg_attr.span.get_source_text(cx) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_CLIPPY_CFG,
|
||||
@ -47,11 +48,7 @@ pub(super) fn check(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let snippet = clippy_lints
|
||||
.iter()
|
||||
.filter_map(|sp| snippet_opt(cx, *sp))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
let snippet = clippy_lints.iter().filter_map(|sp| sp.get_source_text(cx)).join(",");
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
UNNECESSARY_CLIPPY_CFG,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::utils::{extract_clippy_lint, is_lint_level, is_word};
|
||||
use super::{Attribute, USELESS_ATTRIBUTE};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{first_line_of_span, snippet_opt};
|
||||
use clippy_utils::source::{first_line_of_span, SpanRangeExt};
|
||||
use rustc_ast::NestedMetaItem;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
@ -69,14 +69,14 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute])
|
||||
}
|
||||
let line_span = first_line_of_span(cx, attr.span);
|
||||
|
||||
if let Some(mut sugg) = snippet_opt(cx, line_span) {
|
||||
if sugg.contains("#[") {
|
||||
if let Some(src) = line_span.get_source_text(cx) {
|
||||
if src.contains("#[") {
|
||||
#[expect(clippy::collapsible_span_lint_calls)]
|
||||
span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| {
|
||||
sugg = sugg.replacen("#[", "#![", 1);
|
||||
diag.span_suggestion(
|
||||
line_span,
|
||||
"if you just forgot a `!`, use",
|
||||
sugg,
|
||||
src.replacen("#[", "#![", 1),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||
use clippy_utils::eq_expr_value;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
@ -134,28 +134,30 @@ fn check_inverted_bool_in_condition(
|
||||
|
||||
let suggestion = match (left.kind, right.kind) {
|
||||
(ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => {
|
||||
let Some(left) = snippet_opt(cx, left_sub.span) else {
|
||||
let Some(left) = left_sub.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let Some(right) = snippet_opt(cx, right_sub.span) else {
|
||||
let Some(right) = right_sub.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let Some(op) = bin_op_eq_str(op) else { return };
|
||||
format!("{left} {op} {right}")
|
||||
},
|
||||
(ExprKind::Unary(UnOp::Not, left_sub), _) => {
|
||||
let Some(left) = snippet_opt(cx, left_sub.span) else {
|
||||
let Some(left) = left_sub.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let Some(right) = snippet_opt(cx, right.span) else {
|
||||
let Some(right) = right.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let Some(op) = inverted_bin_op_eq_str(op) else { return };
|
||||
format!("{left} {op} {right}")
|
||||
},
|
||||
(_, ExprKind::Unary(UnOp::Not, right_sub)) => {
|
||||
let Some(left) = snippet_opt(cx, left.span) else { return };
|
||||
let Some(right) = snippet_opt(cx, right_sub.span) else {
|
||||
let Some(left) = left.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let Some(right) = right_sub.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let Some(op) = inverted_bin_op_eq_str(op) else { return };
|
||||
@ -313,8 +315,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
||||
self.output.push_str(&str);
|
||||
} else {
|
||||
self.output.push('!');
|
||||
let snip = snippet_opt(self.cx, terminal.span)?;
|
||||
self.output.push_str(&snip);
|
||||
self.output.push_str(&terminal.span.get_source_text(self.cx)?);
|
||||
}
|
||||
},
|
||||
True | False | Not(_) => {
|
||||
@ -345,8 +346,12 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
||||
}
|
||||
},
|
||||
&Term(n) => {
|
||||
let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?;
|
||||
self.output.push_str(&snip);
|
||||
self.output.push_str(
|
||||
&self.terminals[n as usize]
|
||||
.span
|
||||
.source_callsite()
|
||||
.get_source_text(self.cx)?,
|
||||
);
|
||||
},
|
||||
}
|
||||
Some(())
|
||||
@ -370,8 +375,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
||||
_ => None,
|
||||
}
|
||||
.and_then(|op| {
|
||||
let lhs_snippet = snippet_opt(cx, lhs.span)?;
|
||||
let rhs_snippet = snippet_opt(cx, rhs.span)?;
|
||||
let lhs_snippet = lhs.span.get_source_text(cx)?;
|
||||
let rhs_snippet = rhs.span.get_source_text(cx)?;
|
||||
|
||||
if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) {
|
||||
if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) {
|
||||
@ -399,7 +404,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
||||
let path: &str = path.ident.name.as_str();
|
||||
a == path
|
||||
})
|
||||
.and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?)))
|
||||
.and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?)))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::reference::DEREF_ADDROF;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
|
||||
use rustc_errors::Applicability;
|
||||
@ -73,6 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
}
|
||||
})
|
||||
&& !is_from_proc_macro(cx, e)
|
||||
&& let Some(deref_text) = deref_target.span.get_source_text(cx)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"if you would like to reborrow, try removing `&*`",
|
||||
snippet_opt(cx, deref_target.span).unwrap(),
|
||||
deref_text.as_str(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
@ -98,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"if you would like to deref, try using `&**`",
|
||||
format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()),
|
||||
format!("&**{deref_text}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint on missing cargo common metadata
|
||||
|
||||
use cargo_metadata::Metadata;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -205,7 +205,7 @@ declare_clippy_lint! {
|
||||
}
|
||||
|
||||
pub struct Cargo {
|
||||
allowed_duplicate_crates: &'static FxHashSet<String>,
|
||||
allowed_duplicate_crates: FxHashSet<String>,
|
||||
ignore_publish: bool,
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ impl_lint_pass!(Cargo => [
|
||||
impl Cargo {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
allowed_duplicate_crates: &conf.allowed_duplicate_crates,
|
||||
allowed_duplicate_crates: conf.allowed_duplicate_crates.iter().cloned().collect(),
|
||||
ignore_publish: conf.cargo_ignore_publish,
|
||||
}
|
||||
}
|
||||
@ -263,7 +263,7 @@ impl LateLintPass<'_> for Cargo {
|
||||
{
|
||||
match MetadataCommand::new().exec() {
|
||||
Ok(metadata) => {
|
||||
multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates);
|
||||
multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates);
|
||||
},
|
||||
Err(e) => {
|
||||
for lint in WITH_DEPS_LINTS {
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint on multiple versions of a crate being used
|
||||
|
||||
use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use itertools::Itertools;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
||||
&& let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity()
|
||||
&& let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
|
||||
&& let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
|
||||
&& let Some(recv) = snippet_opt(cx, receiver.span)
|
||||
&& let Some(recv) = receiver.span.get_source_text(cx)
|
||||
{
|
||||
// `as_mut_ptr` might not exist
|
||||
let applicability = Applicability::MaybeIncorrect;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_in_const_context;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_isize_or_usize;
|
||||
use rustc_errors::Applicability;
|
||||
@ -34,7 +34,7 @@ pub(super) fn check(
|
||||
diag.help("an `as` cast can become silently lossy if the types change in the future");
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "<from>", &mut applicability);
|
||||
let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else {
|
||||
let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
match cast_to_hir.kind {
|
||||
|
@ -4,7 +4,7 @@ use clippy_utils::expr_or_init;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
|
||||
use rustc_errors::{Applicability, Diag, SuggestionStyle};
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
@ -190,12 +190,10 @@ fn offer_suggestion(
|
||||
format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, ".."))
|
||||
};
|
||||
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"... or use `try_from` and handle the error accordingly",
|
||||
suggestion,
|
||||
Applicability::Unspecified,
|
||||
// always show the suggestion in a separate line
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
@ -24,12 +24,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
||||
expr.span,
|
||||
format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
|
||||
|diag| {
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"did you mean to invoke the function?",
|
||||
format!("{from_snippet}() as {cast_to}"),
|
||||
applicability,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::numeric_literal::NumericLiteral;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::{snippet_opt, SpanRangeExt};
|
||||
use clippy_utils::visitors::{for_each_expr_without_closures, Visitable};
|
||||
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
|
||||
use rustc_ast::{LitFloatType, LitIntType, LitKind};
|
||||
@ -104,7 +104,7 @@ pub(super) fn check<'tcx>(
|
||||
let literal_str = &cast_str;
|
||||
|
||||
if let LitKind::Int(n, _) = lit.node
|
||||
&& let Some(src) = snippet_opt(cx, cast_expr.span)
|
||||
&& let Some(src) = cast_expr.span.get_source_text(cx)
|
||||
&& cast_to.is_floating_point()
|
||||
&& let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
|
||||
&& let from_nbits = 128 - n.get().leading_zeros()
|
||||
@ -131,7 +131,7 @@ pub(super) fn check<'tcx>(
|
||||
| LitKind::Float(_, LitFloatType::Suffixed(_))
|
||||
if cast_from.kind() == cast_to.kind() =>
|
||||
{
|
||||
if let Some(src) = snippet_opt(cx, cast_expr.span) {
|
||||
if let Some(src) = cast_expr.span.get_source_text(cx) {
|
||||
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
|
||||
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
|
||||
return true;
|
||||
@ -253,7 +253,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
|
||||
let res = cx.qpath_res(&qpath, expr.hir_id);
|
||||
// Function call
|
||||
if let Res::Def(DefKind::Fn, def_id) = res {
|
||||
let Some(snippet) = snippet_opt(cx, cx.tcx.def_span(def_id)) else {
|
||||
let Some(snippet) = cx.tcx.def_span(def_id).get_source_text(cx) else {
|
||||
return ControlFlow::Continue(());
|
||||
};
|
||||
// This is the worst part of this entire function. This is the only way I know of to
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability, Ty, TyKind};
|
||||
@ -20,7 +20,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>
|
||||
|
||||
let sugg = if let TyKind::Infer = mut_ty.ty.kind {
|
||||
format!("{std_or_core}::{sugg_fn}()")
|
||||
} else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
|
||||
} else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) {
|
||||
format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")
|
||||
} else {
|
||||
return;
|
||||
|
@ -5,7 +5,7 @@ use rustc_session::declare_lint_pass;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`)
|
||||
/// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#[cfg(not(test))]`)
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This may give the false impression that a codebase has 100% coverage, yet actually has untested code.
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint on manually implemented checked conversions that could be transformed into `try_from`
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! calculate cognitive complexity and warn about overly complex functions
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::{IntoSpan, SpanRangeExt};
|
||||
|
@ -1,17 +1,3 @@
|
||||
//! Checks for if expressions that contain only an if expression.
|
||||
//!
|
||||
//! For example, the lint would catch:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! if x {
|
||||
//! if y {
|
||||
//! println!("Hello world");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This lint is **warn** by default
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
|
||||
use clippy_utils::visitors::{for_each_expr, Visitable};
|
||||
use clippy_utils::{get_enclosing_block, path_to_local_id};
|
||||
use core::ops::ControlFlow;
|
||||
@ -7,7 +7,6 @@ use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -44,24 +43,11 @@ declare_clippy_lint! {
|
||||
}
|
||||
declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]);
|
||||
|
||||
// Add `String` here when it is added to diagnostic items
|
||||
static COLLECTIONS: [Symbol; 9] = [
|
||||
sym::BTreeMap,
|
||||
sym::BTreeSet,
|
||||
sym::BinaryHeap,
|
||||
sym::HashMap,
|
||||
sym::HashSet,
|
||||
sym::LinkedList,
|
||||
sym::Option,
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
];
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
|
||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
|
||||
// Look for local variables whose type is a container. Search surrounding block for read access.
|
||||
if let PatKind::Binding(_, local_id, _, _) = local.pat.kind
|
||||
&& match_acceptable_type(cx, local, &COLLECTIONS)
|
||||
&& match_acceptable_type(cx, local)
|
||||
&& let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id)
|
||||
&& has_no_read_access(cx, local_id, enclosing_block)
|
||||
{
|
||||
@ -70,11 +56,22 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
|
||||
}
|
||||
}
|
||||
|
||||
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool {
|
||||
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
|
||||
let ty = cx.typeck_results().pat_ty(local.pat);
|
||||
collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
|
||||
// String type is a lang item but not a diagnostic item for now so we need a separate check
|
||||
|| is_type_lang_item(cx, ty, LangItem::String)
|
||||
matches!(
|
||||
get_type_diagnostic_name(cx, ty),
|
||||
Some(
|
||||
sym::BTreeMap
|
||||
| sym::BTreeSet
|
||||
| sym::BinaryHeap
|
||||
| sym::HashMap
|
||||
| sym::HashSet
|
||||
| sym::LinkedList
|
||||
| sym::Option
|
||||
| sym::Vec
|
||||
| sym::VecDeque
|
||||
)
|
||||
) || is_type_lang_item(cx, ty, LangItem::String)
|
||||
}
|
||||
|
||||
fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
@ -46,7 +46,7 @@ impl LateLintPass<'_> for CreateDir {
|
||||
"calling `std::fs::create_dir` where there may be a better way",
|
||||
|diag| {
|
||||
let mut app = Applicability::MaybeIncorrect;
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"consider calling `std::fs::create_dir_all` instead",
|
||||
format!(
|
||||
@ -54,7 +54,6 @@ impl LateLintPass<'_> for CreateDir {
|
||||
snippet_with_applicability(cx, arg.span, "..", &mut app)
|
||||
),
|
||||
app,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
pub static LINTS: &[&crate::LintInfo] = &[
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
@ -22,8 +22,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
|
||||
@ -146,6 +144,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
|
||||
crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO,
|
||||
crate::doc::TEST_ATTR_IN_DOCTEST_INFO,
|
||||
crate::doc::TOO_LONG_FIRST_DOC_PARAGRAPH_INFO,
|
||||
crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
|
||||
crate::double_parens::DOUBLE_PARENS_INFO,
|
||||
crate::drop_forget_ref::DROP_NON_DROP_INFO,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use itertools::Itertools;
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{BytePos, Span};
|
||||
use std::ops::Range;
|
||||
@ -59,12 +59,11 @@ pub(super) fn check(
|
||||
&& (doc_comment == "///" || doc_comment == "//!")
|
||||
{
|
||||
// suggest filling in a blank line
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
line_break_span.shrink_to_lo(),
|
||||
"if this should be its own paragraph, add a blank doc comment line",
|
||||
format!("\n{doc_comment}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
if ccount > 0 || blockquote_level > 0 {
|
||||
diag.help("if this not intended to be a quote at all, escape it with `\\>`");
|
||||
@ -79,12 +78,11 @@ pub(super) fn check(
|
||||
if ccount == 0 && blockquote_level == 0 {
|
||||
// simpler suggestion style for indentation
|
||||
let indent = list_indentation - lcount;
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"indent this line",
|
||||
std::iter::repeat(" ").take(indent).join(""),
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
diag.help("if this is supposed to be its own paragraph, add a blank line");
|
||||
return;
|
||||
@ -107,12 +105,11 @@ pub(super) fn check(
|
||||
suggested.push_str(text);
|
||||
}
|
||||
}
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
"add markers to start of line",
|
||||
suggested,
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
diag.help("if this not intended to be a quote at all, escape it with `\\>`");
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
use url::Url;
|
||||
@ -92,6 +92,10 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
|
||||
&& matches!(prefix.chars().last(), Some('S' | 'X'))
|
||||
{
|
||||
prefix
|
||||
} else if let Some(prefix) = s.strip_suffix("ified")
|
||||
&& prefix.chars().all(|c| c.is_ascii_uppercase())
|
||||
{
|
||||
prefix
|
||||
} else {
|
||||
s.strip_suffix('s').unwrap_or(s)
|
||||
};
|
||||
@ -133,24 +137,15 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
|
||||
}
|
||||
|
||||
if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
"item in documentation is missing backticks",
|
||||
|diag| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
|
||||
diag.span_suggestion_with_style(
|
||||
span,
|
||||
"try",
|
||||
format!("`{snippet}`"),
|
||||
applicability,
|
||||
// always show the suggestion in a separate line, since the
|
||||
// inline presentation adds another pair of backticks
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
diag.span_suggestion_verbose(span, "try", format!("`{snippet}`"), applicability);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
mod lazy_continuation;
|
||||
mod too_long_first_doc_paragraph;
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
@ -309,7 +311,7 @@ declare_clippy_lint! {
|
||||
/// ### Known problems
|
||||
/// Inner doc comments can only appear before items, so there are certain cases where the suggestion
|
||||
/// made by this lint is not valid code. For example:
|
||||
/// ```rs
|
||||
/// ```rust
|
||||
/// fn foo() {}
|
||||
/// ///!
|
||||
/// fn bar() {}
|
||||
@ -422,15 +424,47 @@ declare_clippy_lint! {
|
||||
"require every line of a paragraph to be indented and marked"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks if the first line in the documentation of items listed in module page is too long.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Documentation will show the first paragraph of the doscstring in the summary page of a
|
||||
/// module, so having a nice, short summary in the first paragraph is part of writing good docs.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// /// A very short summary.
|
||||
/// /// A much longer explanation that goes into a lot more detail about
|
||||
/// /// how the thing works, possibly with doclinks and so one,
|
||||
/// /// and probably spanning a many rows.
|
||||
/// struct Foo {}
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// /// A very short summary.
|
||||
/// ///
|
||||
/// /// A much longer explanation that goes into a lot more detail about
|
||||
/// /// how the thing works, possibly with doclinks and so one,
|
||||
/// /// and probably spanning a many rows.
|
||||
/// struct Foo {}
|
||||
/// ```
|
||||
#[clippy::version = "1.81.0"]
|
||||
pub TOO_LONG_FIRST_DOC_PARAGRAPH,
|
||||
style,
|
||||
"ensure that the first line of a documentation paragraph isn't too long"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Documentation {
|
||||
valid_idents: &'static FxHashSet<String>,
|
||||
valid_idents: FxHashSet<String>,
|
||||
check_private_items: bool,
|
||||
}
|
||||
|
||||
impl Documentation {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
valid_idents: &conf.doc_valid_idents,
|
||||
valid_idents: conf.doc_valid_idents.iter().cloned().collect(),
|
||||
check_private_items: conf.check_private_items,
|
||||
}
|
||||
}
|
||||
@ -448,48 +482,60 @@ impl_lint_pass!(Documentation => [
|
||||
SUSPICIOUS_DOC_COMMENTS,
|
||||
EMPTY_DOCS,
|
||||
DOC_LAZY_CONTINUATION,
|
||||
TOO_LONG_FIRST_DOC_PARAGRAPH,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Documentation {
|
||||
fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
|
||||
let Some(headers) = check_attrs(cx, self.valid_idents, attrs) else {
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
|
||||
return;
|
||||
};
|
||||
|
||||
match cx.tcx.hir_node(cx.last_node_with_lint_attrs) {
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::Fn(sig, _, body_id) => {
|
||||
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
Node::Item(item) => {
|
||||
too_long_first_doc_paragraph::check(
|
||||
cx,
|
||||
item,
|
||||
attrs,
|
||||
headers.first_paragraph_len,
|
||||
self.check_private_items,
|
||||
);
|
||||
match item.kind {
|
||||
ItemKind::Fn(sig, _, body_id) => {
|
||||
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id())
|
||||
|| in_external_macro(cx.tcx.sess, item.span))
|
||||
{
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
|
||||
let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
|
||||
missing_headers::check(
|
||||
let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
|
||||
missing_headers::check(
|
||||
cx,
|
||||
item.owner_id,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
panic_info,
|
||||
self.check_private_items,
|
||||
);
|
||||
}
|
||||
},
|
||||
ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
|
||||
(false, Safety::Unsafe) => span_lint(
|
||||
cx,
|
||||
item.owner_id,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
panic_info,
|
||||
self.check_private_items,
|
||||
);
|
||||
}
|
||||
},
|
||||
ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
|
||||
(false, Safety::Unsafe) => span_lint(
|
||||
cx,
|
||||
MISSING_SAFETY_DOC,
|
||||
cx.tcx.def_span(item.owner_id),
|
||||
"docs for unsafe trait missing `# Safety` section",
|
||||
),
|
||||
(true, Safety::Safe) => span_lint(
|
||||
cx,
|
||||
UNNECESSARY_SAFETY_DOC,
|
||||
cx.tcx.def_span(item.owner_id),
|
||||
"docs for safe trait have unnecessary `# Safety` section",
|
||||
),
|
||||
MISSING_SAFETY_DOC,
|
||||
cx.tcx.def_span(item.owner_id),
|
||||
"docs for unsafe trait missing `# Safety` section",
|
||||
),
|
||||
(true, Safety::Safe) => span_lint(
|
||||
cx,
|
||||
UNNECESSARY_SAFETY_DOC,
|
||||
cx.tcx.def_span(item.owner_id),
|
||||
"docs for safe trait have unnecessary `# Safety` section",
|
||||
),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
Node::TraitItem(trait_item) => {
|
||||
if let TraitItemKind::Fn(sig, ..) = trait_item.kind
|
||||
@ -547,6 +593,7 @@ struct DocHeaders {
|
||||
safety: bool,
|
||||
errors: bool,
|
||||
panics: bool,
|
||||
first_paragraph_len: usize,
|
||||
}
|
||||
|
||||
/// Does some pre-processing on raw, desugared `#[doc]` attributes such as parsing them and
|
||||
@ -653,6 +700,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
let mut paragraph_range = 0..0;
|
||||
let mut code_level = 0;
|
||||
let mut blockquote_level = 0;
|
||||
let mut is_first_paragraph = true;
|
||||
|
||||
let mut containers = Vec::new();
|
||||
|
||||
@ -720,6 +768,10 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
}
|
||||
ticks_unbalanced = false;
|
||||
paragraph_range = range;
|
||||
if is_first_paragraph {
|
||||
headers.first_paragraph_len = doc[paragraph_range.clone()].chars().count();
|
||||
is_first_paragraph = false;
|
||||
}
|
||||
},
|
||||
End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => {
|
||||
if let End(TagEnd::Heading(_)) = event {
|
||||
|
@ -0,0 +1,91 @@
|
||||
use rustc_ast::ast::Attribute;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
||||
use super::TOO_LONG_FIRST_DOC_PARAGRAPH;
|
||||
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
item: &Item<'_>,
|
||||
attrs: &[Attribute],
|
||||
mut first_paragraph_len: usize,
|
||||
check_private_items: bool,
|
||||
) {
|
||||
if !check_private_items && !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
|
||||
return;
|
||||
}
|
||||
if first_paragraph_len <= 200
|
||||
|| !matches!(
|
||||
item.kind,
|
||||
// This is the list of items which can be documented AND are displayed on the module
|
||||
// page. So associated items or impl blocks are not part of this list.
|
||||
ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::Fn(..)
|
||||
| ItemKind::Macro(..)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..)
|
||||
| ItemKind::Trait(..)
|
||||
| ItemKind::TraitAlias(..)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let mut spans = Vec::new();
|
||||
let mut should_suggest_empty_doc = false;
|
||||
|
||||
for attr in attrs {
|
||||
if let Some(doc) = attr.doc_str() {
|
||||
spans.push(attr.span);
|
||||
let doc = doc.as_str();
|
||||
let doc = doc.trim();
|
||||
if spans.len() == 1 {
|
||||
// We make this suggestion only if the first doc line ends with a punctuation
|
||||
// because it might just need to add an empty line with `///`.
|
||||
should_suggest_empty_doc = doc.ends_with('.') || doc.ends_with('!') || doc.ends_with('?');
|
||||
}
|
||||
let len = doc.chars().count();
|
||||
if len >= first_paragraph_len {
|
||||
break;
|
||||
}
|
||||
first_paragraph_len -= len;
|
||||
}
|
||||
}
|
||||
|
||||
let &[first_span, .., last_span] = spans.as_slice() else {
|
||||
return;
|
||||
};
|
||||
if is_from_proc_macro(cx, item) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
TOO_LONG_FIRST_DOC_PARAGRAPH,
|
||||
first_span.with_hi(last_span.lo()),
|
||||
"first doc comment paragraph is too long",
|
||||
|diag| {
|
||||
if should_suggest_empty_doc
|
||||
&& let Some(second_span) = spans.get(1)
|
||||
&& let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi())
|
||||
&& let Some(snippet) = snippet_opt(cx, new_span)
|
||||
{
|
||||
diag.span_suggestion(
|
||||
new_span,
|
||||
"add an empty line",
|
||||
format!("{snippet}///\n"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
//! Lint on if expressions with an else if, but without a final else branch.
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_ast::ast::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint when there is an enum with no variants
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -1,6 +1,3 @@
|
||||
//! lint on C-like enums that are `repr(isize/usize)` and have values that
|
||||
//! don't fit into an `i32`
|
||||
|
||||
use clippy_utils::consts::{mir_to_const, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::type_diagnostic_name;
|
||||
use clippy_utils::ty::get_type_diagnostic_name;
|
||||
use clippy_utils::usage::{local_used_after_expr, local_used_in};
|
||||
use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id};
|
||||
use rustc_errors::Applicability;
|
||||
@ -139,7 +139,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
|
||||
{
|
||||
let callee_ty_raw = typeck.expr_ty(callee);
|
||||
let callee_ty = callee_ty_raw.peel_refs();
|
||||
if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
|
||||
if matches!(get_type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
|
||||
|| !check_inputs(typeck, body.params, None, args)
|
||||
{
|
||||
return;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::numeric_literal;
|
||||
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, FloatTy};
|
||||
@ -117,12 +117,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
if type_suffix.is_none() {
|
||||
float_str.push_str(".0");
|
||||
}
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"consider changing the type or replacing it with",
|
||||
numeric_literal::format(&float_str, type_suffix, true),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -134,12 +133,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
expr.span,
|
||||
"float has excessive precision",
|
||||
|diag| {
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"consider changing the type or truncating it to",
|
||||
numeric_literal::format(&float_str, type_suffix, true),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage};
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_context};
|
||||
use clippy_utils::source::{snippet_with_context, SpanRangeExt};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
|
||||
use rustc_errors::Applicability;
|
||||
@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
||||
([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
|
||||
([], [_]) => {
|
||||
// Simulate macro expansion, converting {{ and }} to { and }.
|
||||
let Some(snippet) = snippet_opt(cx, format_args.span) else {
|
||||
let Some(snippet) = format_args.span.get_source_text(cx) else {
|
||||
return;
|
||||
};
|
||||
let s_expand = snippet.replace("{{", "{").replace("}}", "}");
|
||||
@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
||||
span_useless_format(cx, call_site, sugg, applicability);
|
||||
},
|
||||
([arg], [piece]) => {
|
||||
if let Ok(value) = find_format_arg_expr(expr, arg)
|
||||
if let Some(value) = find_format_arg_expr(expr, arg)
|
||||
&& let FormatArgsPiece::Placeholder(placeholder) = piece
|
||||
&& placeholder.format_trait == FormatTrait::Display
|
||||
&& placeholder.format_options == FormatOptions::default()
|
||||
|
@ -7,7 +7,7 @@ use clippy_utils::macros::{
|
||||
find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro,
|
||||
is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall,
|
||||
};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::{
|
||||
@ -224,13 +224,11 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
|
||||
if let FormatArgsPiece::Placeholder(placeholder) = piece
|
||||
&& let Ok(index) = placeholder.argument.index
|
||||
&& let Some(arg) = self.format_args.arguments.all_args().get(index)
|
||||
&& let Some(arg_expr) = find_format_arg_expr(self.expr, arg)
|
||||
{
|
||||
let arg_expr = find_format_arg_expr(self.expr, arg);
|
||||
|
||||
self.check_unused_format_specifier(placeholder, arg_expr);
|
||||
|
||||
if let Ok(arg_expr) = arg_expr
|
||||
&& placeholder.format_trait == FormatTrait::Display
|
||||
if placeholder.format_trait == FormatTrait::Display
|
||||
&& placeholder.format_options == FormatOptions::default()
|
||||
&& !self.is_aliased(index)
|
||||
{
|
||||
@ -242,28 +240,13 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_unused_format_specifier(
|
||||
&self,
|
||||
placeholder: &FormatPlaceholder,
|
||||
arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>,
|
||||
) {
|
||||
let ty_or_ast_expr = arg_expr.map(|expr| self.cx.typeck_results().expr_ty(expr).peel_refs());
|
||||
|
||||
let is_format_args = match ty_or_ast_expr {
|
||||
Ok(ty) => is_type_lang_item(self.cx, ty, LangItem::FormatArguments),
|
||||
Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)),
|
||||
};
|
||||
|
||||
fn check_unused_format_specifier(&self, placeholder: &FormatPlaceholder, arg: &Expr<'_>) {
|
||||
let options = &placeholder.format_options;
|
||||
|
||||
let arg_span = match arg_expr {
|
||||
Ok(expr) => expr.span,
|
||||
Err(expr) => expr.span,
|
||||
};
|
||||
|
||||
if let Some(placeholder_span) = placeholder.span
|
||||
&& is_format_args
|
||||
&& *options != FormatOptions::default()
|
||||
&& let ty = self.cx.typeck_results().expr_ty(arg).peel_refs()
|
||||
&& is_type_lang_item(self.cx, ty, LangItem::FormatArguments)
|
||||
{
|
||||
span_lint_and_then(
|
||||
self.cx,
|
||||
@ -274,7 +257,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
|
||||
let mut suggest_format = |spec| {
|
||||
let message = format!("for the {spec} to apply consider using `format!()`");
|
||||
|
||||
if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) {
|
||||
if let Some(mac_call) = matching_root_macro_call(self.cx, arg.span, sym::format_args_macro) {
|
||||
diag.span_suggestion(
|
||||
self.cx.sess().source_map().span_until_char(mac_call.span, '!'),
|
||||
message,
|
||||
@ -424,7 +407,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
|
||||
count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter())
|
||||
&& implements_trait(cx, target, display_trait_id, &[])
|
||||
&& let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait()
|
||||
&& let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite())
|
||||
&& let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx)
|
||||
{
|
||||
let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
|
||||
if n_needed_derefs == 0 && !needs_ref {
|
||||
|
@ -196,7 +196,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
|
||||
&& trait_name == self.format_trait_impl.name
|
||||
&& let Ok(index) = placeholder.argument.index
|
||||
&& let Some(arg) = format_args.arguments.all_args().get(index)
|
||||
&& let Ok(arg_expr) = find_format_arg_expr(self.expr, arg)
|
||||
&& let Some(arg_expr) = find_format_arg_expr(self.expr, arg)
|
||||
{
|
||||
self.check_format_arg_self(arg_expr);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::span_is_local;
|
||||
use clippy_utils::path_def_id;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_path, Visitor};
|
||||
use rustc_hir::{
|
||||
@ -178,8 +178,8 @@ fn convert_to_from(
|
||||
return None;
|
||||
};
|
||||
|
||||
let from = snippet_opt(cx, self_ty.span)?;
|
||||
let into = snippet_opt(cx, target_ty.span)?;
|
||||
let from = self_ty.span.get_source_text(cx)?;
|
||||
let into = target_ty.span.get_source_text(cx)?;
|
||||
|
||||
let mut suggestions = vec![
|
||||
// impl Into<T> for U -> impl From<T> for U
|
||||
@ -187,10 +187,10 @@ fn convert_to_from(
|
||||
(into_trait_seg.ident.span, String::from("From")),
|
||||
// impl Into<T> for U -> impl Into<U> for U
|
||||
// ~ ~
|
||||
(target_ty.span, from.clone()),
|
||||
(target_ty.span, from.to_owned()),
|
||||
// impl Into<T> for U -> impl Into<T> for T
|
||||
// ~ ~
|
||||
(self_ty.span, into),
|
||||
(self_ty.span, into.to_owned()),
|
||||
// fn into(self) -> T -> fn from(self) -> T
|
||||
// ~~~~ ~~~~
|
||||
(impl_item.ident.span, String::from("from")),
|
||||
@ -223,7 +223,7 @@ fn convert_to_from(
|
||||
}
|
||||
|
||||
for span in finder.upper {
|
||||
suggestions.push((span, from.clone()));
|
||||
suggestions.push((span, from.to_owned()));
|
||||
}
|
||||
for span in finder.lower {
|
||||
suggestions.push((span, String::from("val")));
|
||||
|
@ -22,8 +22,8 @@ declare_clippy_lint! {
|
||||
///
|
||||
/// ### Known problems
|
||||
///
|
||||
/// This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly
|
||||
/// in some cases, which is correct but adds unnecessary complexity to the code.
|
||||
/// This lint may suggest using `(&<expression>).parse()` instead of `<expression>.parse()`
|
||||
/// directly in some cases, which is correct but adds unnecessary complexity to the code.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```ignore
|
||||
|
@ -1,6 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_in_test;
|
||||
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
|
||||
@ -18,20 +19,18 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_
|
||||
|diag| {
|
||||
if let Some(gen_span) = generics.span_for_param_suggestion() {
|
||||
// If there's already a generic param with the same bound, do not lint **this** suggestion.
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
gen_span,
|
||||
"add a type parameter",
|
||||
format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]),
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
rustc_errors::SuggestionStyle::ShowAlways,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
generics.span,
|
||||
"add a type parameter",
|
||||
format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]),
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
rustc_errors::SuggestionStyle::ShowAlways,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -8,11 +8,11 @@ use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use clippy_utils::attrs::is_proc_macro;
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::is_must_use_ty;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
@ -129,9 +129,9 @@ fn check_needless_must_use(
|
||||
cx,
|
||||
DOUBLE_MUST_USE,
|
||||
fn_header_span,
|
||||
"this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`",
|
||||
"this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]`",
|
||||
None,
|
||||
"either add some descriptive text or remove the attribute",
|
||||
"either add some descriptive message or remove the attribute",
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -155,7 +155,7 @@ fn check_must_use_candidate<'tcx>(
|
||||
return;
|
||||
}
|
||||
span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| {
|
||||
if let Some(snippet) = snippet_opt(cx, fn_span) {
|
||||
if let Some(snippet) = fn_span.get_source_text(cx) {
|
||||
diag.span_suggestion(
|
||||
fn_span,
|
||||
"add the attribute",
|
||||
@ -193,17 +193,13 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
|
||||
}
|
||||
}
|
||||
|
||||
static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];
|
||||
|
||||
fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool {
|
||||
match *ty.kind() {
|
||||
// primitive types are never mutable
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
|
||||
ty::Adt(adt, args) => {
|
||||
tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
|
||||
|| KNOWN_WRAPPER_TYS
|
||||
.iter()
|
||||
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
|
||||
|| matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc))
|
||||
&& args.types().any(|ty| is_mutable_ty(cx, ty, tys))
|
||||
},
|
||||
ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
|
||||
|
@ -1,12 +1,11 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_span::Span;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
||||
use super::TOO_MANY_LINES;
|
||||
|
||||
pub(super) fn check_fn(
|
||||
@ -22,57 +21,57 @@ pub(super) fn check_fn(
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(code_snippet) = snippet_opt(cx, body.value.span) else {
|
||||
return;
|
||||
};
|
||||
let mut line_count: u64 = 0;
|
||||
let mut in_comment = false;
|
||||
let mut code_in_line;
|
||||
let too_many = body.value.span.check_source_text(cx, |src| {
|
||||
let mut in_comment = false;
|
||||
let mut code_in_line;
|
||||
|
||||
let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
|
||||
&& code_snippet.as_bytes().first().copied() == Some(b'{')
|
||||
&& code_snippet.as_bytes().last().copied() == Some(b'}')
|
||||
{
|
||||
// Removing the braces from the enclosing block
|
||||
&code_snippet[1..code_snippet.len() - 1]
|
||||
} else {
|
||||
&code_snippet
|
||||
}
|
||||
.trim() // Remove leading and trailing blank lines
|
||||
.lines();
|
||||
let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
|
||||
&& src.as_bytes().first().copied() == Some(b'{')
|
||||
&& src.as_bytes().last().copied() == Some(b'}')
|
||||
{
|
||||
// Removing the braces from the enclosing block
|
||||
&src[1..src.len() - 1]
|
||||
} else {
|
||||
src
|
||||
}
|
||||
.trim() // Remove leading and trailing blank lines
|
||||
.lines();
|
||||
|
||||
for mut line in function_lines {
|
||||
code_in_line = false;
|
||||
loop {
|
||||
line = line.trim_start();
|
||||
if line.is_empty() {
|
||||
for mut line in function_lines {
|
||||
code_in_line = false;
|
||||
loop {
|
||||
line = line.trim_start();
|
||||
if line.is_empty() {
|
||||
break;
|
||||
}
|
||||
if in_comment {
|
||||
if let Some(i) = line.find("*/") {
|
||||
line = &line[i + 2..];
|
||||
in_comment = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
let multi_idx = line.find("/*").unwrap_or(line.len());
|
||||
let single_idx = line.find("//").unwrap_or(line.len());
|
||||
code_in_line |= multi_idx > 0 && single_idx > 0;
|
||||
// Implies multi_idx is below line.len()
|
||||
if multi_idx < single_idx {
|
||||
line = &line[multi_idx + 2..];
|
||||
in_comment = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if in_comment {
|
||||
if let Some(i) = line.find("*/") {
|
||||
line = &line[i + 2..];
|
||||
in_comment = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
let multi_idx = line.find("/*").unwrap_or(line.len());
|
||||
let single_idx = line.find("//").unwrap_or(line.len());
|
||||
code_in_line |= multi_idx > 0 && single_idx > 0;
|
||||
// Implies multi_idx is below line.len()
|
||||
if multi_idx < single_idx {
|
||||
line = &line[multi_idx + 2..];
|
||||
in_comment = true;
|
||||
continue;
|
||||
}
|
||||
if code_in_line {
|
||||
line_count += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if code_in_line {
|
||||
line_count += 1;
|
||||
}
|
||||
}
|
||||
line_count > too_many_lines_threshold
|
||||
});
|
||||
|
||||
if line_count > too_many_lines_threshold {
|
||||
if too_many {
|
||||
span_lint(
|
||||
cx,
|
||||
TOO_MANY_LINES,
|
||||
|
@ -1,6 +1,3 @@
|
||||
//! lint on if branches that could be swapped so no `!` operation is necessary
|
||||
//! on the condition
|
||||
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_else_clause;
|
||||
|
@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context, wal
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
@ -54,13 +54,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
|
||||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let snip = snippet_with_applicability(cx, span, "..", &mut app);
|
||||
diag.span_suggestion_with_style(
|
||||
span,
|
||||
"add `return` as shown",
|
||||
format!("return {snip}"),
|
||||
app,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
diag.span_suggestion_verbose(span, "add `return` as shown", format!("return {snip}"), app);
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -75,12 +69,11 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp
|
||||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
break_span,
|
||||
"change `break` to `return` as shown",
|
||||
format!("return {snip}"),
|
||||
app,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -7,8 +7,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{Expr, ExprKind, HirId};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_session::{impl_lint_pass, RustcVersion};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{ExpnKind, Span};
|
||||
|
||||
@ -65,18 +64,18 @@ impl IncompatibleMsrv {
|
||||
StabilityLevel::Stable {
|
||||
since: StableSince::Version(version),
|
||||
..
|
||||
} => Some(RustcVersion::new(
|
||||
version.major.into(),
|
||||
version.minor.into(),
|
||||
version.patch.into(),
|
||||
)),
|
||||
} => Some(version),
|
||||
_ => None,
|
||||
}) {
|
||||
version
|
||||
} else if let Some(parent_def_id) = tcx.opt_parent(def_id) {
|
||||
self.get_def_id_version(tcx, parent_def_id)
|
||||
} else {
|
||||
RustcVersion::new(1, 0, 0)
|
||||
RustcVersion {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
}
|
||||
};
|
||||
self.is_above_msrv.insert(def_id, version);
|
||||
version
|
||||
|
@ -1,4 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::fulfill_or_allowed;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Applicability;
|
||||
@ -71,6 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||
&& let ty = cx.typeck_results().expr_ty(expr)
|
||||
&& let Some(adt_def) = ty.ty_adt_def()
|
||||
&& adt_def.is_struct()
|
||||
&& let Some(local_def_id) = adt_def.did().as_local()
|
||||
&& let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
|
||||
&& let Some(variant) = adt_def.variants().iter().next()
|
||||
{
|
||||
let mut def_order_map = FxHashMap::default();
|
||||
@ -103,15 +106,17 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||
snippet(cx, qpath.span(), ".."),
|
||||
);
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
INCONSISTENT_STRUCT_CONSTRUCTOR,
|
||||
expr.span,
|
||||
"struct constructor field order is inconsistent with struct definition field order",
|
||||
"try",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
INCONSISTENT_STRUCT_CONSTRUCTOR,
|
||||
expr.span,
|
||||
"struct constructor field order is inconsistent with struct definition field order",
|
||||
"try",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint on indexing and slicing operations
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
|
@ -1,10 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
|
||||
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -210,18 +210,6 @@ const COMPLETING_METHODS: [(&str, usize); 12] = [
|
||||
("product", 0),
|
||||
];
|
||||
|
||||
/// the paths of types that are known to be infinitely allocating
|
||||
const INFINITE_COLLECTORS: &[Symbol] = &[
|
||||
sym::BinaryHeap,
|
||||
sym::BTreeMap,
|
||||
sym::BTreeSet,
|
||||
sym::HashMap,
|
||||
sym::HashSet,
|
||||
sym::LinkedList,
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
];
|
||||
|
||||
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||
match expr.kind {
|
||||
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||
@ -248,10 +236,19 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||
}
|
||||
} else if method.ident.name == sym!(collect) {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if INFINITE_COLLECTORS
|
||||
.iter()
|
||||
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
|
||||
{
|
||||
if matches!(
|
||||
get_type_diagnostic_name(cx, ty),
|
||||
Some(
|
||||
sym::BinaryHeap
|
||||
| sym::BTreeMap
|
||||
| sym::BTreeSet
|
||||
| sym::HashMap
|
||||
| sym::HashSet
|
||||
| sym::LinkedList
|
||||
| sym::Vec
|
||||
| sym::VecDeque,
|
||||
)
|
||||
) {
|
||||
return is_infinite(cx, receiver);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint on inherent implementations
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! checks for `#[inline]` on trait methods without bodies
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::sugg::DiagExt;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -1,7 +1,5 @@
|
||||
//! lint on blocks unnecessarily using >= with a + 1 or - 1
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind};
|
||||
use rustc_ast::token;
|
||||
use rustc_errors::Applicability;
|
||||
@ -132,8 +130,8 @@ impl IntPlusOne {
|
||||
BinOpKind::Le => "<",
|
||||
_ => return None,
|
||||
};
|
||||
if let Some(snippet) = snippet_opt(cx, node.span) {
|
||||
if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
|
||||
if let Some(snippet) = node.span.get_source_text(cx) {
|
||||
if let Some(other_side_snippet) = other_side.span.get_source_text(cx) {
|
||||
let rec = match side {
|
||||
Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")),
|
||||
Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")),
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint on enum variants that are prefixed or suffixed by the same characters
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
|
||||
use clippy_utils::is_bool;
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint when items are used after statements
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_hir;
|
||||
use rustc_hir::{Block, ItemKind, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_hir::{HirId, Item, ItemKind, Mod};
|
||||
@ -93,11 +93,14 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
|
||||
if let Some(prev) = mod_pos.checked_sub(1)
|
||||
&& let prev = cx.tcx.hir().item(module.item_ids[prev])
|
||||
&& let items_span = last.span.with_lo(test_mod.span.hi())
|
||||
&& let Some(items) = snippet_opt(cx, items_span)
|
||||
&& let Some(items) = items_span.get_source_text(cx)
|
||||
{
|
||||
diag.multipart_suggestion_with_style(
|
||||
"move the items to before the test module was defined",
|
||||
vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())],
|
||||
vec![
|
||||
(prev.span.shrink_to_hi(), items.to_owned()),
|
||||
(items_span, String::new()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! lint when there is a large size difference between variants on an enum
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
|
@ -3,7 +3,7 @@ use std::{fmt, ops};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::fn_has_unsatisfiable_preds;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl};
|
||||
@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
|
||||
// TODO: Is there a cleaner, robust way to ask this question?
|
||||
// The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data",
|
||||
// and that doesn't get us the true name in scope rather than the span text either.
|
||||
if let Some(name) = snippet_opt(cx, local_span)
|
||||
if let Some(name) = local_span.get_source_text(cx)
|
||||
&& is_ident(&name)
|
||||
{
|
||||
// If the local is an ordinary named variable,
|
||||
|
@ -3,7 +3,7 @@ use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::{get_parent_expr, is_from_proc_macro};
|
||||
use hir::def_id::DefId;
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
@ -143,12 +143,11 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
{
|
||||
span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
"use the associated constant instead",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_context};
|
||||
use clippy_utils::source::{snippet_with_context, SpanRangeExt};
|
||||
use clippy_utils::sugg::{has_enclosing_paren, Sugg};
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
|
||||
use rustc_ast::ast::LitKind;
|
||||
@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
||||
}
|
||||
|
||||
fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span {
|
||||
let Some(snippet) = snippet_opt(cx, span) else {
|
||||
let Some(snippet) = span.get_source_text(cx) else {
|
||||
return span;
|
||||
};
|
||||
if has_enclosing_paren(snippet) {
|
||||
|
@ -66,8 +66,8 @@ extern crate declare_clippy_lint;
|
||||
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
|
||||
mod utils;
|
||||
|
||||
mod declared_lints;
|
||||
mod deprecated_lints;
|
||||
pub mod declared_lints;
|
||||
pub mod deprecated_lints;
|
||||
|
||||
// begin lints modules, do not remove this comment, it’s used in `update_lints`
|
||||
mod absolute_paths;
|
||||
@ -440,7 +440,7 @@ impl RegistrationGroups {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum LintCategory {
|
||||
Cargo,
|
||||
Complexity,
|
||||
@ -479,11 +479,39 @@ impl LintCategory {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LintInfo {
|
||||
pub struct LintInfo {
|
||||
/// Double reference to maintain pointer equality
|
||||
lint: &'static &'static Lint,
|
||||
pub lint: &'static &'static Lint,
|
||||
category: LintCategory,
|
||||
explanation: &'static str,
|
||||
pub explanation: &'static str,
|
||||
/// e.g. `clippy_lints/src/absolute_paths.rs#43`
|
||||
pub location: &'static str,
|
||||
pub version: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl LintInfo {
|
||||
/// Returns the lint name in lowercase without the `clippy::` prefix
|
||||
#[allow(clippy::missing_panics_doc)]
|
||||
pub fn name_lower(&self) -> String {
|
||||
self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase()
|
||||
}
|
||||
|
||||
/// Returns the name of the lint's category in lowercase (`style`, `pedantic`)
|
||||
pub fn category_str(&self) -> &'static str {
|
||||
match self.category {
|
||||
Cargo => "cargo",
|
||||
Complexity => "complexity",
|
||||
Correctness => "correctness",
|
||||
Nursery => "nursery",
|
||||
Pedantic => "pedantic",
|
||||
Perf => "perf",
|
||||
Restriction => "restriction",
|
||||
Style => "style",
|
||||
Suspicious => "suspicious",
|
||||
#[cfg(feature = "internal")]
|
||||
Internal => "internal",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn explain(name: &str) -> i32 {
|
||||
@ -538,14 +566,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
||||
store.register_removed(name, reason);
|
||||
}
|
||||
|
||||
#[cfg(feature = "internal")]
|
||||
{
|
||||
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
|
||||
store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let format_args_storage = FormatArgsStorage::default();
|
||||
let format_args = format_args_storage.clone();
|
||||
store.register_early_pass(move || {
|
||||
|
@ -1,10 +1,7 @@
|
||||
//! Lints concerned with the grouping of digits with underscores in integral or
|
||||
//! floating-point literal expressions.
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_ast::ast::{Expr, ExprKind, LitKind};
|
||||
use rustc_ast::token;
|
||||
use rustc_errors::Applicability;
|
||||
@ -228,7 +225,7 @@ impl LiteralDigitGrouping {
|
||||
}
|
||||
|
||||
fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
|
||||
if let Some(src) = snippet_opt(cx, span)
|
||||
if let Some(src) = span.get_source_text(cx)
|
||||
&& let Ok(lit_kind) = LitKind::from_token_lit(lit)
|
||||
&& let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
|
||||
{
|
||||
@ -442,7 +439,7 @@ impl DecimalLiteralRepresentation {
|
||||
// Lint integral literals.
|
||||
if let Ok(lit_kind) = LitKind::from_token_lit(lit)
|
||||
&& let LitKind::Int(val, _) = lit_kind
|
||||
&& let Some(src) = snippet_opt(cx, span)
|
||||
&& let Some(src) = span.get_source_text(cx)
|
||||
&& let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
|
||||
&& num_lit.radix == Radix::Decimal
|
||||
&& val >= u128::from(self.threshold)
|
||||
|
@ -3,7 +3,7 @@ use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{
|
||||
implements_trait, implements_trait_with_env, is_copy, make_normalized_projection,
|
||||
implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
|
||||
make_normalized_projection_with_regions, normalize_with_regions,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
@ -20,9 +20,10 @@ pub(super) fn check(
|
||||
msrv: &Msrv,
|
||||
enforce_iter_loop_reborrow: bool,
|
||||
) {
|
||||
let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow) else {
|
||||
let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow, msrv) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let ty::Array(_, count) = *ty.peel_refs().kind() {
|
||||
if !ty.is_ref() {
|
||||
if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) {
|
||||
@ -109,6 +110,7 @@ fn is_ref_iterable<'tcx>(
|
||||
self_arg: &Expr<'_>,
|
||||
call_expr: &Expr<'_>,
|
||||
enforce_iter_loop_reborrow: bool,
|
||||
msrv: &Msrv,
|
||||
) -> Option<(AdjustKind, Ty<'tcx>)> {
|
||||
let typeck = cx.typeck_results();
|
||||
if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
|
||||
@ -128,6 +130,12 @@ fn is_ref_iterable<'tcx>(
|
||||
let self_ty = typeck.expr_ty(self_arg);
|
||||
let self_is_copy = is_copy(cx, self_ty);
|
||||
|
||||
if !msrv.meets(msrvs::BOX_INTO_ITER)
|
||||
&& is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if adjustments.is_empty() && self_is_copy {
|
||||
// Exact type match, already checked earlier
|
||||
return Some((AdjustKind::None, self_ty));
|
||||
|
@ -122,8 +122,23 @@ struct BodyVisitor<'a, 'tcx> {
|
||||
/// within a relevant macro.
|
||||
macro_unsafe_blocks: Vec<HirId>,
|
||||
/// When this is >0, it means that the node currently being visited is "within" a
|
||||
/// macro definition. This is not necessary for correctness, it merely helps reduce the number
|
||||
/// of spans we need to insert into the map, since only spans from macros are relevant.
|
||||
/// macro definition.
|
||||
/// This is used to detect if an expression represents a metavariable.
|
||||
///
|
||||
/// For example, the following pre-expansion code that we want to lint
|
||||
/// ```ignore
|
||||
/// macro_rules! m { ($e:expr) => { unsafe { $e; } } }
|
||||
/// m!(1);
|
||||
/// ```
|
||||
/// would look like this post-expansion code:
|
||||
/// ```ignore
|
||||
/// unsafe { /* macro */
|
||||
/// 1 /* root */; /* macro */
|
||||
/// }
|
||||
/// ```
|
||||
/// Visiting the block and the statement will increment the `expn_depth` so that it is >0,
|
||||
/// and visiting the expression with a root context while `expn_depth > 0` tells us
|
||||
/// that it must be a metavariable.
|
||||
expn_depth: u32,
|
||||
cx: &'a LateContext<'tcx>,
|
||||
lint: &'a mut ExprMetavarsInUnsafe,
|
||||
@ -157,7 +172,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> {
|
||||
&& (self.lint.warn_unsafe_macro_metavars_in_private_macros || is_public_macro(self.cx, macro_def_id))
|
||||
{
|
||||
self.macro_unsafe_blocks.push(block.hir_id);
|
||||
self.expn_depth += 1;
|
||||
walk_block(self, block);
|
||||
self.expn_depth -= 1;
|
||||
self.macro_unsafe_blocks.pop();
|
||||
} else if ctxt.is_root() && self.expn_depth > 0 {
|
||||
let unsafe_block = self.macro_unsafe_blocks.last().copied();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
|
||||
use clippy_utils::source::{position_before_rarrow, snippet_block, SpanRangeExt};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
@ -68,8 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
|
||||
header_span,
|
||||
"this function can be simplified using the `async fn` syntax",
|
||||
|diag| {
|
||||
if let Some(vis_snip) = snippet_opt(cx, *vis_span)
|
||||
&& let Some(header_snip) = snippet_opt(cx, header_span)
|
||||
if let Some(vis_snip) = vis_span.get_source_text(cx)
|
||||
&& let Some(header_snip) = header_span.get_source_text(cx)
|
||||
&& let Some(ret_pos) = position_before_rarrow(&header_snip)
|
||||
&& let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output)
|
||||
{
|
||||
@ -190,6 +190,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str,
|
||||
Some((sugg, String::new()))
|
||||
} else {
|
||||
let sugg = "return the output of the future directly";
|
||||
snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}")))
|
||||
output.span.get_source_text(cx).map(|src| (sugg, format!(" -> {src}")))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{is_from_proc_macro, path_to_local};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Constness, Expr, ExprKind};
|
||||
@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
||||
// case somebody does that for some reason
|
||||
&& (is_infinity(&const_1) && is_neg_infinity(&const_2)
|
||||
|| is_neg_infinity(&const_1) && is_infinity(&const_2))
|
||||
&& let Some(local_snippet) = snippet_opt(cx, first.span)
|
||||
&& let Some(local_snippet) = first.span.get_source_text(cx)
|
||||
{
|
||||
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
|
||||
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::visitors::{is_local_used, local_used_once};
|
||||
use clippy_utils::{is_trait_method, path_to_local_id};
|
||||
use rustc_errors::Applicability;
|
||||
@ -107,8 +107,8 @@ impl LateLintPass<'_> for ManualHashOne {
|
||||
finish_expr.span,
|
||||
"manual implementation of `BuildHasher::hash_one`",
|
||||
|diag| {
|
||||
if let Some(build_hasher) = snippet_opt(cx, build_hasher.span)
|
||||
&& let Some(hashed_value) = snippet_opt(cx, hashed_value.span)
|
||||
if let Some(build_hasher) = build_hasher.span.get_source_text(cx)
|
||||
&& let Some(hashed_value) = hashed_value.span.get_source_text(cx)
|
||||
{
|
||||
diag.multipart_suggestion(
|
||||
"try",
|
||||
|
@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::is_doc_hidden;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_ast::ast::{self, VisibilityKind};
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -124,7 +124,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
|
||||
|diag| {
|
||||
if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive))
|
||||
&& let header_span = cx.sess().source_map().span_until_char(item.span, delimiter)
|
||||
&& let Some(snippet) = snippet_opt(cx, header_span)
|
||||
&& let Some(snippet) = header_span.get_source_text(cx)
|
||||
{
|
||||
diag.span_suggestion(
|
||||
header_span,
|
||||
@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
|
||||
"this seems like a manual implementation of the non-exhaustive pattern",
|
||||
|diag| {
|
||||
let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
|
||||
if let Some(snippet) = snippet_opt(cx, header_span) {
|
||||
if let Some(snippet) = header_span.get_source_text(cx) {
|
||||
diag.span_suggestion(
|
||||
header_span,
|
||||
"add the attribute",
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns {
|
||||
pat.span,
|
||||
"this OR pattern can be rewritten using a range",
|
||||
|diag| {
|
||||
if let Some(min) = snippet_opt(cx, min.span)
|
||||
&& let Some(max) = snippet_opt(cx, max.span)
|
||||
if let Some(min) = min.span.get_source_text(cx)
|
||||
&& let Some(max) = max.span.get_source_text(cx)
|
||||
{
|
||||
diag.span_suggestion(
|
||||
pat.span,
|
||||
|
@ -2,14 +2,13 @@ use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
|
||||
use clippy_utils::{match_def_path, paths, SpanlessEq};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::ExprKind::Assign;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
@ -21,16 +20,6 @@ const ACCEPTABLE_METHODS: [&[&str]; 5] = [
|
||||
&paths::SLICE_INTO,
|
||||
&paths::VEC_DEQUE_ITER,
|
||||
];
|
||||
const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 7] = [
|
||||
(sym::BinaryHeap, Some(msrvs::BINARY_HEAP_RETAIN)),
|
||||
(sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)),
|
||||
(sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)),
|
||||
(sym::HashSet, Some(msrvs::HASH_SET_RETAIN)),
|
||||
(sym::HashMap, Some(msrvs::HASH_MAP_RETAIN)),
|
||||
(sym::Vec, None),
|
||||
(sym::VecDeque, None),
|
||||
];
|
||||
const MAP_TYPES: [rustc_span::Symbol; 2] = [sym::BTreeMap, sym::HashMap];
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -265,16 +254,22 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo
|
||||
}
|
||||
|
||||
fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {
|
||||
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| {
|
||||
is_type_diagnostic_item(cx, expr_ty, *ty)
|
||||
&& acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
|
||||
})
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
let required = match get_type_diagnostic_name(cx, ty) {
|
||||
Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN,
|
||||
Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN,
|
||||
Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN,
|
||||
Some(sym::HashSet) => msrvs::HASH_SET_RETAIN,
|
||||
Some(sym::HashMap) => msrvs::HASH_MAP_RETAIN,
|
||||
Some(sym::Vec | sym::VecDeque) => return true,
|
||||
_ => return false,
|
||||
};
|
||||
msrv.meets(required)
|
||||
}
|
||||
|
||||
fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
MAP_TYPES.iter().any(|ty| is_type_diagnostic_item(cx, expr_ty, *ty))
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap))
|
||||
}
|
||||
|
||||
fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) {
|
||||
|
@ -96,7 +96,7 @@ fn check_arm<'tcx>(
|
||||
// collapsing patterns need an explicit field name in struct pattern matching
|
||||
// ex: Struct {x: Some(1)}
|
||||
let replace_msg = if is_innermost_parent_pat_struct {
|
||||
format!(", prefixed by {}:", snippet(cx, binding_span, "their field name"))
|
||||
format!(", prefixed by `{}`:", snippet(cx, binding_span, "their field name"))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::consts::ConstEvalCtxt;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::usage::contains_return_break_continue_macro;
|
||||
use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
|
||||
@ -67,11 +67,11 @@ fn check_and_lint<'tcx>(
|
||||
&& path_to_local_id(peel_blocks(then_expr), binding_hir_id)
|
||||
&& cx.typeck_results().expr_adjustments(then_expr).is_empty()
|
||||
&& let Some(ty_name) = find_type_name(cx, ty)
|
||||
&& let Some(or_body_snippet) = snippet_opt(cx, else_expr.span)
|
||||
&& let Some(or_body_snippet) = else_expr.span.get_source_text(cx)
|
||||
&& let Some(indent) = indent_of(cx, expr.span)
|
||||
&& ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some()
|
||||
{
|
||||
lint(cx, expr, let_expr, ty_name, or_body_snippet, indent);
|
||||
lint(cx, expr, let_expr, ty_name, &or_body_snippet, indent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ fn lint<'tcx>(
|
||||
expr: &Expr<'tcx>,
|
||||
scrutinee: &'tcx Expr<'_>,
|
||||
ty_name: &str,
|
||||
or_body_snippet: String,
|
||||
or_body_snippet: &str,
|
||||
indent: usize,
|
||||
) {
|
||||
let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent));
|
||||
|
@ -22,7 +22,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
|
||||
/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
|
||||
/// match arms.
|
||||
fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
|
||||
if let Some(ff) = span.get_source_text(cx)
|
||||
if let Some(ff) = span.get_source_range(cx)
|
||||
&& let Some(text) = ff.as_str()
|
||||
{
|
||||
text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt};
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
@ -49,10 +49,12 @@ pub(super) fn check<'tcx>(
|
||||
"case-sensitive file extension comparison",
|
||||
|diag| {
|
||||
diag.help("consider using a case-insensitive comparison instead");
|
||||
if let Some(mut recv_source) = snippet_opt(cx, recv.span) {
|
||||
if !cx.typeck_results().expr_ty(recv).is_ref() {
|
||||
recv_source = format!("&{recv_source}");
|
||||
}
|
||||
if let Some(recv_source) = recv.span.get_source_text(cx) {
|
||||
let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() {
|
||||
recv_source.to_owned()
|
||||
} else {
|
||||
format!("&{recv_source}")
|
||||
};
|
||||
|
||||
let suggestion_source = reindent_multiline(
|
||||
format!(
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::FILTER_MAP_BOOL_THEN;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::paths::BOOL_THEN;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks};
|
||||
use rustc_errors::Applicability;
|
||||
@ -42,9 +42,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
|
||||
.iter()
|
||||
.filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
|
||||
.count()
|
||||
&& let Some(param_snippet) = snippet_opt(cx, param.span)
|
||||
&& let Some(filter) = snippet_opt(cx, recv.span)
|
||||
&& let Some(map) = snippet_opt(cx, then_body.span)
|
||||
&& let Some(param_snippet) = param.span.get_source_text(cx)
|
||||
&& let Some(filter) = recv.span.get_source_text(cx)
|
||||
&& let Some(map) = then_body.span.get_source_text(cx)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_path_diagnostic_item, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
@ -39,7 +39,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) ->
|
||||
}
|
||||
|
||||
let call_site = expr.span.source_callsite();
|
||||
if let Some(snippet) = snippet_opt(cx, call_site)
|
||||
if let Some(snippet) = call_site.get_source_text(cx)
|
||||
&& let snippet_split = snippet.split("::").collect::<Vec<_>>()
|
||||
&& let Some((_, elements)) = snippet_split.split_last()
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ pub(super) fn check<'tcx>(
|
||||
"&"
|
||||
};
|
||||
|
||||
diag.span_suggestion_with_style(
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
"using `[]` is clearer and more concise",
|
||||
format!(
|
||||
@ -82,7 +82,6 @@ pub(super) fn check<'tcx>(
|
||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
rustc_errors::SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! Lint for `c.is_digit(10)`
|
||||
|
||||
use super::IS_DIGIT_ASCII_RADIX;
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::expr_or_init;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a
|
||||
join_arg.span,
|
||||
"argument to `Path::join` starts with a path separator",
|
||||
|diag| {
|
||||
let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string());
|
||||
let arg_str = snippet(cx, spanned.span, "..");
|
||||
|
||||
let no_separator = if sym_str.starts_with('/') {
|
||||
arg_str.replacen('/', "", 1)
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
|
||||
use rustc_errors::Applicability;
|
||||
@ -23,11 +23,11 @@ pub(super) fn check<'tcx>(
|
||||
&& let ExprKind::Call(err_path, [err_arg]) = or_expr.kind
|
||||
&& is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr)
|
||||
&& is_ok_wrapping(cx, map_expr)
|
||||
&& let Some(recv_snippet) = snippet_opt(cx, recv.span)
|
||||
&& let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span)
|
||||
&& let Some(recv_snippet) = recv.span.get_source_text(cx)
|
||||
&& let Some(err_arg_snippet) = err_arg.span.get_source_text(cx)
|
||||
&& let Some(indent) = indent_of(cx, expr.span)
|
||||
{
|
||||
let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
|
||||
let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str().into(), true, Some(indent + 4));
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_OK_OR,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_from_proc_macro, is_trait_method};
|
||||
use rustc_errors::Applicability;
|
||||
@ -31,13 +31,15 @@ pub(super) fn check<'tcx>(
|
||||
&& let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id)
|
||||
&& let ExprKind::Closure(closure) = acc.kind
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
&& let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span))
|
||||
&& let Some(args_snip) = closure
|
||||
.fn_arg_span
|
||||
.and_then(|fn_arg_span| fn_arg_span.get_source_text(cx))
|
||||
{
|
||||
let init_snip = rest
|
||||
.is_empty()
|
||||
.then_some(first.span)
|
||||
.and_then(|span| snippet_opt(cx, span))
|
||||
.unwrap_or("...".to_owned());
|
||||
.and_then(|span| span.get_source_text(cx))
|
||||
.map_or_else(|| "...".to_owned(), |src| src.to_owned());
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -2702,10 +2702,10 @@ declare_clippy_lint! {
|
||||
/// }
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
/// ```
|
||||
///
|
||||
/// After:
|
||||
/// ```rust
|
||||
/// After:
|
||||
/// ```rust
|
||||
/// use std::{fmt, num::ParseIntError};
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
|
@ -7,7 +7,7 @@ use rustc_span::Span;
|
||||
use super::utils::get_last_chain_binding_hir_id;
|
||||
use super::NEEDLESS_CHARACTER_ITERATION;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
|
||||
|
||||
fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
|
||||
@ -35,7 +35,7 @@ fn handle_expr(
|
||||
&& path_to_local_id(receiver, first_param)
|
||||
&& let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
|
||||
&& *char_arg_ty.kind() == ty::Char
|
||||
&& let Some(snippet) = snippet_opt(cx, before_chars)
|
||||
&& let Some(snippet) = before_chars.get_source_text(cx)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -79,7 +79,7 @@ fn handle_expr(
|
||||
&& let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
|
||||
&& match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"])
|
||||
&& path_to_local_id(peels_expr_ref(arg), first_param)
|
||||
&& let Some(snippet) = snippet_opt(cx, before_chars)
|
||||
&& let Some(snippet) = before_chars.get_source_text(cx)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -2,7 +2,7 @@ use super::NEEDLESS_COLLECT;
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection};
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id,
|
||||
CaptureKind,
|
||||
@ -88,9 +88,10 @@ pub(super) fn check<'tcx>(
|
||||
Node::LetStmt(l) => {
|
||||
if let PatKind::Binding(BindingMode::NONE | BindingMode::MUT, id, _, None) = l.pat.kind
|
||||
&& let ty = cx.typeck_results().expr_ty(collect_expr)
|
||||
&& [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList]
|
||||
.into_iter()
|
||||
.any(|item| is_type_diagnostic_item(cx, ty, item))
|
||||
&& matches!(
|
||||
get_type_diagnostic_name(cx, ty),
|
||||
Some(sym::Vec | sym::VecDeque | sym::BinaryHeap | sym::LinkedList)
|
||||
)
|
||||
&& let iter_ty = cx.typeck_results().expr_ty(iter_expr)
|
||||
&& let Some(block) = get_enclosing_block(cx, l.hir_id)
|
||||
&& let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty))
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::path_res;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::usage::local_used_after_expr;
|
||||
use rustc_errors::Applicability;
|
||||
@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
|
||||
expr.span,
|
||||
"derefed type is same as origin",
|
||||
"try",
|
||||
snippet_opt(cx, recv.span).unwrap(),
|
||||
recv.span.get_source_text(cx).unwrap().to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local};
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::LitKind;
|
||||
@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
|
||||
_ => return,
|
||||
}
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
&& let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span)
|
||||
&& let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx)
|
||||
{
|
||||
// Normalize the char using `map` so `join` doesn't use `Display`, if we don't then
|
||||
// something like `r"\"` will become `'\'`, which is of course invalid
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user