Skip to content

Commit df73348

Browse files
author
Michael Wright
committed
Merge branch 'master' into fix-3514
2 parents c6505aa + 379c934 commit df73348

File tree

470 files changed

+7028
-6737
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

470 files changed

+7028
-6737
lines changed

.travis.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,6 @@ env:
1818
global:
1919
- RUST_BACKTRACE=1
2020

21-
before_install:
22-
- |
23-
# work-around for issue https://github.com/travis-ci/travis-ci/issues/6307
24-
# might not be necessary in the future
25-
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
26-
command curl -sSL https://rvm.io/mpapis.asc | gpg --import -
27-
rvm get stable
28-
fi
29-
3021
install:
3122
- |
3223
if [ -z ${INTEGRATION} ]; then

CONTRIBUTING.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ All contributors are expected to follow the [Rust Code of Conduct](http://www.ru
1919
* [Running test suite](#running-test-suite)
2020
* [Running rustfmt](#running-rustfmt)
2121
* [Testing manually](#testing-manually)
22-
* [Linting Clippy with your local changes](#linting-clippy-with-your-local-changes)
2322
* [How Clippy works](#how-clippy-works)
2423
* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust)
2524
* [Issue and PR Triage](#issue-and-pr-triage)

README.md

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ script:
106106
# etc.
107107
```
108108

109-
It might happen that clippy is not available for a certain nightly release.
110-
In this case you can try to conditionally install clippy from the git repo.
109+
It might happen that Clippy is not available for a certain nightly release.
110+
In this case you can try to conditionally install Clippy from the git repo.
111111

112112
```yaml
113113
language: rust
@@ -149,21 +149,7 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
149149

150150
Note: `deny` produces errors instead of warnings.
151151

152-
Note: To use the new `clippy::lint_name` syntax, a recent compiler has to be used
153-
currently. If you want to compile your code with the stable toolchain you can use a `cfg_attr` to
154-
activate the `tool_lints` feature:
155-
```rust
156-
#![cfg_attr(feature = "cargo-clippy", allow(clippy::lint_name))]
157-
```
158-
159-
For this to work you have to use Clippy on the nightly toolchain: `cargo +nightly clippy`. If you
160-
want to use Clippy with the stable toolchain, you can stick to the old unscoped method to
161-
enable/disable Clippy lints until `tool_lints` are stable:
162-
```rust
163-
#![cfg_attr(feature = "cargo-clippy", allow(clippy_lint))]
164-
```
165-
166-
If you do not want to include your lint levels in your code, you can globally enable/disable lints by passing extra flags to clippy during the run: `cargo clippy -- -A lint_name` will run clippy with `lint_name` disabled and `cargo clippy -- -W lint_name` will run it with that enabled. On newer compilers you may need to use `clippy::lint_name` instead.
152+
If you do not want to include your lint levels in your code, you can globally enable/disable lints by passing extra flags to Clippy during the run: `cargo clippy -- -A clippy::lint_name` will run Clippy with `lint_name` disabled and `cargo clippy -- -W clippy::lint_name` will run it with that enabled. This also works with lint groups. For example you can run Clippy with warnings for all lints enabled: `cargo clippy -- -W clippy::pedantic`
167153

168154
## License
169155

ci/base-tests.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,20 @@ cd clippy_dev && cargo test && cd ..
2929
# Perform various checks for lint registration
3030
./util/dev update_lints --check
3131
cargo +nightly fmt --all -- --check
32+
33+
34+
#avoid loop spam
35+
set +x
36+
# make sure tests are formatted
37+
38+
# some lints are sensitive to formatting, exclude some files
39+
needs_formatting=false
40+
for file in `find tests -not -path "tests/ui/methods.rs" -not -path "tests/ui/format.rs" -not -path "tests/ui/formatting.rs" -not -path "tests/ui/empty_line_after_outer_attribute.rs" -not -path "tests/ui/double_parens.rs" -not -path "tests/ui/doc.rs" -not -path "tests/ui/unused_unit.rs" | grep "\.rs$"` ; do
41+
rustfmt ${file} --check || echo "${file} needs reformatting!" ; needs_formatting=true
42+
done
43+
44+
if [ "${needs_reformatting}" = true ] ; then
45+
echo "Tests need reformatting!"
46+
exit 2
47+
fi
48+
set -x

clippy_lints/src/doc.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
238238
}
239239

240240
fn check_text(cx: &EarlyContext<'_>, valid_idents: &[String], text: &str, span: Span) {
241-
for word in text.split_whitespace() {
241+
for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
242242
// Trim punctuation as in `some comment (see foo::bar).`
243243
// ^^
244244
// Or even as in `_foo bar_` which is emphasized.
@@ -281,6 +281,10 @@ fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) {
281281
s != "_" && !s.contains("\\_") && s.contains('_')
282282
}
283283

284+
fn has_hyphen(s: &str) -> bool {
285+
s != "-" && s.contains('-')
286+
}
287+
284288
if let Ok(url) = Url::parse(word) {
285289
// try to get around the fact that `foo::bar` parses as a valid URL
286290
if !url.cannot_be_a_base() {
@@ -295,6 +299,11 @@ fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) {
295299
}
296300
}
297301

302+
// We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
303+
if has_underscore(word) && has_hyphen(word) {
304+
return;
305+
}
306+
298307
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
299308
span_lint(
300309
cx,

clippy_lints/src/explicit_write.rs

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
use crate::rustc::hir::*;
1111
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
1212
use crate::rustc::{declare_tool_lint, lint_array};
13-
use crate::utils::opt_def_id;
14-
use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint};
13+
use crate::rustc_errors::Applicability;
14+
use crate::syntax::ast::LitKind;
15+
use crate::utils::{is_expn_of, match_def_path, opt_def_id, resolve_node, span_lint, span_lint_and_sugg};
1516
use if_chain::if_chain;
1617

1718
/// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
@@ -81,32 +82,85 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
8182
} else {
8283
""
8384
};
84-
if let Some(macro_name) = calling_macro {
85-
span_lint(
86-
cx,
87-
EXPLICIT_WRITE,
88-
expr.span,
89-
&format!(
90-
"use of `{}!({}(), ...).unwrap()`. Consider using `{}{}!` instead",
91-
macro_name,
92-
dest_name,
93-
prefix,
94-
macro_name.replace("write", "print")
95-
)
96-
);
85+
86+
// We need to remove the last trailing newline from the string because the
87+
// underlying `fmt::write` function doesn't know whether `println!` or `print!` was
88+
// used.
89+
if let Some(mut write_output) = write_output_string(write_args) {
90+
if write_output.ends_with('\n') {
91+
write_output.pop();
92+
}
93+
94+
if let Some(macro_name) = calling_macro {
95+
span_lint_and_sugg(
96+
cx,
97+
EXPLICIT_WRITE,
98+
expr.span,
99+
&format!(
100+
"use of `{}!({}(), ...).unwrap()`",
101+
macro_name,
102+
dest_name
103+
),
104+
"try this",
105+
format!("{}{}!(\"{}\")", prefix, macro_name.replace("write", "print"), write_output.escape_default()),
106+
Applicability::MachineApplicable
107+
);
108+
} else {
109+
span_lint_and_sugg(
110+
cx,
111+
EXPLICIT_WRITE,
112+
expr.span,
113+
&format!("use of `{}().write_fmt(...).unwrap()`", dest_name),
114+
"try this",
115+
format!("{}print!(\"{}\")", prefix, write_output.escape_default()),
116+
Applicability::MachineApplicable
117+
);
118+
}
97119
} else {
98-
span_lint(
99-
cx,
100-
EXPLICIT_WRITE,
101-
expr.span,
102-
&format!(
103-
"use of `{}().write_fmt(...).unwrap()`. Consider using `{}print!` instead",
104-
dest_name,
105-
prefix,
106-
)
107-
);
120+
// We don't have a proper suggestion
121+
if let Some(macro_name) = calling_macro {
122+
span_lint(
123+
cx,
124+
EXPLICIT_WRITE,
125+
expr.span,
126+
&format!(
127+
"use of `{}!({}(), ...).unwrap()`. Consider using `{}{}!` instead",
128+
macro_name,
129+
dest_name,
130+
prefix,
131+
macro_name.replace("write", "print")
132+
)
133+
);
134+
} else {
135+
span_lint(
136+
cx,
137+
EXPLICIT_WRITE,
138+
expr.span,
139+
&format!("use of `{}().write_fmt(...).unwrap()`. Consider using `{}print!` instead", dest_name, prefix),
140+
);
141+
}
108142
}
143+
109144
}
110145
}
111146
}
112147
}
148+
149+
// Extract the output string from the given `write_args`.
150+
fn write_output_string(write_args: &HirVec<Expr>) -> Option<String> {
151+
if_chain! {
152+
// Obtain the string that should be printed
153+
if write_args.len() > 1;
154+
if let ExprKind::Call(_, ref output_args) = write_args[1].node;
155+
if output_args.len() > 0;
156+
if let ExprKind::AddrOf(_, ref output_string_expr) = output_args[0].node;
157+
if let ExprKind::Array(ref string_exprs) = output_string_expr.node;
158+
if string_exprs.len() > 0;
159+
if let ExprKind::Lit(ref lit) = string_exprs[0].node;
160+
if let LitKind::Str(ref write_output, _) = lit.node;
161+
then {
162+
return Some(write_output.to_string())
163+
}
164+
}
165+
None
166+
}

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![feature(slice_patterns)]
1515
#![feature(stmt_expr_attributes)]
1616
#![feature(range_contains)]
17+
#![feature(str_escape)]
1718
#![allow(clippy::missing_docs_in_private_items)]
1819
#![recursion_limit = "256"]
1920
#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]

clippy_lints/src/new_without_default.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::rustc_errors::Applicability;
1717
use crate::syntax::source_map::Span;
1818
use crate::utils::paths;
1919
use crate::utils::sugg::DiagnosticBuilderExt;
20-
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then};
20+
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_node_and_then};
2121
use if_chain::if_chain;
2222

2323
/// **What it does:** Checks for types with a `fn new() -> Self` method and no
@@ -165,9 +165,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
165165
}
166166

167167
if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
168-
span_lint_and_then(
168+
span_lint_node_and_then(
169169
cx,
170170
NEW_WITHOUT_DEFAULT_DERIVE,
171+
id,
171172
impl_item.span,
172173
&format!(
173174
"you should consider deriving a `Default` implementation for `{}`",
@@ -183,9 +184,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
183184
);
184185
});
185186
} else {
186-
span_lint_and_then(
187+
span_lint_node_and_then(
187188
cx,
188189
NEW_WITHOUT_DEFAULT,
190+
id,
189191
impl_item.span,
190192
&format!(
191193
"you should consider adding a `Default` implementation for `{}`",

clippy_lints/src/partialeq_ne_impl.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use crate::rustc::hir::*;
1111
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
1212
use crate::rustc::{declare_tool_lint, lint_array};
13-
use crate::utils::{is_automatically_derived, span_lint};
13+
use crate::utils::{is_automatically_derived, span_lint_node};
1414
use if_chain::if_chain;
1515

1616
/// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
@@ -56,10 +56,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
5656
then {
5757
for impl_item in impl_items {
5858
if impl_item.ident.name == "ne" {
59-
span_lint(cx,
60-
PARTIALEQ_NE_IMPL,
61-
impl_item.span,
62-
"re-implementing `PartialEq::ne` is unnecessary")
59+
span_lint_node(
60+
cx,
61+
PARTIALEQ_NE_IMPL,
62+
impl_item.id.node_id,
63+
impl_item.span,
64+
"re-implementing `PartialEq::ne` is unnecessary",
65+
);
6366
}
6467
}
6568
}

clippy_lints/src/question_mark.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use if_chain::if_chain;
1717

1818
use crate::rustc_errors::Applicability;
1919
use crate::utils::paths::*;
20-
use crate::utils::{match_def_path, match_type, span_lint_and_then};
20+
use crate::utils::{match_def_path, match_type, span_lint_and_then, SpanlessEq};
2121

2222
/// **What it does:** Checks for expressions that could be replaced by the question mark operator
2323
///
@@ -64,14 +64,40 @@ impl Pass {
6464
/// If it matches, it will suggest to use the question mark operator instead
6565
fn check_is_none_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr) {
6666
if_chain! {
67-
if let ExprKind::If(ref if_expr, ref body, _) = expr.node;
68-
if let ExprKind::MethodCall(ref segment, _, ref args) = if_expr.node;
67+
if let ExprKind::If(if_expr, body, else_) = &expr.node;
68+
if let ExprKind::MethodCall(segment, _, args) = &if_expr.node;
6969
if segment.ident.name == "is_none";
7070
if Self::expression_returns_none(cx, body);
7171
if let Some(subject) = args.get(0);
7272
if Self::is_option(cx, subject);
7373

7474
then {
75+
if let Some(else_) = else_ {
76+
if_chain! {
77+
if let ExprKind::Block(block, None) = &else_.node;
78+
if block.stmts.len() == 0;
79+
if let Some(block_expr) = &block.expr;
80+
if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
81+
then {
82+
span_lint_and_then(
83+
cx,
84+
QUESTION_MARK,
85+
expr.span,
86+
"this block may be rewritten with the `?` operator",
87+
|db| {
88+
db.span_suggestion_with_applicability(
89+
expr.span,
90+
"replace_it_with",
91+
format!("Some({}?)", Sugg::hir(cx, subject, "..")),
92+
Applicability::MaybeIncorrect, // snippet
93+
);
94+
}
95+
)
96+
}
97+
}
98+
return;
99+
}
100+
75101
span_lint_and_then(
76102
cx,
77103
QUESTION_MARK,
@@ -84,7 +110,7 @@ impl Pass {
84110
expr.span,
85111
"replace_it_with",
86112
format!("{}?;", receiver_str),
87-
Applicability::MachineApplicable, // snippet
113+
Applicability::MaybeIncorrect, // snippet
88114
);
89115
}
90116
)
@@ -133,9 +159,13 @@ impl Pass {
133159
}
134160
}
135161

136-
// Check if the block has an implicit return expression
137-
if let Some(ref ret_expr) = block.expr {
138-
return Some(ret_expr.clone());
162+
// Check for `return` without a semicolon.
163+
if_chain! {
164+
if block.stmts.len() == 0;
165+
if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.node);
166+
then {
167+
return Some(ret_expr.clone());
168+
}
139169
}
140170

141171
None

clippy_lints/src/redundant_field_names.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ impl EarlyLintPass for RedundantFieldNames {
5757
continue;
5858
}
5959
if let ExprKind::Path(None, path) = &field.expr.node {
60-
if path.segments.len() == 1 && path.segments[0].ident == field.ident {
60+
if path.segments.len() == 1
61+
&& path.segments[0].ident == field.ident
62+
&& path.segments[0].args.is_none()
63+
{
6164
span_lint_and_sugg(
6265
cx,
6366
REDUNDANT_FIELD_NAMES,

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ define_Conf! {
137137
"iOS", "macOS",
138138
"TeX", "LaTeX", "BibTeX", "BibLaTeX",
139139
"MinGW",
140+
"CamelCase",
140141
] => Vec<String>),
141142
/// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
142143
(too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),

0 commit comments

Comments
 (0)