mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge commit '1fcc74cc9e03bc91eaa80ecf92976b0b14b3aeb6' into clippyup
This commit is contained in:
parent
48dec842f2
commit
ba4bf4f9c5
39 changed files with 646 additions and 248 deletions
35
.github/ISSUE_TEMPLATE/false_negative.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/false_negative.md
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
name: Bug Report (False Negative)
|
||||
about: Create a bug report about missing warnings from a lint
|
||||
labels: L-bug, L-false-negative
|
||||
---
|
||||
<!--
|
||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||
along with any information you feel relevant to replicating the bug.
|
||||
-->
|
||||
Lint name:
|
||||
|
||||
|
||||
I tried this code:
|
||||
|
||||
```rust
|
||||
<code>
|
||||
```
|
||||
|
||||
I expected to see this happen: *explanation*
|
||||
|
||||
Instead, this happened: *explanation*
|
||||
|
||||
### Meta
|
||||
|
||||
- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
|
||||
- `rustc -Vv`:
|
||||
```
|
||||
rustc 1.46.0-nightly (f455e46ea 2020-06-20)
|
||||
binary: rustc
|
||||
commit-hash: f455e46eae1a227d735091091144601b467e1565
|
||||
commit-date: 2020-06-20
|
||||
host: x86_64-unknown-linux-gnu
|
||||
release: 1.46.0-nightly
|
||||
LLVM version: 10.0
|
||||
```
|
35
.github/ISSUE_TEMPLATE/false_positive.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/false_positive.md
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
name: Bug Report (False Positive)
|
||||
about: Create a bug report about a wrongly emitted lint warning
|
||||
labels: L-bug, L-false-positive
|
||||
---
|
||||
<!--
|
||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||
along with any information you feel relevant to replicating the bug.
|
||||
-->
|
||||
Lint name:
|
||||
|
||||
|
||||
I tried this code:
|
||||
|
||||
```rust
|
||||
<code>
|
||||
```
|
||||
|
||||
I expected to see this happen: *explanation*
|
||||
|
||||
Instead, this happened: *explanation*
|
||||
|
||||
### Meta
|
||||
|
||||
- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
|
||||
- `rustc -Vv`:
|
||||
```
|
||||
rustc 1.46.0-nightly (f455e46ea 2020-06-20)
|
||||
binary: rustc
|
||||
commit-hash: f455e46eae1a227d735091091144601b467e1565
|
||||
commit-date: 2020-06-20
|
||||
host: x86_64-unknown-linux-gnu
|
||||
release: 1.46.0-nightly
|
||||
LLVM version: 10.0
|
||||
```
|
3
.github/workflows/clippy.yml
vendored
3
.github/workflows/clippy.yml
vendored
|
@ -50,6 +50,9 @@ jobs:
|
|||
- name: Build
|
||||
run: cargo build --features deny-warnings,internal-lints
|
||||
|
||||
- name: Test "--fix -Zunstable-options"
|
||||
run: cargo run --features deny-warnings,internal-lints --bin cargo-clippy -- clippy --fix -Zunstable-options
|
||||
|
||||
- name: Test
|
||||
run: cargo test --features deny-warnings,internal-lints
|
||||
|
||||
|
|
|
@ -1841,6 +1841,7 @@ Released 2018-09-13
|
|||
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
|
||||
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
|
||||
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
|
||||
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
|
||||
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
|
||||
[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
|
||||
[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.0.212"
|
||||
version = "0.1.51"
|
||||
authors = [
|
||||
"Manish Goregaokar <manishsmail@gmail.com>",
|
||||
"Andre Bogus <bogusandre@gmail.com>",
|
||||
|
@ -29,7 +29,7 @@ path = "src/driver.rs"
|
|||
|
||||
[dependencies]
|
||||
# begin automatic update
|
||||
clippy_lints = { version = "0.0.212", path = "clippy_lints" }
|
||||
clippy_lints = { version = "0.1.50", path = "clippy_lints" }
|
||||
# end automatic update
|
||||
semver = "0.11"
|
||||
rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" }
|
||||
|
|
43
README.md
43
README.md
|
@ -10,16 +10,16 @@ A collection of lints to catch common mistakes and improve your [Rust](https://g
|
|||
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
|
||||
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
|
||||
|
||||
Category | Description | Default level
|
||||
-- | -- | --
|
||||
`clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny**
|
||||
`clippy::correctness` | code that is outright wrong or very useless | **deny**
|
||||
`clippy::style` | code that should be written in a more idiomatic way | **warn**
|
||||
`clippy::complexity` | code that does something simple but in a complex way | **warn**
|
||||
`clippy::perf` | code that can be written to run faster | **warn**
|
||||
`clippy::pedantic` | lints which are rather strict or might have false positives | allow
|
||||
`clippy::nursery` | new lints that are still under development | allow
|
||||
`clippy::cargo` | lints for the cargo manifest | allow
|
||||
| Category | Description | Default level |
|
||||
| --------------------- | ----------------------------------------------------------------------- | ------------- |
|
||||
| `clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny** |
|
||||
| `clippy::correctness` | code that is outright wrong or very useless | **deny** |
|
||||
| `clippy::style` | code that should be written in a more idiomatic way | **warn** |
|
||||
| `clippy::complexity` | code that does something simple but in a complex way | **warn** |
|
||||
| `clippy::perf` | code that can be written to run faster | **warn** |
|
||||
| `clippy::pedantic` | lints which are rather strict or might have false positives | allow |
|
||||
| `clippy::nursery` | new lints that are still under development | allow |
|
||||
| `clippy::cargo` | lints for the cargo manifest | allow |
|
||||
|
||||
More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
|
||||
|
||||
|
@ -98,17 +98,6 @@ If you want to run Clippy **only** on the given crate, use the `--no-deps` optio
|
|||
cargo clippy -p example -- --no-deps
|
||||
```
|
||||
|
||||
### Running Clippy from the command line without installing it
|
||||
|
||||
To have cargo compile your crate with Clippy without Clippy installation
|
||||
in your code, you can use:
|
||||
|
||||
```terminal
|
||||
cargo run --bin cargo-clippy --manifest-path=path_to_clippys_Cargo.toml
|
||||
```
|
||||
|
||||
*Note:* Be sure that Clippy was compiled with the same version of rustc that cargo invokes here!
|
||||
|
||||
### Travis CI
|
||||
|
||||
You can add Clippy to Travis CI in the same way you use it locally:
|
||||
|
@ -130,18 +119,6 @@ script:
|
|||
# etc.
|
||||
```
|
||||
|
||||
If you are on nightly, It might happen that Clippy is not available for a certain nightly release.
|
||||
In this case you can try to conditionally install Clippy from the Git repo.
|
||||
|
||||
```yaml
|
||||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
before_script:
|
||||
- rustup component add clippy --toolchain=nightly || cargo install --git https://github.com/rust-lang/rust-clippy/ --force clippy
|
||||
# etc.
|
||||
```
|
||||
|
||||
Note that adding `-D warnings` will cause your build to fail if **any** warnings are found in your code.
|
||||
That includes warnings found by rustc (e.g. `dead_code`, etc.). If you want to avoid this and only cause
|
||||
an error for Clippy warnings, use `#![deny(clippy::all)]` in your code or `-D clippy::all` on the command
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
// This module takes an absolute path to a rustc repo and alters the dependencies to point towards
|
||||
// the respective rustc subcrates instead of using extern crate xyz.
|
||||
|
@ -44,7 +44,7 @@ pub fn run(rustc_path: Option<&str>) {
|
|||
}
|
||||
|
||||
fn inject_deps_into_manifest(
|
||||
rustc_source_dir: &PathBuf,
|
||||
rustc_source_dir: &Path,
|
||||
manifest_path: &str,
|
||||
cargo_toml: &str,
|
||||
lib_rs: &str,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
# begin automatic update
|
||||
version = "0.0.212"
|
||||
version = "0.1.51"
|
||||
# end automatic update
|
||||
authors = [
|
||||
"Manish Goregaokar <manishsmail@gmail.com>",
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, Adt, Ty};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
@ -103,18 +103,41 @@ impl LateLintPass<'_> for Default {
|
|||
}
|
||||
|
||||
fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
|
||||
// find all binding statements like `let mut _ = T::default()` where `T::default()` is the
|
||||
// `default` method of the `Default` trait, and store statement index in current block being
|
||||
// checked and the name of the bound variable
|
||||
let binding_statements_using_default = enumerate_bindings_using_default(cx, block);
|
||||
|
||||
// start from the `let mut _ = _::default();` and look at all the following
|
||||
// statements, see if they re-assign the fields of the binding
|
||||
for (stmt_idx, binding_name, binding_type, span) in binding_statements_using_default {
|
||||
// the last statement of a block cannot trigger the lint
|
||||
if stmt_idx == block.stmts.len() - 1 {
|
||||
break;
|
||||
}
|
||||
let stmts_head = match block.stmts {
|
||||
// Skip the last statement since there cannot possibly be any following statements that re-assign fields.
|
||||
[head @ .., _] if !head.is_empty() => head,
|
||||
_ => return,
|
||||
};
|
||||
for (stmt_idx, stmt) in stmts_head.iter().enumerate() {
|
||||
// find all binding statements like `let mut _ = T::default()` where `T::default()` is the
|
||||
// `default` method of the `Default` trait, and store statement index in current block being
|
||||
// checked and the name of the bound variable
|
||||
let (local, variant, binding_name, binding_type, span) = if_chain! {
|
||||
// only take `let ...` statements
|
||||
if let StmtKind::Local(local) = stmt.kind;
|
||||
if let Some(expr) = local.init;
|
||||
// only take bindings to identifiers
|
||||
if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
|
||||
// only when assigning `... = Default::default()`
|
||||
if is_expr_default(expr, cx);
|
||||
let binding_type = cx.typeck_results().node_type(binding_id);
|
||||
if let Some(adt) = binding_type.ty_adt_def();
|
||||
if adt.is_struct();
|
||||
let variant = adt.non_enum_variant();
|
||||
if adt.did.is_local() || !variant.is_field_list_non_exhaustive();
|
||||
let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id();
|
||||
if variant
|
||||
.fields
|
||||
.iter()
|
||||
.all(|field| field.vis.is_accessible_from(module_did, cx.tcx));
|
||||
then {
|
||||
(local, variant, ident.name, binding_type, expr.span)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// find all "later statement"'s where the fields of the binding set as
|
||||
// Default::default() get reassigned, unless the reassignment refers to the original binding
|
||||
|
@ -122,15 +145,8 @@ impl LateLintPass<'_> for Default {
|
|||
let mut assigned_fields = Vec::new();
|
||||
let mut cancel_lint = false;
|
||||
for consecutive_statement in &block.stmts[stmt_idx + 1..] {
|
||||
// interrupt if the statement is a let binding (`Local`) that shadows the original
|
||||
// binding
|
||||
if stmt_shadows_binding(consecutive_statement, binding_name) {
|
||||
break;
|
||||
}
|
||||
// find out if and which field was set by this `consecutive_statement`
|
||||
else if let Some((field_ident, assign_rhs)) =
|
||||
field_reassigned_by_stmt(consecutive_statement, binding_name)
|
||||
{
|
||||
if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) {
|
||||
// interrupt and cancel lint if assign_rhs references the original binding
|
||||
if contains_name(binding_name, assign_rhs) {
|
||||
cancel_lint = true;
|
||||
|
@ -152,7 +168,7 @@ impl LateLintPass<'_> for Default {
|
|||
first_assign = Some(consecutive_statement);
|
||||
}
|
||||
}
|
||||
// interrupt also if no field was assigned, since we only want to look at consecutive statements
|
||||
// interrupt if no field was assigned, since we only want to look at consecutive statements
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
@ -161,55 +177,45 @@ impl LateLintPass<'_> for Default {
|
|||
// if there are incorrectly assigned fields, do a span_lint_and_note to suggest
|
||||
// construction using `Ty { fields, ..Default::default() }`
|
||||
if !assigned_fields.is_empty() && !cancel_lint {
|
||||
// take the original assignment as span
|
||||
let stmt = &block.stmts[stmt_idx];
|
||||
// if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion.
|
||||
let ext_with_default = !variant
|
||||
.fields
|
||||
.iter()
|
||||
.all(|field| assigned_fields.iter().any(|(a, _)| a == &field.ident.name));
|
||||
|
||||
if let StmtKind::Local(preceding_local) = &stmt.kind {
|
||||
// filter out fields like `= Default::default()`, because the FRU already covers them
|
||||
let assigned_fields = assigned_fields
|
||||
.into_iter()
|
||||
.filter(|(_, rhs)| !is_expr_default(rhs, cx))
|
||||
.collect::<Vec<(Symbol, &Expr<'_>)>>();
|
||||
let field_list = assigned_fields
|
||||
.into_iter()
|
||||
.map(|(field, rhs)| {
|
||||
// extract and store the assigned value for help message
|
||||
let value_snippet = snippet(cx, rhs.span, "..");
|
||||
format!("{}: {}", field, value_snippet)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
|
||||
// if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion.
|
||||
let ext_with_default = !fields_of_type(binding_type)
|
||||
.iter()
|
||||
.all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));
|
||||
|
||||
let field_list = assigned_fields
|
||||
.into_iter()
|
||||
.map(|(field, rhs)| {
|
||||
// extract and store the assigned value for help message
|
||||
let value_snippet = snippet(cx, rhs.span, "..");
|
||||
format!("{}: {}", field, value_snippet)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
|
||||
let sugg = if ext_with_default {
|
||||
if field_list.is_empty() {
|
||||
format!("{}::default()", binding_type)
|
||||
} else {
|
||||
format!("{} {{ {}, ..Default::default() }}", binding_type, field_list)
|
||||
}
|
||||
let sugg = if ext_with_default {
|
||||
if field_list.is_empty() {
|
||||
format!("{}::default()", binding_type)
|
||||
} else {
|
||||
format!("{} {{ {} }}", binding_type, field_list)
|
||||
};
|
||||
format!("{} {{ {}, ..Default::default() }}", binding_type, field_list)
|
||||
}
|
||||
} else {
|
||||
format!("{} {{ {} }}", binding_type, field_list)
|
||||
};
|
||||
|
||||
// span lint once per statement that binds default
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
FIELD_REASSIGN_WITH_DEFAULT,
|
||||
first_assign.unwrap().span,
|
||||
"field assignment outside of initializer for an instance created with Default::default()",
|
||||
Some(preceding_local.span),
|
||||
&format!(
|
||||
"consider initializing the variable with `{}` and removing relevant reassignments",
|
||||
sugg
|
||||
),
|
||||
);
|
||||
self.reassigned_linted.insert(span);
|
||||
}
|
||||
// span lint once per statement that binds default
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
FIELD_REASSIGN_WITH_DEFAULT,
|
||||
first_assign.unwrap().span,
|
||||
"field assignment outside of initializer for an instance created with Default::default()",
|
||||
Some(local.span),
|
||||
&format!(
|
||||
"consider initializing the variable with `{}` and removing relevant reassignments",
|
||||
sugg
|
||||
),
|
||||
);
|
||||
self.reassigned_linted.insert(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,47 +236,6 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the block indices, identifiers and types of bindings set as `Default::default()`, except
|
||||
/// for when the pattern type is a tuple.
|
||||
fn enumerate_bindings_using_default<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
block: &Block<'tcx>,
|
||||
) -> Vec<(usize, Symbol, Ty<'tcx>, Span)> {
|
||||
block
|
||||
.stmts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, stmt)| {
|
||||
if_chain! {
|
||||
// only take `let ...` statements
|
||||
if let StmtKind::Local(ref local) = stmt.kind;
|
||||
// only take bindings to identifiers
|
||||
if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
|
||||
// that are not tuples
|
||||
let ty = cx.typeck_results().pat_ty(local.pat);
|
||||
if !matches!(ty.kind(), ty::Tuple(_));
|
||||
// only when assigning `... = Default::default()`
|
||||
if let Some(ref expr) = local.init;
|
||||
if is_expr_default(expr, cx);
|
||||
then {
|
||||
Some((idx, ident.name, ty, expr.span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn stmt_shadows_binding(this: &Stmt<'_>, shadowed: Symbol) -> bool {
|
||||
if let StmtKind::Local(local) = &this.kind {
|
||||
if let PatKind::Binding(_, _, ident, _) = local.pat.kind {
|
||||
return ident.name == shadowed;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns the reassigned field and the assigning expression (right-hand side of assign).
|
||||
fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
|
||||
if_chain! {
|
||||
|
@ -290,14 +255,3 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the vec of fields for a struct and an empty vec for non-struct ADTs.
|
||||
fn fields_of_type(ty: Ty<'_>) -> Vec<Ident> {
|
||||
if let Adt(adt, _) = ty.kind() {
|
||||
if adt.is_struct() {
|
||||
let variant = &adt.non_enum_variant();
|
||||
return variant.fields.iter().map(|f| f.ident).collect();
|
||||
}
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
|
|
83
clippy_lints/src/from_over_into.rs
Normal file
83
clippy_lints/src/from_over_into.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use crate::utils::paths::INTO;
|
||||
use crate::utils::{match_def_path, meets_msrv, span_lint_and_help};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
const FROM_OVER_INTO_MSRV: RustcVersion = RustcVersion::new(1, 41, 0);
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead.
|
||||
///
|
||||
/// **Why is this bad?** According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// struct StringWrapper(String);
|
||||
///
|
||||
/// impl Into<StringWrapper> for String {
|
||||
/// fn into(self) -> StringWrapper {
|
||||
/// StringWrapper(self)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// struct StringWrapper(String);
|
||||
///
|
||||
/// impl From<String> for StringWrapper {
|
||||
/// fn from(s: String) -> StringWrapper {
|
||||
/// StringWrapper(s)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub FROM_OVER_INTO,
|
||||
style,
|
||||
"Warns on implementations of `Into<..>` to use `From<..>`"
|
||||
}
|
||||
|
||||
pub struct FromOverInto {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl FromOverInto {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
FromOverInto { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
|
||||
|
||||
impl LateLintPass<'_> for FromOverInto {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &FROM_OVER_INTO_MSRV) {
|
||||
return;
|
||||
}
|
||||
|
||||
let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id);
|
||||
if_chain! {
|
||||
if let hir::ItemKind::Impl{ .. } = &item.kind;
|
||||
if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id);
|
||||
if match_def_path(cx, impl_trait_ref.def_id, &INTO);
|
||||
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
FROM_OVER_INTO,
|
||||
item.span,
|
||||
"an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
|
||||
None,
|
||||
"consider to implement `From` instead",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
|
@ -4,6 +4,7 @@ use crate::utils::{snippet_opt, span_lint_and_then};
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind, VariantData};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_target::abi::LayoutOf;
|
||||
|
||||
|
@ -58,6 +59,9 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if in_external_macro(cx.tcx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
let did = cx.tcx.hir().local_def_id(item.hir_id);
|
||||
if let ItemKind::Enum(ref def, _) = item.kind {
|
||||
let ty = cx.tcx.type_of(did);
|
||||
|
|
|
@ -207,6 +207,7 @@ mod float_literal;
|
|||
mod floating_point_arithmetic;
|
||||
mod format;
|
||||
mod formatting;
|
||||
mod from_over_into;
|
||||
mod functions;
|
||||
mod future_not_send;
|
||||
mod get_last_with_len;
|
||||
|
@ -614,6 +615,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
||||
&formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||
&formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
||||
&from_over_into::FROM_OVER_INTO,
|
||||
&functions::DOUBLE_MUST_USE,
|
||||
&functions::MUST_USE_CANDIDATE,
|
||||
&functions::MUST_USE_UNIT,
|
||||
|
@ -1014,6 +1016,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
|
||||
store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
|
||||
store.register_late_pass(move || box ranges::Ranges::new(msrv));
|
||||
store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
|
||||
store.register_late_pass(move || box use_self::UseSelf::new(msrv));
|
||||
store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
|
||||
|
||||
|
@ -1417,6 +1420,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
||||
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||
LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||
LintId::of(&from_over_into::FROM_OVER_INTO),
|
||||
LintId::of(&functions::DOUBLE_MUST_USE),
|
||||
LintId::of(&functions::MUST_USE_UNIT),
|
||||
LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
|
||||
|
@ -1663,6 +1667,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
||||
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||
LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||
LintId::of(&from_over_into::FROM_OVER_INTO),
|
||||
LintId::of(&functions::DOUBLE_MUST_USE),
|
||||
LintId::of(&functions::MUST_USE_UNIT),
|
||||
LintId::of(&functions::RESULT_UNIT_ERR),
|
||||
|
|
|
@ -105,7 +105,7 @@ impl MacroUseImports {
|
|||
impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
if_chain! {
|
||||
if cx.sess().opts.edition == Edition::Edition2018;
|
||||
if cx.sess().opts.edition >= Edition::Edition2018;
|
||||
if let hir::ItemKind::Use(path, _kind) = &item.kind;
|
||||
if let Some(mac_attr) = item
|
||||
.attrs
|
||||
|
|
|
@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
|
|||
|diag| {
|
||||
if_chain! {
|
||||
if let Some(header_snip) = snippet_opt(cx, header_span);
|
||||
if let Some(ret_pos) = position_before_rarrow(header_snip.clone());
|
||||
if let Some(ret_pos) = position_before_rarrow(&header_snip);
|
||||
if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
|
||||
then {
|
||||
let help = format!("make the function `async` and {}", ret_sugg);
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
|||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for instances of `map_err(|_| Some::Enum)`
|
||||
///
|
||||
/// **Why is this bad?** This map_err throws away the original error rather than allowing the enum to contain and report the cause of the error
|
||||
/// **Why is this bad?** This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
|
@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
|
|||
body_span,
|
||||
"`map_err(|_|...` wildcard pattern discards the original error",
|
||||
None,
|
||||
"Consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
|
||||
"consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,20 +182,6 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
|
|||
|
||||
if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
|
||||
if is_type_diagnostic_item(cx, ty, sym::vec_type) {
|
||||
let mut ty_snippet = None;
|
||||
if_chain! {
|
||||
if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
|
||||
if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
|
||||
then {
|
||||
let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
|
||||
GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
}).collect();
|
||||
if types.len() == 1 {
|
||||
ty_snippet = snippet_opt(cx, types[0].span);
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
@ -204,7 +190,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
|
|||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices.",
|
||||
|diag| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) {
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"change this to",
|
||||
|
@ -247,6 +233,33 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
|
|||
},
|
||||
);
|
||||
}
|
||||
} else if match_type(cx, ty, &paths::PATH_BUF) {
|
||||
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"change this to",
|
||||
"&Path".into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
for (clonespan, suggestion) in spans {
|
||||
diag.span_suggestion_short(
|
||||
clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
|
||||
Cow::Owned(format!("change `{}` to", x))
|
||||
}),
|
||||
suggestion.into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if match_type(cx, ty, &paths::COW) {
|
||||
if_chain! {
|
||||
if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
|
||||
|
@ -309,6 +322,23 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
|
|||
}
|
||||
}
|
||||
|
||||
fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> {
|
||||
if_chain! {
|
||||
if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
|
||||
if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
|
||||
let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
|
||||
GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
}).collect();
|
||||
if types.len() == 1;
|
||||
then {
|
||||
snippet_opt(cx, types[0].span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
|
||||
if let TyKind::Rptr(ref lt, ref m) = ty.kind {
|
||||
Some((lt, m.mutbl, ty.span))
|
||||
|
|
|
@ -40,7 +40,7 @@ impl EarlyLintPass for SingleComponentPathImports {
|
|||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
if_chain! {
|
||||
if !in_macro(item.span);
|
||||
if cx.sess.opts.edition == Edition::Edition2018;
|
||||
if cx.sess.opts.edition >= Edition::Edition2018;
|
||||
if !item.vis.kind.is_pub();
|
||||
if let ItemKind::Use(use_tree) = &item.kind;
|
||||
if let segments = &use_tree.prefix.segments;
|
||||
|
|
|
@ -120,7 +120,7 @@ fn is_unit_expr(expr: &ast::Expr) -> bool {
|
|||
|
||||
fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
|
||||
let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
|
||||
position_before_rarrow(fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
|
|
|
@ -501,8 +501,18 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
|||
&& match (&l.kind, &r.kind) {
|
||||
(Lifetime, Lifetime) => true,
|
||||
(Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
|
||||
(Const { ty: lt, kw_span: _ , default: ld}, Const { ty: rt, kw_span: _, default: rd }) =>
|
||||
eq_ty(lt, rt) && both(ld, rd, |ld, rd| eq_anon_const(ld, rd)),
|
||||
(
|
||||
Const {
|
||||
ty: lt,
|
||||
kw_span: _,
|
||||
default: ld,
|
||||
},
|
||||
Const {
|
||||
ty: rt,
|
||||
kw_span: _,
|
||||
default: rd,
|
||||
},
|
||||
) => eq_ty(lt, rt) && both(ld, rd, |ld, rd| eq_anon_const(ld, rd)),
|
||||
_ => false,
|
||||
}
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
|
|
|
@ -788,8 +788,7 @@ pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
|
|||
/// fn into3(self) -> () {}
|
||||
/// ^
|
||||
/// ```
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn position_before_rarrow(s: String) -> Option<usize> {
|
||||
pub fn position_before_rarrow(s: &str) -> Option<usize> {
|
||||
s.rfind("->").map(|rpos| {
|
||||
let mut rpos = rpos;
|
||||
let chars: Vec<char> = s.chars().collect();
|
||||
|
|
|
@ -72,7 +72,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2020-12-20"
|
||||
channel = "nightly-2021-01-02"
|
||||
components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]
|
||||
|
|
|
@ -84,3 +84,13 @@ macro_rules! as_conv {
|
|||
0u32 as u64
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! large_enum_variant {
|
||||
() => {
|
||||
enum LargeEnumInMacro {
|
||||
A(i32),
|
||||
B([i32; 8000]),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -107,4 +107,16 @@ fn main() {
|
|||
x.i = side_effect.next();
|
||||
x.j = 2;
|
||||
x.i = side_effect.next();
|
||||
|
||||
// don't lint - some private fields
|
||||
let mut x = m::F::default();
|
||||
x.a = 1;
|
||||
}
|
||||
|
||||
mod m {
|
||||
#[derive(Default)]
|
||||
pub struct F {
|
||||
pub a: u64,
|
||||
b: u64,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ error: field assignment outside of initializer for an instance created with Defa
|
|||
LL | a.i = Default::default();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: consider initializing the variable with `A::default()` and removing relevant reassignments
|
||||
note: consider initializing the variable with `A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
|
||||
--> $DIR/field_reassign_with_default.rs:90:5
|
||||
|
|
||||
LL | let mut a: A = Default::default();
|
||||
|
@ -65,7 +65,7 @@ error: field assignment outside of initializer for an instance created with Defa
|
|||
LL | a.i = Default::default();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: consider initializing the variable with `A { j: 45, ..Default::default() }` and removing relevant reassignments
|
||||
note: consider initializing the variable with `A { i: Default::default(), j: 45 }` and removing relevant reassignments
|
||||
--> $DIR/field_reassign_with_default.rs:94:5
|
||||
|
|
||||
LL | let mut a: A = Default::default();
|
||||
|
|
21
tests/ui/from_over_into.rs
Normal file
21
tests/ui/from_over_into.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
#![warn(clippy::from_over_into)]
|
||||
|
||||
// this should throw an error
|
||||
struct StringWrapper(String);
|
||||
|
||||
impl Into<StringWrapper> for String {
|
||||
fn into(self) -> StringWrapper {
|
||||
StringWrapper(self)
|
||||
}
|
||||
}
|
||||
|
||||
// this is fine
|
||||
struct A(String);
|
||||
|
||||
impl From<String> for A {
|
||||
fn from(s: String) -> A {
|
||||
A(s)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
15
tests/ui/from_over_into.stderr
Normal file
15
tests/ui/from_over_into.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into.rs:6:1
|
||||
|
|
||||
LL | / impl Into<StringWrapper> for String {
|
||||
LL | | fn into(self) -> StringWrapper {
|
||||
LL | | StringWrapper(self)
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= note: `-D clippy::from-over-into` implied by `-D warnings`
|
||||
= help: consider to implement `From` instead
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
// aux-build:macro_rules.rs
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![warn(clippy::large_enum_variant)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
||||
enum LargeEnum {
|
||||
A(i32),
|
||||
B([i32; 8000]),
|
||||
|
@ -51,4 +56,6 @@ enum LargeEnumOk {
|
|||
LargeB([i32; 8001]),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
large_enum_variant!();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
error: large size difference between variants
|
||||
--> $DIR/large_enum_variant.rs:7:5
|
||||
--> $DIR/large_enum_variant.rs:12:5
|
||||
|
|
||||
LL | B([i32; 8000]),
|
||||
| ^^^^^^^^^^^^^^ this variant is 32000 bytes
|
||||
|
|
||||
= note: `-D clippy::large-enum-variant` implied by `-D warnings`
|
||||
note: and the second-largest variant is 4 bytes:
|
||||
--> $DIR/large_enum_variant.rs:6:5
|
||||
--> $DIR/large_enum_variant.rs:11:5
|
||||
|
|
||||
LL | A(i32),
|
||||
| ^^^^^^
|
||||
|
@ -16,13 +16,13 @@ LL | B(Box<[i32; 8000]>),
|
|||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: large size difference between variants
|
||||
--> $DIR/large_enum_variant.rs:31:5
|
||||
--> $DIR/large_enum_variant.rs:36:5
|
||||
|
|
||||
LL | ContainingLargeEnum(LargeEnum),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
|
||||
|
|
||||
note: and the second-largest variant is 8 bytes:
|
||||
--> $DIR/large_enum_variant.rs:30:5
|
||||
--> $DIR/large_enum_variant.rs:35:5
|
||||
|
|
||||
LL | VariantOk(i32, u32),
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -32,30 +32,30 @@ LL | ContainingLargeEnum(Box<LargeEnum>),
|
|||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: large size difference between variants
|
||||
--> $DIR/large_enum_variant.rs:41:5
|
||||
--> $DIR/large_enum_variant.rs:46:5
|
||||
|
|
||||
LL | StructLikeLarge { x: [i32; 8000], y: i32 },
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
|
||||
|
|
||||
note: and the second-largest variant is 8 bytes:
|
||||
--> $DIR/large_enum_variant.rs:40:5
|
||||
--> $DIR/large_enum_variant.rs:45:5
|
||||
|
|
||||
LL | VariantOk(i32, u32),
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
help: consider boxing the large fields to reduce the total size of the enum
|
||||
--> $DIR/large_enum_variant.rs:41:5
|
||||
--> $DIR/large_enum_variant.rs:46:5
|
||||
|
|
||||
LL | StructLikeLarge { x: [i32; 8000], y: i32 },
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: large size difference between variants
|
||||
--> $DIR/large_enum_variant.rs:46:5
|
||||
--> $DIR/large_enum_variant.rs:51:5
|
||||
|
|
||||
LL | StructLikeLarge2 { x: [i32; 8000] },
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
|
||||
|
|
||||
note: and the second-largest variant is 8 bytes:
|
||||
--> $DIR/large_enum_variant.rs:45:5
|
||||
--> $DIR/large_enum_variant.rs:50:5
|
||||
|
|
||||
LL | VariantOk(i32, u32),
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -5,7 +5,7 @@ LL | println!("{:?}", x.map_err(|_| Errors::Ignored));
|
|||
| ^^^
|
||||
|
|
||||
= note: `-D clippy::map-err-ignore` implied by `-D warnings`
|
||||
= help: Consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)
|
||||
= help: consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -57,6 +57,14 @@ pub fn checked_conversion() {
|
|||
let _ = value <= (u32::MAX as i64) && value >= 0;
|
||||
}
|
||||
|
||||
pub struct FromOverInto(String);
|
||||
|
||||
impl Into<FromOverInto> for String {
|
||||
fn into(self) -> FromOverInto {
|
||||
FromOverInto(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filter_map_next() {
|
||||
let a = ["1", "lol", "3", "NaN", "5"];
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
error: stripping a prefix manually
|
||||
--> $DIR/min_rust_version_attr.rs:142:24
|
||||
--> $DIR/min_rust_version_attr.rs:150:24
|
||||
|
|
||||
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::manual-strip` implied by `-D warnings`
|
||||
note: the prefix was tested here
|
||||
--> $DIR/min_rust_version_attr.rs:141:9
|
||||
--> $DIR/min_rust_version_attr.rs:149:9
|
||||
|
|
||||
LL | if s.starts_with("hello, ") {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -17,13 +17,13 @@ LL | assert_eq!(<stripped>.to_uppercase(), "WORLD!");
|
|||
|
|
||||
|
||||
error: stripping a prefix manually
|
||||
--> $DIR/min_rust_version_attr.rs:154:24
|
||||
--> $DIR/min_rust_version_attr.rs:162:24
|
||||
|
|
||||
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the prefix was tested here
|
||||
--> $DIR/min_rust_version_attr.rs:153:9
|
||||
--> $DIR/min_rust_version_attr.rs:161:9
|
||||
|
|
||||
LL | if s.starts_with("hello, ") {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#![warn(clippy::ptr_arg)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn do_vec(x: &Vec<i64>) {
|
||||
//Nothing here
|
||||
|
@ -21,6 +22,15 @@ fn do_str_mut(x: &mut String) {
|
|||
//Nothing here either
|
||||
}
|
||||
|
||||
fn do_path(x: &PathBuf) {
|
||||
//Nothing here either
|
||||
}
|
||||
|
||||
fn do_path_mut(x: &mut PathBuf) {
|
||||
// no error here
|
||||
//Nothing here either
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
trait Foo {
|
||||
|
@ -55,6 +65,14 @@ fn str_cloned(x: &String) -> String {
|
|||
x.clone()
|
||||
}
|
||||
|
||||
fn path_cloned(x: &PathBuf) -> PathBuf {
|
||||
let a = x.clone();
|
||||
let b = x.clone();
|
||||
let c = b.clone();
|
||||
let d = a.clone().clone().clone();
|
||||
x.clone()
|
||||
}
|
||||
|
||||
fn false_positive_capacity(x: &Vec<u8>, y: &String) {
|
||||
let a = x.capacity();
|
||||
let b = y.clone();
|
||||
|
@ -87,10 +105,12 @@ impl Foo2 for String {
|
|||
// Check that the allow attribute on parameters is honored
|
||||
mod issue_5644 {
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn allowed(
|
||||
#[allow(clippy::ptr_arg)] _v: &Vec<u32>,
|
||||
#[allow(clippy::ptr_arg)] _s: &String,
|
||||
#[allow(clippy::ptr_arg)] _p: &PathBuf,
|
||||
#[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
|
||||
) {
|
||||
}
|
||||
|
@ -100,6 +120,7 @@ mod issue_5644 {
|
|||
fn allowed(
|
||||
#[allow(clippy::ptr_arg)] _v: &Vec<u32>,
|
||||
#[allow(clippy::ptr_arg)] _s: &String,
|
||||
#[allow(clippy::ptr_arg)] _p: &PathBuf,
|
||||
#[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
|
||||
) {
|
||||
}
|
||||
|
@ -109,8 +130,28 @@ mod issue_5644 {
|
|||
fn allowed(
|
||||
#[allow(clippy::ptr_arg)] _v: &Vec<u32>,
|
||||
#[allow(clippy::ptr_arg)] _s: &String,
|
||||
#[allow(clippy::ptr_arg)] _p: &PathBuf,
|
||||
#[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod issue6509 {
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn foo_vec(vec: &Vec<u8>) {
|
||||
let _ = vec.clone().pop();
|
||||
let _ = vec.clone().clone();
|
||||
}
|
||||
|
||||
fn foo_path(path: &PathBuf) {
|
||||
let _ = path.clone().pop();
|
||||
let _ = path.clone().clone();
|
||||
}
|
||||
|
||||
fn foo_str(str: &PathBuf) {
|
||||
let _ = str.clone().pop();
|
||||
let _ = str.clone().clone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
|
||||
--> $DIR/ptr_arg.rs:6:14
|
||||
--> $DIR/ptr_arg.rs:7:14
|
||||
|
|
||||
LL | fn do_vec(x: &Vec<i64>) {
|
||||
| ^^^^^^^^^ help: change this to: `&[i64]`
|
||||
|
@ -7,19 +7,25 @@ LL | fn do_vec(x: &Vec<i64>) {
|
|||
= note: `-D clippy::ptr-arg` implied by `-D warnings`
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:15:14
|
||||
--> $DIR/ptr_arg.rs:16:14
|
||||
|
|
||||
LL | fn do_str(x: &String) {
|
||||
| ^^^^^^^ help: change this to: `&str`
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:25:15
|
||||
|
|
||||
LL | fn do_path(x: &PathBuf) {
|
||||
| ^^^^^^^^ help: change this to: `&Path`
|
||||
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
|
||||
--> $DIR/ptr_arg.rs:28:18
|
||||
--> $DIR/ptr_arg.rs:38:18
|
||||
|
|
||||
LL | fn do_vec(x: &Vec<i64>);
|
||||
| ^^^^^^^^^ help: change this to: `&[i64]`
|
||||
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
|
||||
--> $DIR/ptr_arg.rs:41:14
|
||||
--> $DIR/ptr_arg.rs:51:14
|
||||
|
|
||||
LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
|
||||
| ^^^^^^^^
|
||||
|
@ -38,7 +44,7 @@ LL | x.to_owned()
|
|||
|
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:50:18
|
||||
--> $DIR/ptr_arg.rs:60:18
|
||||
|
|
||||
LL | fn str_cloned(x: &String) -> String {
|
||||
| ^^^^^^^
|
||||
|
@ -60,8 +66,31 @@ help: change `x.clone()` to
|
|||
LL | x.to_string()
|
||||
|
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:68:19
|
||||
|
|
||||
LL | fn path_cloned(x: &PathBuf) -> PathBuf {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn path_cloned(x: &Path) -> PathBuf {
|
||||
| ^^^^^
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let a = x.to_path_buf();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let b = x.to_path_buf();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | x.to_path_buf()
|
||||
|
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:58:44
|
||||
--> $DIR/ptr_arg.rs:76:44
|
||||
|
|
||||
LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
|
||||
| ^^^^^^^
|
||||
|
@ -80,10 +109,67 @@ LL | let c = y;
|
|||
| ^
|
||||
|
||||
error: using a reference to `Cow` is not recommended.
|
||||
--> $DIR/ptr_arg.rs:72:25
|
||||
--> $DIR/ptr_arg.rs:90:25
|
||||
|
|
||||
LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
|
||||
| ^^^^^^^^^^^ help: change this to: `&[i32]`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
|
||||
--> $DIR/ptr_arg.rs:143:21
|
||||
|
|
||||
LL | fn foo_vec(vec: &Vec<u8>) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn foo_vec(vec: &[u8]) {
|
||||
| ^^^^^
|
||||
help: change `vec.clone()` to
|
||||
|
|
||||
LL | let _ = vec.to_owned().pop();
|
||||
| ^^^^^^^^^^^^^^
|
||||
help: change `vec.clone()` to
|
||||
|
|
||||
LL | let _ = vec.to_owned().clone();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:148:23
|
||||
|
|
||||
LL | fn foo_path(path: &PathBuf) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn foo_path(path: &Path) {
|
||||
| ^^^^^
|
||||
help: change `path.clone()` to
|
||||
|
|
||||
LL | let _ = path.to_path_buf().pop();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
help: change `path.clone()` to
|
||||
|
|
||||
LL | let _ = path.to_path_buf().clone();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.
|
||||
--> $DIR/ptr_arg.rs:153:21
|
||||
|
|
||||
LL | fn foo_str(str: &PathBuf) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn foo_str(str: &Path) {
|
||||
| ^^^^^
|
||||
help: change `str.clone()` to
|
||||
|
|
||||
LL | let _ = str.to_path_buf().pop();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
help: change `str.clone()` to
|
||||
|
|
||||
LL | let _ = str.to_path_buf().clone();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#![deny(clippy::unused_unit)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::from_over_into)]
|
||||
|
||||
struct Unitter;
|
||||
impl Unitter {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#![deny(clippy::unused_unit)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::from_over_into)]
|
||||
|
||||
struct Unitter;
|
||||
impl Unitter {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:18:28
|
||||
--> $DIR/unused_unit.rs:19:28
|
||||
|
|
||||
LL | pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
@ -11,109 +11,109 @@ LL | #![deny(clippy::unused_unit)]
|
|||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:19:18
|
||||
--> $DIR/unused_unit.rs:20:18
|
||||
|
|
||||
LL | where G: Fn() -> () {
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:18:58
|
||||
--> $DIR/unused_unit.rs:19:58
|
||||
|
|
||||
LL | pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:20:26
|
||||
--> $DIR/unused_unit.rs:21:26
|
||||
|
|
||||
LL | let _y: &dyn Fn() -> () = &f;
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:27:18
|
||||
--> $DIR/unused_unit.rs:28:18
|
||||
|
|
||||
LL | fn into(self) -> () {
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit expression
|
||||
--> $DIR/unused_unit.rs:28:9
|
||||
--> $DIR/unused_unit.rs:29:9
|
||||
|
|
||||
LL | ()
|
||||
| ^^ help: remove the final `()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:33:29
|
||||
--> $DIR/unused_unit.rs:34:29
|
||||
|
|
||||
LL | fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:35:19
|
||||
--> $DIR/unused_unit.rs:36:19
|
||||
|
|
||||
LL | G: FnMut() -> (),
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:36:16
|
||||
--> $DIR/unused_unit.rs:37:16
|
||||
|
|
||||
LL | H: Fn() -> ();
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:40:29
|
||||
--> $DIR/unused_unit.rs:41:29
|
||||
|
|
||||
LL | fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:42:19
|
||||
--> $DIR/unused_unit.rs:43:19
|
||||
|
|
||||
LL | G: FnMut() -> (),
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:43:16
|
||||
--> $DIR/unused_unit.rs:44:16
|
||||
|
|
||||
LL | H: Fn() -> () {}
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:46:17
|
||||
--> $DIR/unused_unit.rs:47:17
|
||||
|
|
||||
LL | fn return_unit() -> () { () }
|
||||
| ^^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit expression
|
||||
--> $DIR/unused_unit.rs:46:26
|
||||
--> $DIR/unused_unit.rs:47:26
|
||||
|
|
||||
LL | fn return_unit() -> () { () }
|
||||
| ^^ help: remove the final `()`
|
||||
|
||||
error: unneeded `()`
|
||||
--> $DIR/unused_unit.rs:56:14
|
||||
--> $DIR/unused_unit.rs:57:14
|
||||
|
|
||||
LL | break();
|
||||
| ^^ help: remove the `()`
|
||||
|
||||
error: unneeded `()`
|
||||
--> $DIR/unused_unit.rs:58:11
|
||||
--> $DIR/unused_unit.rs:59:11
|
||||
|
|
||||
LL | return();
|
||||
| ^^ help: remove the `()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:75:10
|
||||
--> $DIR/unused_unit.rs:76:10
|
||||
|
|
||||
LL | fn test()->(){}
|
||||
| ^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:78:11
|
||||
--> $DIR/unused_unit.rs:79:11
|
||||
|
|
||||
LL | fn test2() ->(){}
|
||||
| ^^^^^ help: remove the `-> ()`
|
||||
|
||||
error: unneeded unit return type
|
||||
--> $DIR/unused_unit.rs:81:11
|
||||
--> $DIR/unused_unit.rs:82:11
|
||||
|
|
||||
LL | fn test3()-> (){}
|
||||
| ^^^^^ help: remove the `-> ()`
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#![allow(clippy::single_match_else)]
|
||||
use rustc_tools_util::VersionInfo;
|
||||
|
||||
#[test]
|
||||
fn check_that_clippy_lints_has_the_same_version_as_clippy() {
|
||||
let clippy_meta = cargo_metadata::MetadataCommand::new()
|
||||
|
@ -17,3 +20,53 @@ fn check_that_clippy_lints_has_the_same_version_as_clippy() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_that_clippy_has_the_same_major_version_as_rustc() {
|
||||
let clippy_version = rustc_tools_util::get_version_info!();
|
||||
let clippy_major = clippy_version.major;
|
||||
let clippy_minor = clippy_version.minor;
|
||||
let clippy_patch = clippy_version.patch;
|
||||
|
||||
// get the rustc version
|
||||
// this way the rust-toolchain file version is honored
|
||||
let rustc_version = String::from_utf8(
|
||||
std::process::Command::new("rustc")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`")
|
||||
.stdout,
|
||||
)
|
||||
.unwrap();
|
||||
// extract "1 XX 0" from "rustc 1.XX.0-nightly (<commit> <date>)"
|
||||
let vsplit: Vec<&str> = rustc_version
|
||||
.split(' ')
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.split('-')
|
||||
.next()
|
||||
.unwrap()
|
||||
.split('.')
|
||||
.collect();
|
||||
match vsplit.as_slice() {
|
||||
[rustc_major, rustc_minor, _rustc_patch] => {
|
||||
// clippy 0.1.XX should correspond to rustc 1.XX.0
|
||||
assert_eq!(clippy_major, 0); // this will probably stay the same for a long time
|
||||
assert_eq!(
|
||||
clippy_minor.to_string(),
|
||||
*rustc_major,
|
||||
"clippy minor version does not equal rustc major version"
|
||||
);
|
||||
assert_eq!(
|
||||
clippy_patch.to_string(),
|
||||
*rustc_minor,
|
||||
"clippy patch version does not equal rustc minor version"
|
||||
);
|
||||
// do not check rustc_patch because when a stable-patch-release is made (like 1.50.2),
|
||||
// we don't want our tests failing suddenly
|
||||
},
|
||||
_ => {
|
||||
panic!("Failed to parse rustc version: {:?}", vsplit);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
<div class="col-md-12 form-horizontal">
|
||||
<div class="input-group">
|
||||
<label class="input-group-addon" id="filter-label" for="filter-input">Filter:</label>
|
||||
<input type="text" class="form-control" placeholder="Keywords or search string" id="filter-input" ng-model="search" />
|
||||
<input type="text" class="form-control" placeholder="Keywords or search string" id="filter-input" ng-model="search" ng-model-options="{debounce: 50}"/>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="button" ng-click="search = ''">
|
||||
Clear
|
||||
|
@ -119,6 +119,7 @@
|
|||
{{title}}
|
||||
</h4>
|
||||
<div class="list-group-item-text" ng-bind-html="text | markdown"></div>
|
||||
<a ng-if="title == 'Known problems'" href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+is%3Aopen+{{lint.id}}">Search on GitHub</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
@ -180,6 +181,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
function searchLint(lint, term) {
|
||||
for (const field in lint.docs) {
|
||||
// Continue if it's not a property
|
||||
if (!lint.docs.hasOwnProperty(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Return if not found
|
||||
if (lint.docs[field].toLowerCase().indexOf(term) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
angular.module("clippy", [])
|
||||
.filter('markdown', function ($sce) {
|
||||
return function (text) {
|
||||
|
@ -216,40 +233,31 @@
|
|||
};
|
||||
|
||||
$scope.bySearch = function (lint, index, array) {
|
||||
let search_str = $scope.search;
|
||||
let searchStr = $scope.search;
|
||||
// It can be `null` I haven't missed this value
|
||||
if (search_str == null || search_str.length == 0) {
|
||||
if (searchStr == null || searchStr.length < 3) {
|
||||
return true;
|
||||
}
|
||||
search_str = search_str.toLowerCase();
|
||||
searchStr = searchStr.toLowerCase();
|
||||
|
||||
// Search by id
|
||||
let id_search = search_str.trim().replace(/(\-| )/g, "_");
|
||||
if (lint.id.includes(id_search)) {
|
||||
if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Search the description
|
||||
// The use of `for`-loops instead of `foreach` enables us to return early
|
||||
let search_lint = (lint, therm) => {
|
||||
for (const field in lint.docs) {
|
||||
// Continue if it's not a property
|
||||
if (!lint.docs.hasOwnProperty(field)) {
|
||||
continue;
|
||||
}
|
||||
let terms = searchStr.split(" ");
|
||||
for (index = 0; index < terms.length; index++) {
|
||||
if (lint.id.indexOf(terms[index]) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Return if not found
|
||||
if (lint.docs[field].toLowerCase().includes(therm)) {
|
||||
return true;
|
||||
}
|
||||
if (searchLint(lint, terms[index])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
let therms = search_str.split(" ");
|
||||
for (index = 0; index < therms.length; index++) {
|
||||
if (!search_lint(lint, therms[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue