mirror of https://github.com/rust-lang/rust.git
Merge branch 'master' into no_effect_with_drop
This commit is contained in:
commit
fcdce8fc1d
|
@ -28,6 +28,7 @@ script:
|
|||
- cargo test --features debugging
|
||||
- mkdir -p ~/rust/cargo/bin
|
||||
- cp target/debug/cargo-clippy ~/rust/cargo/bin/cargo-clippy
|
||||
- cp target/debug/clippy-driver ~/rust/cargo/bin/clippy-driver
|
||||
- PATH=$PATH:~/rust/cargo/bin cargo clippy --all -- -D clippy
|
||||
- cd clippy_workspace_tests && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ..
|
||||
- cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../..
|
||||
|
|
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -1,6 +1,22 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 0.0.165
|
||||
* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
|
||||
* New lint: [`mut_range_bound`]
|
||||
|
||||
## 0.0.164
|
||||
* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
|
||||
* New lint: [`int_plus_one`]
|
||||
|
||||
## 0.0.163
|
||||
* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
|
||||
|
||||
## 0.0.162
|
||||
* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
|
||||
* New lint: [`chars_last_cmp`]
|
||||
* Improved suggestions for [`needless_borrow`], [`ptr_arg`],
|
||||
|
||||
## 0.0.161
|
||||
* Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
|
||||
|
||||
|
@ -457,6 +473,7 @@ All notable changes to this project will be documented in this file.
|
|||
[`cast_precision_loss`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_precision_loss
|
||||
[`cast_sign_loss`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_sign_loss
|
||||
[`char_lit_as_u8`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#char_lit_as_u8
|
||||
[`chars_last_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#chars_last_cmp
|
||||
[`chars_next_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#chars_next_cmp
|
||||
[`clone_double_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_double_ref
|
||||
[`clone_on_copy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_on_copy
|
||||
|
@ -510,6 +527,7 @@ All notable changes to this project will be documented in this file.
|
|||
[`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask
|
||||
[`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter
|
||||
[`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always
|
||||
[`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one
|
||||
[`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic
|
||||
[`invalid_regex`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_regex
|
||||
[`invalid_upcast_comparisons`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
|
||||
|
@ -547,6 +565,7 @@ All notable changes to this project will be documented in this file.
|
|||
[`modulo_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#modulo_one
|
||||
[`mut_from_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_from_ref
|
||||
[`mut_mut`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_mut
|
||||
[`mut_range_bound`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_range_bound
|
||||
[`mutex_atomic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mutex_atomic
|
||||
[`mutex_integer`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mutex_integer
|
||||
[`naive_bytecount`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#naive_bytecount
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[root]
|
||||
name = "clippy_lints"
|
||||
version = "0.0.161"
|
||||
version = "0.0.165"
|
||||
dependencies = [
|
||||
"itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -9,10 +9,11 @@ dependencies = [
|
|||
"quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -28,22 +29,22 @@ name = "backtrace"
|
|||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.12"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -61,11 +62,16 @@ name = "cargo_metadata"
|
|||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.2"
|
||||
|
@ -73,17 +79,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.0.161"
|
||||
version = "0.0.165"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy-mini-macro-test 0.1.0",
|
||||
"clippy_lints 0.0.161",
|
||||
"clippy_lints 0.0.165",
|
||||
"compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -137,16 +143,21 @@ dependencies = [
|
|||
"backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.6.2"
|
||||
|
@ -157,7 +168,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -181,7 +192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.30"
|
||||
version = "0.2.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -199,7 +210,7 @@ name = "memchr"
|
|||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -209,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -228,6 +239,11 @@ dependencies = [
|
|||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.0.15"
|
||||
|
@ -289,12 +305,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -317,9 +333,9 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -328,7 +344,7 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -364,7 +380,15 @@ name = "toml"
|
|||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -385,6 +409,16 @@ dependencies = [
|
|||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.0"
|
||||
|
@ -408,10 +442,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
[metadata]
|
||||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983"
|
||||
"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"
|
||||
"checksum backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c63ea141ef8fdb10409d0f5daf30ac51f84ef43bff66f16627773d2a292cd189"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
|
||||
"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2741d378feb7a434dba54228c89a70b4e427fee521de67cdda3750b8a0265f5a"
|
||||
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||
|
@ -419,20 +454,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c"
|
||||
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
|
||||
"checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46"
|
||||
"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a"
|
||||
"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9"
|
||||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
||||
"checksum itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22c285d60139cf413244894189ca52debcfd70b57966feed060da76802e415a0"
|
||||
"checksum itoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ac17257442c2ed77dbc9fd555cf83c58b0c7f7d0e8f2ae08c0ac05c72842e1f6"
|
||||
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
||||
"checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b"
|
||||
"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915"
|
||||
"checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487"
|
||||
"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0"
|
||||
"checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1"
|
||||
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
|
||||
"checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b"
|
||||
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
|
@ -442,8 +478,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb6a7637a47663ee073391a139ed07851f27ed2532c2abc88c6bf27a16cdf34"
|
||||
"checksum serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "812ff66056fd9a9a5b7c119714243b0862cf98340e7d4b5ee05a932c40d5ea6c"
|
||||
"checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799"
|
||||
"checksum serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1afcaae083fd1c46952a315062326bc9957f182358eb7da03b57ef1c688f7aa9"
|
||||
"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58"
|
||||
"checksum serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d243424e06f9f9c39e3cd36147470fd340db785825e367625f79298a6ac6b7ac"
|
||||
"checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc"
|
||||
|
@ -451,9 +487,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.0.161"
|
||||
version = "0.0.165"
|
||||
authors = [
|
||||
"Manish Goregaokar <manishsmail@gmail.com>",
|
||||
"Andre Bogus <bogusandre@gmail.com>",
|
||||
|
@ -14,6 +14,7 @@ readme = "README.md"
|
|||
license = "MPL-2.0"
|
||||
keywords = ["clippy", "lint", "plugin"]
|
||||
categories = ["development-tools", "development-tools::cargo-plugins"]
|
||||
build = "build.rs"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "rust-lang-nursery/rust-clippy" }
|
||||
|
@ -29,9 +30,14 @@ name = "cargo-clippy"
|
|||
test = false
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "clippy-driver"
|
||||
test = false
|
||||
path = "src/driver.rs"
|
||||
|
||||
[dependencies]
|
||||
# begin automatic update
|
||||
clippy_lints = { version = "0.0.161", path = "clippy_lints" }
|
||||
clippy_lints = { version = "0.0.165", path = "clippy_lints" }
|
||||
# end automatic update
|
||||
cargo_metadata = "0.2"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ Steps to publish a new clippy version
|
|||
- `git push`
|
||||
- Wait for Travis's approval.
|
||||
- Merge.
|
||||
- `cargo publish` in `./clippy_clints`.
|
||||
- `cargo publish` in `./clippy_lints`.
|
||||
- `cargo publish` in the root directory.
|
||||
- `git pull`.
|
||||
- `git tag -s v0.0.X -m "v0.0.X"`.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
use std::env;
|
||||
|
||||
fn main() {
|
||||
// Forward the profile to the main compilation
|
||||
println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
|
||||
// Don't rebuild even if nothing changed
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
# begin automatic update
|
||||
version = "0.0.161"
|
||||
version = "0.0.165"
|
||||
# end automatic update
|
||||
authors = [
|
||||
"Manish Goregaokar <manishsmail@gmail.com>",
|
||||
|
@ -28,6 +28,7 @@ serde_derive = "1.0"
|
|||
toml = "0.4"
|
||||
unicode-normalization = "0.1"
|
||||
pulldown-cmark = "0.0.15"
|
||||
url = "1.5.0"
|
||||
|
||||
[features]
|
||||
debugging = []
|
||||
|
|
|
@ -90,7 +90,17 @@ declare_lint! {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct BitMask;
|
||||
pub struct BitMask {
|
||||
verbose_bit_mask_threshold: u64,
|
||||
}
|
||||
|
||||
impl BitMask {
|
||||
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
|
||||
Self {
|
||||
verbose_bit_mask_threshold: verbose_bit_mask_threshold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LintPass for BitMask {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
|
@ -119,6 +129,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
|
|||
let Expr_::ExprLit(ref lit1) = right.node,
|
||||
let LitKind::Int(0, _) = lit1.node,
|
||||
n.leading_zeros() == n.count_zeros(),
|
||||
n > u128::from(self.verbose_bit_mask_threshold),
|
||||
], {
|
||||
span_lint_and_then(cx,
|
||||
VERBOSE_BIT_MASK,
|
||||
|
@ -307,7 +318,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u128> {
|
|||
cx.tcx.mir_const_qualif(def_id);
|
||||
cx.tcx.hir.body(cx.tcx.hir.body_owned_by(id))
|
||||
} else {
|
||||
cx.tcx.extern_const_body(def_id)
|
||||
cx.tcx.extern_const_body(def_id).body
|
||||
};
|
||||
fetch_int_literal(cx, &body.value)
|
||||
})
|
||||
|
|
|
@ -298,7 +298,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
|
|||
self.tcx.mir_const_qualif(def_id);
|
||||
self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
|
||||
} else {
|
||||
self.tcx.extern_const_body(def_id)
|
||||
self.tcx.extern_const_body(def_id).body
|
||||
};
|
||||
let ret = cx.expr(&body.value);
|
||||
if ret.is_some() {
|
||||
|
|
|
@ -5,6 +5,7 @@ use syntax::ast;
|
|||
use syntax::codemap::{BytePos, Span};
|
||||
use syntax_pos::Pos;
|
||||
use utils::span_lint;
|
||||
use url::Url;
|
||||
|
||||
/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
|
||||
/// outside ticks in documentation.
|
||||
|
@ -195,16 +196,26 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
|
|||
use pulldown_cmark::Tag::*;
|
||||
|
||||
let mut in_code = false;
|
||||
let mut in_link = None;
|
||||
|
||||
for (offset, event) in docs {
|
||||
match event {
|
||||
Start(CodeBlock(_)) | Start(Code) => in_code = true,
|
||||
End(CodeBlock(_)) | End(Code) => in_code = false,
|
||||
Start(_tag) | End(_tag) => (), // We don't care about other tags
|
||||
Start(Link(link, _)) => in_link = Some(link),
|
||||
End(Link(_, _)) => in_link = None,
|
||||
Start(_tag) | End(_tag) => (), // We don't care about other tags
|
||||
Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it
|
||||
SoftBreak => (),
|
||||
HardBreak => (),
|
||||
FootnoteReference(text) | Text(text) => {
|
||||
if Some(&text) == in_link.as_ref() {
|
||||
// Probably a link of the form `<http://example.com>`
|
||||
// Which are represented as a link to "http://example.com" with
|
||||
// text "http://example.com" by pulldown-cmark
|
||||
continue;
|
||||
}
|
||||
|
||||
if !in_code {
|
||||
let index = match spans.binary_search_by(|c| c.0.cmp(&offset)) {
|
||||
Ok(o) => o,
|
||||
|
@ -270,6 +281,18 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) {
|
|||
s != "_" && !s.contains("\\_") && s.contains('_')
|
||||
}
|
||||
|
||||
if let Ok(url) = Url::parse(word) {
|
||||
// try to get around the fact that `foo::bar` parses as a valid URL
|
||||
if !url.cannot_be_a_base() {
|
||||
span_lint(cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
"you should put bare URLs between `<`/`>` or make a proper Markdown link");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
|
||||
span_lint(
|
||||
cx,
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use rustc::hir::*;
|
||||
use rustc::hir::map::Node::NodeItem;
|
||||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use syntax::ast::LitKind;
|
||||
use syntax::symbol::InternedString;
|
||||
use utils::paths;
|
||||
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty, opt_def_id};
|
||||
|
||||
|
@ -50,8 +48,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)),
|
||||
match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1),
|
||||
// ensure the format string is `"{..}"` with only one argument and no text
|
||||
check_static_str(cx, &args[0]),
|
||||
check_static_str(&args[0]),
|
||||
// ensure the format argument is `{}` ie. Display with no fancy option
|
||||
// and that the argument is a string
|
||||
check_arg_is_display(cx, &args[1])
|
||||
], {
|
||||
span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
|
||||
|
@ -69,44 +68,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the slice of format string parts in an `Arguments::new_v1` call.
|
||||
/// Public because it's shared with a lint in print.rs.
|
||||
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) -> Option<Vec<InternedString>> {
|
||||
/// Checks if the expressions matches `&[""]`
|
||||
fn check_static_str(expr: &Expr) -> bool {
|
||||
if_let_chain! {[
|
||||
let ExprBlock(ref block) = expr.node,
|
||||
block.stmts.len() == 1,
|
||||
let StmtDecl(ref decl, _) = block.stmts[0].node,
|
||||
let DeclItem(ref decl) = decl.node,
|
||||
let Some(NodeItem(decl)) = cx.tcx.hir.find(decl.id),
|
||||
decl.name == "__STATIC_FMTSTR",
|
||||
let ItemStatic(_, _, ref expr) = decl.node,
|
||||
let ExprAddrOf(_, ref expr) = cx.tcx.hir.body(*expr).value.node, // &["…", "…", …]
|
||||
let ExprArray(ref exprs) = expr.node,
|
||||
let ExprAddrOf(_, ref expr) = expr.node, // &[""]
|
||||
let ExprArray(ref exprs) = expr.node, // [""]
|
||||
exprs.len() == 1,
|
||||
let ExprLit(ref lit) = exprs[0].node,
|
||||
let LitKind::Str(ref lit, _) = lit.node,
|
||||
], {
|
||||
let mut result = Vec::new();
|
||||
for expr in exprs {
|
||||
if let ExprLit(ref lit) = expr.node {
|
||||
if let LitKind::Str(ref lit, _) = lit.node {
|
||||
result.push(lit.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Some(result);
|
||||
return lit.as_str().is_empty();
|
||||
}}
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks if the expressions matches
|
||||
/// ```rust, ignore
|
||||
/// { static __STATIC_FMTSTR: &'static[&'static str] = &["a", "b", c];
|
||||
/// __STATIC_FMTSTR }
|
||||
/// ```
|
||||
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
|
||||
if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
|
||||
expr.len() == 1 && expr[0].is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks if the expressions matches
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use syntax::ast::NodeId;
|
||||
use utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, span_lint_and_then};
|
||||
use utils::{opt_def_id, paths, resolve_node};
|
||||
|
||||
/// **What it does:** Checks for always-identical `Into`/`From` conversions.
|
||||
///
|
||||
/// **Why is this bad?** Redundant code.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// // format!() returns a `String`
|
||||
/// let s: String = format!("hello").into();
|
||||
/// ```
|
||||
declare_lint! {
|
||||
pub IDENTITY_CONVERSION,
|
||||
Warn,
|
||||
"using always-identical `Into`/`From` conversions"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct IdentityConversion {
|
||||
try_desugar_arm: Vec<NodeId>,
|
||||
}
|
||||
|
||||
impl LintPass for IdentityConversion {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(IDENTITY_CONVERSION)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
|
||||
if in_macro(e.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if Some(&e.id) == self.try_desugar_arm.last() {
|
||||
return;
|
||||
}
|
||||
|
||||
match e.node {
|
||||
ExprMatch(_, ref arms, MatchSource::TryDesugar) => {
|
||||
let e = match arms[0].body.node {
|
||||
ExprRet(Some(ref e)) | ExprBreak(_, Some(ref e)) => e,
|
||||
_ => return,
|
||||
};
|
||||
if let ExprCall(_, ref args) = e.node {
|
||||
self.try_desugar_arm.push(args[0].id);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
ExprMethodCall(ref name, .., ref args) => {
|
||||
if match_trait_method(cx, e, &paths::INTO[..]) && &*name.name.as_str() == "into" {
|
||||
let a = cx.tables.expr_ty(e);
|
||||
let b = cx.tables.expr_ty(&args[0]);
|
||||
if same_tys(cx, a, b) {
|
||||
let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
|
||||
db.span_suggestion(e.span, "consider removing `.into()`", sugg);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ExprCall(ref path, ref args) => if let ExprPath(ref qpath) = path.node {
|
||||
if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) {
|
||||
if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
|
||||
let a = cx.tables.expr_ty(e);
|
||||
let b = cx.tables.expr_ty(&args[0]);
|
||||
if same_tys(cx, a, b) {
|
||||
let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
|
||||
let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
|
||||
db.span_suggestion(e.span, &sugg_msg, sugg);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
|
||||
if Some(&e.id) == self.try_desugar_arm.last() {
|
||||
self.try_desugar_arm.pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
//! lint on blocks unnecessarily using >= with a + 1 or - 1
|
||||
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::*;
|
||||
|
||||
use utils::{span_lint_and_then, snippet_opt};
|
||||
|
||||
/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
|
||||
///
|
||||
///
|
||||
/// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// x >= y + 1
|
||||
/// ```
|
||||
///
|
||||
/// Could be written:
|
||||
///
|
||||
/// ```rust
|
||||
/// x > y
|
||||
/// ```
|
||||
declare_lint! {
|
||||
pub INT_PLUS_ONE,
|
||||
Allow,
|
||||
"instead of using x >= y + 1, use x > y"
|
||||
}
|
||||
|
||||
pub struct IntPlusOne;
|
||||
|
||||
impl LintPass for IntPlusOne {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(INT_PLUS_ONE)
|
||||
}
|
||||
}
|
||||
|
||||
// cases:
|
||||
// BinOpKind::Ge
|
||||
// x >= y + 1
|
||||
// x - 1 >= y
|
||||
//
|
||||
// BinOpKind::Le
|
||||
// x + 1 <= y
|
||||
// x <= y - 1
|
||||
|
||||
enum Side {
|
||||
LHS,
|
||||
RHS,
|
||||
}
|
||||
|
||||
impl IntPlusOne {
|
||||
#[allow(cast_sign_loss)]
|
||||
fn check_lit(&self, lit: &Lit, target_value: i128) -> bool {
|
||||
if let LitKind::Int(value, ..) = lit.node {
|
||||
return value == (target_value as u128)
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
|
||||
match (binop, &lhs.node, &rhs.node) {
|
||||
// case where `x - 1 >= ...` or `-1 + x >= ...`
|
||||
(BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
|
||||
match (lhskind.node, &lhslhs.node, &lhsrhs.node) {
|
||||
// `-1 + x`
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS),
|
||||
// `x - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
// case where `... >= y + 1` or `... >= 1 + y`
|
||||
(BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => {
|
||||
match (&rhslhs.node, &rhsrhs.node) {
|
||||
// `y + 1` and `1 + y`
|
||||
(&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS),
|
||||
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
// case where `x + 1 <= ...` or `1 + x <= ...`
|
||||
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => {
|
||||
match (&lhslhs.node, &lhsrhs.node) {
|
||||
// `1 + x` and `x + 1`
|
||||
(&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS),
|
||||
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
// case where `... >= y - 1` or `... >= -1 + y`
|
||||
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
|
||||
match (rhskind.node, &rhslhs.node, &rhsrhs.node) {
|
||||
// `-1 + y`
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS),
|
||||
// `y - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_recommendation(&self, cx: &EarlyContext, binop: BinOpKind, node: &Expr, other_side: &Expr, side: Side) -> Option<String> {
|
||||
let binop_string = match binop {
|
||||
BinOpKind::Ge => ">",
|
||||
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) {
|
||||
let rec = match side {
|
||||
Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
|
||||
Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
|
||||
};
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) {
|
||||
span_lint_and_then(cx,
|
||||
INT_PLUS_ONE,
|
||||
block.span,
|
||||
"Unnecessary `>= y + 1` or `x - 1 >=`",
|
||||
|db| {
|
||||
db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for IntPlusOne {
|
||||
fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) {
|
||||
if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node {
|
||||
if let Some(ref rec) = self.check_binop(cx, kind.node, lhs, rhs) {
|
||||
self.emit_warning(cx, item, rec.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use utils::{match_def_path, paths, span_help_and_lint, opt_def_id};
|
||||
|
||||
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
|
||||
///
|
||||
/// **Why is this bad?** Creation of null references is undefined behavior.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let bad_ref: &usize = std::mem::zeroed();
|
||||
/// ```
|
||||
|
||||
declare_lint! {
|
||||
pub INVALID_REF,
|
||||
Warn,
|
||||
"creation of invalid reference"
|
||||
}
|
||||
|
||||
const ZERO_REF_SUMMARY: &str = "reference to zeroed memory";
|
||||
const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory";
|
||||
const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
|
||||
|
||||
pub struct InvalidRef;
|
||||
|
||||
impl LintPass for InvalidRef {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(INVALID_REF)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
if_let_chain!{[
|
||||
let ExprCall(ref path, ref args) = expr.node,
|
||||
let ExprPath(ref qpath) = path.node,
|
||||
args.len() == 0,
|
||||
let ty::TyRef(..) = cx.tables.expr_ty(expr).sty,
|
||||
let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)),
|
||||
], {
|
||||
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) {
|
||||
ZERO_REF_SUMMARY
|
||||
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) {
|
||||
UNINIT_REF_SUMMARY
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP);
|
||||
}}
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@ extern crate lazy_static;
|
|||
|
||||
extern crate itertools;
|
||||
extern crate pulldown_cmark;
|
||||
extern crate url;
|
||||
|
||||
macro_rules! declare_restriction_lint {
|
||||
{ pub $name:tt, $description:tt } => {
|
||||
|
@ -92,10 +93,13 @@ pub mod eval_order_dependence;
|
|||
pub mod format;
|
||||
pub mod formatting;
|
||||
pub mod functions;
|
||||
pub mod identity_conversion;
|
||||
pub mod identity_op;
|
||||
pub mod if_let_redundant_pattern_matching;
|
||||
pub mod if_not_else;
|
||||
pub mod infinite_iter;
|
||||
pub mod int_plus_one;
|
||||
pub mod invalid_ref;
|
||||
pub mod is_unit_expr;
|
||||
pub mod items_after_statements;
|
||||
pub mod large_enum_variant;
|
||||
|
@ -231,7 +235,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
reg.register_early_lint_pass(box enum_variants::EnumVariantNames::new(conf.enum_variant_name_threshold));
|
||||
reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse);
|
||||
reg.register_late_lint_pass(box enum_clike::UnportableVariant);
|
||||
reg.register_late_lint_pass(box bit_mask::BitMask);
|
||||
reg.register_late_lint_pass(box bit_mask::BitMask::new(conf.verbose_bit_mask_threshold));
|
||||
reg.register_late_lint_pass(box ptr::PointerPass);
|
||||
reg.register_late_lint_pass(box needless_bool::NeedlessBool);
|
||||
reg.register_late_lint_pass(box needless_bool::BoolComparison);
|
||||
|
@ -299,6 +303,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
reg.register_early_lint_pass(box formatting::Formatting);
|
||||
reg.register_late_lint_pass(box swap::Swap);
|
||||
reg.register_early_lint_pass(box if_not_else::IfNotElse);
|
||||
reg.register_early_lint_pass(box int_plus_one::IntPlusOne);
|
||||
reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional);
|
||||
reg.register_late_lint_pass(box unused_label::UnusedLabel);
|
||||
reg.register_late_lint_pass(box new_without_default::NewWithoutDefault);
|
||||
|
@ -326,6 +331,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
reg.register_late_lint_pass(box use_self::UseSelf);
|
||||
reg.register_late_lint_pass(box bytecount::ByteCount);
|
||||
reg.register_late_lint_pass(box infinite_iter::Pass);
|
||||
reg.register_late_lint_pass(box invalid_ref::InvalidRef);
|
||||
reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default());
|
||||
|
||||
reg.register_lint_group("clippy_restrictions", vec![
|
||||
arithmetic::FLOAT_ARITHMETIC,
|
||||
|
@ -342,6 +349,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
enum_variants::STUTTER,
|
||||
if_not_else::IF_NOT_ELSE,
|
||||
infinite_iter::MAYBE_INFINITE_ITER,
|
||||
int_plus_one::INT_PLUS_ONE,
|
||||
invalid_ref::INVALID_REF,
|
||||
items_after_statements::ITEMS_AFTER_STATEMENTS,
|
||||
matches::SINGLE_MATCH_ELSE,
|
||||
mem_forget::MEM_FORGET,
|
||||
|
@ -424,6 +433,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||
functions::NOT_UNSAFE_PTR_ARG_DEREF,
|
||||
functions::TOO_MANY_ARGUMENTS,
|
||||
identity_conversion::IDENTITY_CONVERSION,
|
||||
identity_op::IDENTITY_OP,
|
||||
if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
|
||||
infinite_iter::INFINITE_ITER,
|
||||
|
@ -446,6 +456,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
loops::FOR_LOOP_OVER_RESULT,
|
||||
loops::ITER_NEXT_LOOP,
|
||||
loops::MANUAL_MEMCPY,
|
||||
loops::MUT_RANGE_BOUND,
|
||||
loops::NEEDLESS_RANGE_LOOP,
|
||||
loops::NEVER_LOOP,
|
||||
loops::REVERSE_RANGE_LOOP,
|
||||
|
@ -458,6 +469,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
matches::MATCH_REF_PATS,
|
||||
matches::MATCH_WILD_ERR_ARM,
|
||||
matches::SINGLE_MATCH,
|
||||
methods::CHARS_LAST_CMP,
|
||||
methods::CHARS_NEXT_CMP,
|
||||
methods::CLONE_DOUBLE_REF,
|
||||
methods::CLONE_ON_COPY,
|
||||
|
@ -535,6 +547,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
transmute::TRANSMUTE_PTR_TO_REF,
|
||||
transmute::USELESS_TRANSMUTE,
|
||||
transmute::WRONG_TRANSMUTE,
|
||||
transmute::TRANSMUTE_INT_TO_CHAR,
|
||||
transmute::TRANSMUTE_INT_TO_BOOL,
|
||||
transmute::TRANSMUTE_INT_TO_FLOAT,
|
||||
types::ABSURD_EXTREME_COMPARISONS,
|
||||
types::BORROWED_BOX,
|
||||
types::BOX_VEC,
|
||||
|
|
|
@ -104,19 +104,20 @@ fn check_fn_inner<'a, 'tcx>(
|
|||
for typ in &generics.ty_params {
|
||||
for bound in &typ.bounds {
|
||||
if let TraitTyParamBound(ref trait_ref, _) = *bound {
|
||||
let bounds = &trait_ref
|
||||
let params = &trait_ref
|
||||
.trait_ref
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.expect("a path must have at least one segment")
|
||||
.parameters
|
||||
.lifetimes;
|
||||
for bound in bounds {
|
||||
if bound.name != "'static" && !bound.is_elided() {
|
||||
return;
|
||||
.parameters;
|
||||
if let Some(ref params) = *params {
|
||||
for bound in ¶ms.lifetimes {
|
||||
if bound.name.name() != "'static" && !bound.is_elided() {
|
||||
return;
|
||||
}
|
||||
bounds_lts.push(bound);
|
||||
}
|
||||
bounds_lts.push(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +226,7 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
|
|||
let mut allowed_lts = HashSet::new();
|
||||
for lt in named_lts {
|
||||
if lt.bounds.is_empty() {
|
||||
allowed_lts.insert(RefLt::Named(lt.lifetime.name));
|
||||
allowed_lts.insert(RefLt::Named(lt.lifetime.name.name()));
|
||||
}
|
||||
}
|
||||
allowed_lts.insert(RefLt::Unnamed);
|
||||
|
@ -235,8 +236,8 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
|
|||
|
||||
fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> {
|
||||
for lt in bounds_lts {
|
||||
if lt.name != "'static" {
|
||||
vec.push(RefLt::Named(lt.name));
|
||||
if lt.name.name() != "'static" {
|
||||
vec.push(RefLt::Named(lt.name.name()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,12 +267,12 @@ impl<'v, 't> RefVisitor<'v, 't> {
|
|||
|
||||
fn record(&mut self, lifetime: &Option<Lifetime>) {
|
||||
if let Some(ref lt) = *lifetime {
|
||||
if lt.name == "'static" {
|
||||
if lt.name.name() == "'static" {
|
||||
self.lts.push(RefLt::Static);
|
||||
} else if lt.is_elided() {
|
||||
self.lts.push(RefLt::Unnamed);
|
||||
} else {
|
||||
self.lts.push(RefLt::Named(lt.name));
|
||||
self.lts.push(RefLt::Named(lt.name.name()));
|
||||
}
|
||||
} else {
|
||||
self.lts.push(RefLt::Unnamed);
|
||||
|
@ -287,23 +288,24 @@ impl<'v, 't> RefVisitor<'v, 't> {
|
|||
}
|
||||
|
||||
fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
|
||||
let last_path_segment = &last_path_segment(qpath).parameters;
|
||||
if !last_path_segment.parenthesized && last_path_segment.lifetimes.is_empty() {
|
||||
let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
|
||||
match self.cx.tables.qpath_def(qpath, hir_id) {
|
||||
Def::TyAlias(def_id) | Def::Struct(def_id) => {
|
||||
let generics = self.cx.tcx.generics_of(def_id);
|
||||
for _ in generics.regions.as_slice() {
|
||||
self.record(&None);
|
||||
}
|
||||
},
|
||||
Def::Trait(def_id) => {
|
||||
let trait_def = self.cx.tcx.trait_def(def_id);
|
||||
for _ in &self.cx.tcx.generics_of(trait_def.def_id).regions {
|
||||
self.record(&None);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
if let Some(ref last_path_segment) = last_path_segment(qpath).parameters {
|
||||
if !last_path_segment.parenthesized && last_path_segment.lifetimes.is_empty() {
|
||||
let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
|
||||
match self.cx.tables.qpath_def(qpath, hir_id) {
|
||||
Def::TyAlias(def_id) | Def::Struct(def_id) => {
|
||||
let generics = self.cx.tcx.generics_of(def_id);
|
||||
for _ in generics.regions.as_slice() {
|
||||
self.record(&None);
|
||||
}
|
||||
},
|
||||
Def::Trait(def_id) => {
|
||||
let trait_def = self.cx.tcx.trait_def(def_id);
|
||||
for _ in &self.cx.tcx.generics_of(trait_def.def_id).regions {
|
||||
self.record(&None);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +398,7 @@ struct LifetimeChecker {
|
|||
impl<'tcx> Visitor<'tcx> for LifetimeChecker {
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
self.map.remove(&lifetime.name);
|
||||
self.map.remove(&lifetime.name.name());
|
||||
}
|
||||
|
||||
fn visit_lifetime_def(&mut self, _: &'tcx LifetimeDef) {
|
||||
|
@ -415,7 +417,7 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx
|
|||
let hs = generics
|
||||
.lifetimes
|
||||
.iter()
|
||||
.map(|lt| (lt.lifetime.name, lt.lifetime.span))
|
||||
.map(|lt| (lt.lifetime.name.name(), lt.lifetime.span))
|
||||
.collect();
|
||||
let mut checker = LifetimeChecker { map: hs };
|
||||
|
||||
|
@ -434,7 +436,7 @@ struct BodyLifetimeChecker {
|
|||
impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
if lifetime.name != keywords::Invalid.name() && lifetime.name != "'static" {
|
||||
if lifetime.name.name() != keywords::Invalid.name() && lifetime.name.name() != "'static" {
|
||||
self.lifetimes_used_in_body = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,12 +279,19 @@ impl LiteralDigitGrouping {
|
|||
let fractional_part = &parts[1].chars().rev().collect::<String>();
|
||||
let _ = Self::do_lint(fractional_part)
|
||||
.map(|fractional_group_size| {
|
||||
let consistent = Self::parts_consistent(integral_group_size, fractional_group_size, parts[0].len(), parts[1].len());
|
||||
let consistent = Self::parts_consistent(integral_group_size,
|
||||
fractional_group_size,
|
||||
parts[0].len(),
|
||||
parts[1].len());
|
||||
if !consistent {
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), cx, &lit.span);
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
&lit.span);
|
||||
}
|
||||
})
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
&lit.span));
|
||||
}
|
||||
})
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
|
||||
|
@ -332,7 +339,8 @@ impl LiteralDigitGrouping {
|
|||
.windows(2)
|
||||
.all(|ps| ps[1] - ps[0] == group_size + 1)
|
||||
// number of digits to the left of the last group cannot be bigger than group size.
|
||||
&& (digits.len() - underscore_positions.last().expect("there's at least one element") <= group_size + 1);
|
||||
&& (digits.len() - underscore_positions.last()
|
||||
.expect("there's at least one element") <= group_size + 1);
|
||||
|
||||
if !consistent {
|
||||
return Err(WarningType::InconsistentDigitGrouping);
|
||||
|
|
|
@ -2,16 +2,22 @@ use itertools::Itertools;
|
|||
use reexport::*;
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def_id;
|
||||
use rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
|
||||
use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt};
|
||||
use rustc::lint::*;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::region;
|
||||
// use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::expr_use_visitor::*;
|
||||
use rustc::middle::mem_categorization::Categorization;
|
||||
use rustc::middle::mem_categorization::cmt;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc_const_eval::ConstContext;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use utils::sugg;
|
||||
use utils::const_to_u64;
|
||||
|
||||
|
@ -328,6 +334,14 @@ declare_lint! {
|
|||
"any loop that will always `break` or `return`"
|
||||
}
|
||||
|
||||
/// TODO: add documentation
|
||||
|
||||
declare_lint! {
|
||||
pub MUT_RANGE_BOUND,
|
||||
Warn,
|
||||
"for loop over a range where one of the bounds is a mutable variable"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Pass;
|
||||
|
||||
|
@ -348,7 +362,8 @@ impl LintPass for Pass {
|
|||
EMPTY_LOOP,
|
||||
WHILE_LET_ON_ITERATOR,
|
||||
FOR_KV_MAP,
|
||||
NEVER_LOOP
|
||||
NEVER_LOOP,
|
||||
MUT_RANGE_BOUND
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -363,7 +378,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
match expr.node {
|
||||
ExprWhile(_, ref block, _) |
|
||||
ExprLoop(ref block, _, _) => {
|
||||
if never_loop(block, &expr.id) {
|
||||
if never_loop(block, expr.id) {
|
||||
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops");
|
||||
}
|
||||
},
|
||||
|
@ -470,11 +485,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
}
|
||||
}
|
||||
|
||||
fn never_loop(block: &Block, id: &NodeId) -> bool {
|
||||
!contains_continue_block(block, id) && loop_exit_block(block)
|
||||
fn never_loop(block: &Block, id: NodeId) -> bool {
|
||||
!contains_continue_block(block, Some(id)) && loop_exit_block(block, &mut vec![id])
|
||||
}
|
||||
|
||||
fn contains_continue_block(block: &Block, dest: &NodeId) -> bool {
|
||||
fn contains_continue_block(block: &Block, dest: Option<NodeId>) -> bool {
|
||||
block.stmts.iter().any(|e| contains_continue_stmt(e, dest)) ||
|
||||
block.expr.as_ref().map_or(
|
||||
false,
|
||||
|
@ -482,7 +497,7 @@ fn contains_continue_block(block: &Block, dest: &NodeId) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool {
|
||||
fn contains_continue_stmt(stmt: &Stmt, dest: Option<NodeId>) -> bool {
|
||||
match stmt.node {
|
||||
StmtSemi(ref e, _) |
|
||||
StmtExpr(ref e, _) => contains_continue_expr(e, dest),
|
||||
|
@ -490,7 +505,7 @@ fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn contains_continue_decl(decl: &Decl, dest: &NodeId) -> bool {
|
||||
fn contains_continue_decl(decl: &Decl, dest: Option<NodeId>) -> bool {
|
||||
match decl.node {
|
||||
DeclLocal(ref local) => {
|
||||
local.init.as_ref().map_or(
|
||||
|
@ -502,7 +517,7 @@ fn contains_continue_decl(decl: &Decl, dest: &NodeId) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool {
|
||||
fn contains_continue_expr(expr: &Expr, dest: Option<NodeId>) -> bool {
|
||||
match expr.node {
|
||||
ExprRet(Some(ref e)) |
|
||||
ExprBox(ref e) |
|
||||
|
@ -540,31 +555,32 @@ fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool {
|
|||
|e| contains_continue_expr(e, dest),
|
||||
)
|
||||
},
|
||||
ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| id == *dest),
|
||||
ExprAgain(d) => dest.map_or(true, |dest| d.target_id.opt_id().map_or(false, |id| id == dest)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn loop_exit_block(block: &Block) -> bool {
|
||||
block.stmts.iter().any(|e| loop_exit_stmt(e)) || block.expr.as_ref().map_or(false, |e| loop_exit_expr(e))
|
||||
fn loop_exit_block(block: &Block, loops: &mut Vec<NodeId>) -> bool {
|
||||
block.stmts.iter().take_while(|s| !contains_continue_stmt(s, None)).any(|s| loop_exit_stmt(s, loops))
|
||||
|| block.expr.as_ref().map_or(false, |e| loop_exit_expr(e, loops))
|
||||
}
|
||||
|
||||
fn loop_exit_stmt(stmt: &Stmt) -> bool {
|
||||
fn loop_exit_stmt(stmt: &Stmt, loops: &mut Vec<NodeId>) -> bool {
|
||||
match stmt.node {
|
||||
StmtSemi(ref e, _) |
|
||||
StmtExpr(ref e, _) => loop_exit_expr(e),
|
||||
StmtDecl(ref d, _) => loop_exit_decl(d),
|
||||
StmtExpr(ref e, _) => loop_exit_expr(e, loops),
|
||||
StmtDecl(ref d, _) => loop_exit_decl(d, loops),
|
||||
}
|
||||
}
|
||||
|
||||
fn loop_exit_decl(decl: &Decl) -> bool {
|
||||
fn loop_exit_decl(decl: &Decl, loops: &mut Vec<NodeId>) -> bool {
|
||||
match decl.node {
|
||||
DeclLocal(ref local) => local.init.as_ref().map_or(false, |e| loop_exit_expr(e)),
|
||||
DeclLocal(ref local) => local.init.as_ref().map_or(false, |e| loop_exit_expr(e, loops)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn loop_exit_expr(expr: &Expr) -> bool {
|
||||
fn loop_exit_expr(expr: &Expr, loops: &mut Vec<NodeId>) -> bool {
|
||||
match expr.node {
|
||||
ExprBox(ref e) |
|
||||
ExprUnary(_, ref e) |
|
||||
|
@ -573,22 +589,34 @@ fn loop_exit_expr(expr: &Expr) -> bool {
|
|||
ExprField(ref e, _) |
|
||||
ExprTupField(ref e, _) |
|
||||
ExprAddrOf(_, ref e) |
|
||||
ExprRepeat(ref e, _) => loop_exit_expr(e),
|
||||
ExprRepeat(ref e, _) => loop_exit_expr(e, loops),
|
||||
ExprArray(ref es) |
|
||||
ExprMethodCall(_, _, ref es) |
|
||||
ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e)),
|
||||
ExprCall(ref e, ref es) => loop_exit_expr(e) || es.iter().any(|e| loop_exit_expr(e)),
|
||||
ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e, loops)),
|
||||
ExprCall(ref e, ref es) => loop_exit_expr(e, loops) || es.iter().any(|e| loop_exit_expr(e, loops)),
|
||||
ExprBinary(_, ref e1, ref e2) |
|
||||
ExprAssign(ref e1, ref e2) |
|
||||
ExprAssignOp(_, ref e1, ref e2) |
|
||||
ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| loop_exit_expr(e)),
|
||||
ExprIf(ref e, ref e2, ref e3) => {
|
||||
loop_exit_expr(e) || e3.as_ref().map_or(false, |e| loop_exit_expr(e)) && loop_exit_expr(e2)
|
||||
ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| loop_exit_expr(e, loops)),
|
||||
ExprIf(ref e, ref e2, ref e3) => loop_exit_expr(e, loops)
|
||||
|| e3.as_ref().map_or(false, |e3| loop_exit_expr(e3, loops)) && loop_exit_expr(e2, loops),
|
||||
ExprLoop(ref b, _, _) => {
|
||||
loops.push(expr.id);
|
||||
let val = loop_exit_block(b, loops);
|
||||
loops.pop();
|
||||
val
|
||||
},
|
||||
ExprWhile(ref e, ref b, _) => loop_exit_expr(e) || loop_exit_block(b),
|
||||
ExprMatch(ref e, ref arms, _) => loop_exit_expr(e) || arms.iter().all(|a| loop_exit_expr(&a.body)),
|
||||
ExprBlock(ref b) => loop_exit_block(b),
|
||||
ExprBreak(_, _) | ExprAgain(_) | ExprRet(_) => true,
|
||||
ExprWhile(ref e, ref b, _) => {
|
||||
loops.push(expr.id);
|
||||
let val = loop_exit_expr(e, loops) || loop_exit_block(b, loops);
|
||||
loops.pop();
|
||||
val
|
||||
},
|
||||
ExprMatch(ref e, ref arms, _) => loop_exit_expr(e, loops) || arms.iter().all(|a| loop_exit_expr(&a.body, loops)),
|
||||
ExprBlock(ref b) => loop_exit_block(b, loops),
|
||||
ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| loops.iter().skip(1).all(|&id2| id != id2)),
|
||||
ExprBreak(d, _) => d.target_id.opt_id().map_or(false, |id| loops[0] == id),
|
||||
ExprRet(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -605,6 +633,7 @@ fn check_for_loop<'a, 'tcx>(
|
|||
check_for_loop_arg(cx, pat, arg, expr);
|
||||
check_for_loop_explicit_counter(cx, arg, body, expr);
|
||||
check_for_loop_over_map_kv(cx, pat, arg, body, expr);
|
||||
check_for_mut_range_bound(cx, arg, body);
|
||||
detect_manual_memcpy(cx, pat, arg, body, expr);
|
||||
}
|
||||
|
||||
|
@ -1294,6 +1323,102 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
struct MutateDelegate {
|
||||
node_id_low: Option<NodeId>,
|
||||
node_id_high: Option<NodeId>,
|
||||
span_low: Option<Span>,
|
||||
span_high: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'tcx> Delegate<'tcx> for MutateDelegate {
|
||||
fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) {
|
||||
}
|
||||
|
||||
fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {
|
||||
}
|
||||
|
||||
fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) {
|
||||
}
|
||||
|
||||
fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) {
|
||||
if let ty::BorrowKind::MutBorrow = bk {
|
||||
if let Categorization::Local(id) = cmt.cat {
|
||||
if Some(id) == self.node_id_low {
|
||||
self.span_low = Some(sp)
|
||||
}
|
||||
if Some(id) == self.node_id_high {
|
||||
self.span_high = Some(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mutate(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: MutateMode) {
|
||||
if let Categorization::Local(id) = cmt.cat {
|
||||
if Some(id) == self.node_id_low {
|
||||
self.span_low = Some(sp)
|
||||
}
|
||||
if Some(id) == self.node_id_high {
|
||||
self.span_high = Some(sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decl_without_init(&mut self, _: NodeId, _: Span) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutateDelegate {
|
||||
fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
|
||||
(self.span_low, self.span_high)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) {
|
||||
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(arg) {
|
||||
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
|
||||
if mut_ids[0].is_some() || mut_ids[1].is_some() {
|
||||
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
|
||||
mut_warn_with_span(cx, span_low);
|
||||
mut_warn_with_span(cx, span_high);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) {
|
||||
if let Some(sp) = span {
|
||||
span_lint(cx, MUT_RANGE_BOUND, sp, "attempt to mutate range bound within loop; note that the range of the loop is unchanged");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> {
|
||||
if_let_chain! {[
|
||||
let ExprPath(ref qpath) = bound.node,
|
||||
let QPath::Resolved(None, _) = *qpath,
|
||||
], {
|
||||
let def = cx.tables.qpath_def(qpath, bound.hir_id);
|
||||
if let Def::Local(node_id) = def {
|
||||
let node_str = cx.tcx.hir.get(node_id);
|
||||
if_let_chain! {[
|
||||
let map::Node::NodeBinding(pat) = node_str,
|
||||
let PatKind::Binding(bind_ann, _, _, _) = pat.node,
|
||||
let BindingAnnotation::Mutable = bind_ann,
|
||||
], {
|
||||
return Some(node_id);
|
||||
}}
|
||||
}
|
||||
}}
|
||||
None
|
||||
}
|
||||
|
||||
fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) {
|
||||
let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None };
|
||||
let def_id = def_id::DefId::local(body.hir_id.owner);
|
||||
let region_scope_tree = &cx.tcx.region_scope_tree(def_id);
|
||||
ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body);
|
||||
delegate.mutation_span()
|
||||
}
|
||||
|
||||
/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`.
|
||||
fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool {
|
||||
match *pat {
|
||||
|
@ -1492,7 +1617,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool {
|
|||
fn is_iterable_array(ty: Ty) -> bool {
|
||||
// IntoIterator is currently only implemented for array sizes <= 32 in rustc
|
||||
match ty.sty {
|
||||
ty::TyArray(_, n) => (0...32).contains(const_to_u64(n)),
|
||||
ty::TyArray(_, n) => (0..=32).contains(const_to_u64(n)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,8 @@ fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool {
|
|||
let arg_segment = [
|
||||
PathSegment {
|
||||
name: id,
|
||||
parameters: PathParameters::none(),
|
||||
parameters: None,
|
||||
infer_types: true,
|
||||
},
|
||||
];
|
||||
!path.is_global() && path.segments[..] == arg_segment
|
||||
|
|
|
@ -1617,11 +1617,18 @@ fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Gener
|
|||
match_path(path, name) &&
|
||||
path.segments
|
||||
.last()
|
||||
.map_or(false, |s| if s.parameters.parenthesized {
|
||||
false
|
||||
} else {
|
||||
s.parameters.types.len() == 1 &&
|
||||
(is_self_ty(&s.parameters.types[0]) || is_ty(&*s.parameters.types[0], self_ty))
|
||||
.map_or(false, |s| {
|
||||
if let Some(ref params) = s.parameters {
|
||||
if params.parenthesized {
|
||||
false
|
||||
} else {
|
||||
params.types.len() == 1 &&
|
||||
(is_self_ty(¶ms.types[0])
|
||||
|| is_ty(&*params.types[0], self_ty))
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
false
|
||||
|
|
|
@ -15,16 +15,7 @@
|
|||
// *rustc*'s
|
||||
// [`missing_doc`].
|
||||
//
|
||||
// [`missing_doc`]:
|
||||
// https://github.
|
||||
// com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// rs#L246
|
||||
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246
|
||||
//
|
||||
|
||||
use rustc::hir;
|
||||
|
|
|
@ -144,7 +144,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
|
|||
let TyPath(QPath::Resolved(_, ref path)) = input.node,
|
||||
let Some(elem_ty) = path.segments.iter()
|
||||
.find(|seg| seg.name == "Vec")
|
||||
.map(|ps| &ps.parameters.types[0]),
|
||||
.and_then(|ps| ps.parameters.as_ref())
|
||||
.map(|params| ¶ms.types[0]),
|
||||
], {
|
||||
let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
|
||||
db.span_suggestion(input.span,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use rustc::hir::*;
|
||||
use rustc::hir::map::Node::{NodeImplItem, NodeItem};
|
||||
use rustc::lint::*;
|
||||
use utils::{paths, opt_def_id};
|
||||
use syntax::ast::LitKind;
|
||||
use syntax::symbol::InternedString;
|
||||
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint};
|
||||
use format::get_argument_fmtstr_parts;
|
||||
use utils::{paths, opt_def_id};
|
||||
|
||||
/// **What it does:** This lint warns when you using `print!()` with a format
|
||||
/// string that
|
||||
|
@ -103,15 +104,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
let ExprTup(ref args) = args.node,
|
||||
|
||||
// collect the format string parts and check the last one
|
||||
let Some(fmtstrs) = get_argument_fmtstr_parts(cx, &args_args[0]),
|
||||
let Some(last_str) = fmtstrs.last(),
|
||||
let Some('\n') = last_str.chars().last(),
|
||||
let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]),
|
||||
let Some('\n') = fmtstr.chars().last(),
|
||||
|
||||
// "foo{}bar" is made into two strings + one argument,
|
||||
// if the format string starts with `{}` (eg. "{}foo"),
|
||||
// the string array is prepended an empty string "".
|
||||
// We only want to check the last string after any `{}`:
|
||||
args.len() < fmtstrs.len(),
|
||||
args.len() < fmtlen,
|
||||
], {
|
||||
span_lint(cx, PRINT_WITH_NEWLINE, span,
|
||||
"using `print!()` with a format string that ends in a \
|
||||
|
@ -124,7 +124,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) {
|
||||
if let ExprPath(ref qpath) = args[1].node {
|
||||
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, args[1].hir_id)) {
|
||||
if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() {
|
||||
if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD)
|
||||
&& !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() {
|
||||
span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
|
||||
}
|
||||
}
|
||||
|
@ -149,3 +150,17 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
|
|||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns the slice of format string parts in an `Arguments::new_v1` call.
|
||||
fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(InternedString, usize)> {
|
||||
if_let_chain! {[
|
||||
let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
|
||||
let ExprArray(ref exprs) = expr.node,
|
||||
let Some(expr) = exprs.last(),
|
||||
let ExprLit(ref lit) = expr.node,
|
||||
let LitKind::Str(ref lit, _) = lit.node,
|
||||
], {
|
||||
return Some((lit.as_str(), exprs.len()));
|
||||
}}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Checks for usage of `&Vec[_]` and `&String`.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use rustc::hir::map::NodeItem;
|
||||
|
@ -158,49 +159,53 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
|
|||
let mut ty_snippet = None;
|
||||
if_let_chain!([
|
||||
let TyPath(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).node,
|
||||
let Some(&PathSegment{ref parameters, ..}) = path.segments.last(),
|
||||
let Some(&PathSegment{parameters: Some(ref parameters), ..}) = path.segments.last(),
|
||||
parameters.types.len() == 1,
|
||||
], {
|
||||
ty_snippet = snippet_opt(cx, parameters.types[0].span);
|
||||
});
|
||||
let spans = get_spans(cx, opt_body_id, idx, "to_owned");
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices.",
|
||||
|db| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
if let Ok(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices.",
|
||||
|db| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet));
|
||||
}
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion(clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(),
|
||||
|x| Cow::Owned(format!("change `{}` to", x))),
|
||||
suggestion.into());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
} else if match_type(cx, ty, &paths::STRING) {
|
||||
if let Ok(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&String` instead of `&str` involves a new object where a slice will do.",
|
||||
|db| {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet));
|
||||
"&str".into());
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion_short(clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(),
|
||||
|x| Cow::Owned(format!("change `{}` to", x))),
|
||||
suggestion.into());
|
||||
}
|
||||
}
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion(clonespan,
|
||||
"change the `.clone()` to",
|
||||
suggestion);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else if match_type(cx, ty, &paths::STRING) {
|
||||
let spans = get_spans(cx, opt_body_id, idx, "to_string");
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&String` instead of `&str` involves a new object where a slice will do.",
|
||||
|db| {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
"&str".into());
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion_short(clonespan,
|
||||
"change the `.clone` to ",
|
||||
suggestion);
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,38 +234,50 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
|
|||
}
|
||||
}
|
||||
|
||||
fn get_spans(cx: &LateContext, opt_body_id: Option<BodyId>, idx: usize, fn_name: &'static str) -> Vec<(Span, String)> {
|
||||
fn get_spans(cx: &LateContext, opt_body_id: Option<BodyId>, idx: usize, replacements: &'static [(&'static str, &'static str)]) -> Result<Vec<(Span, Cow<'static, str>)>, ()> {
|
||||
if let Some(body) = opt_body_id.map(|id| cx.tcx.hir.body(id)) {
|
||||
get_binding_name(&body.arguments[idx]).map_or_else(Vec::new,
|
||||
|name| extract_clone_suggestions(cx, name, fn_name, body))
|
||||
get_binding_name(&body.arguments[idx]).map_or_else(|| Ok(vec![]),
|
||||
|name| extract_clone_suggestions(cx, name, replacements, body))
|
||||
} else {
|
||||
vec![]
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_clone_suggestions<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, fn_name: &'static str, body: &'tcx Body) -> Vec<(Span, String)> {
|
||||
fn extract_clone_suggestions<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, replace: &'static [(&'static str, &'static str)], body: &'tcx Body) -> Result<Vec<(Span, Cow<'static, str>)>, ()> {
|
||||
let mut visitor = PtrCloneVisitor {
|
||||
cx,
|
||||
name,
|
||||
fn_name,
|
||||
spans: vec![]
|
||||
replace,
|
||||
spans: vec![],
|
||||
abort: false,
|
||||
};
|
||||
visitor.visit_body(body);
|
||||
visitor.spans
|
||||
if visitor.abort { Err(()) } else { Ok(visitor.spans) }
|
||||
}
|
||||
|
||||
struct PtrCloneVisitor<'a, 'tcx: 'a> {
|
||||
cx: &'a LateContext<'a, 'tcx>,
|
||||
name: Name,
|
||||
fn_name: &'static str,
|
||||
spans: Vec<(Span, String)>,
|
||||
replace: &'static [(&'static str, &'static str)],
|
||||
spans: Vec<(Span, Cow<'static, str>)>,
|
||||
abort: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
if self.abort { return; }
|
||||
if let ExprMethodCall(ref seg, _, ref args) = expr.node {
|
||||
if args.len() == 1 && match_var(&args[0], self.name) && seg.name == "clone" {
|
||||
self.spans.push((expr.span, format!("{}.{}()", snippet(self.cx, args[0].span, "_"), self.fn_name)));
|
||||
if args.len() == 1 && match_var(&args[0], self.name) {
|
||||
if seg.name == "capacity" {
|
||||
self.abort = true;
|
||||
return;
|
||||
}
|
||||
for &(fn_name, suffix) in self.replace {
|
||||
if seg.name == fn_name {
|
||||
self.spans.push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use rustc::lint::*;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::hir::*;
|
||||
use std::borrow::Cow;
|
||||
use syntax::ast;
|
||||
use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then};
|
||||
use utils::{sugg, opt_def_id};
|
||||
|
||||
|
@ -76,11 +78,73 @@ declare_lint! {
|
|||
"transmutes from a pointer to a reference type"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for transmutes from an integer to a `char`.
|
||||
///
|
||||
/// **Why is this bad?** Not every integer is a unicode scalar value.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let _: char = std::mem::transmute(x); // where x: u32
|
||||
/// // should be:
|
||||
/// let _: Option<char> = std::char::from_u32(x);
|
||||
/// ```
|
||||
declare_lint! {
|
||||
pub TRANSMUTE_INT_TO_CHAR,
|
||||
Warn,
|
||||
"transmutes from an integer to a `char`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for transmutes from an integer to a `bool`.
|
||||
///
|
||||
/// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let _: bool = std::mem::transmute(x); // where x: u8
|
||||
/// // should be:
|
||||
/// let _: bool = x != 0;
|
||||
/// ```
|
||||
declare_lint! {
|
||||
pub TRANSMUTE_INT_TO_BOOL,
|
||||
Warn,
|
||||
"transmutes from an integer to a `bool`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for transmutes from an integer to a float.
|
||||
///
|
||||
/// **Why is this bad?** This might result in an invalid in-memory representation of a float.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let _: f32 = std::mem::transmute(x); // where x: u32
|
||||
/// // should be:
|
||||
/// let _: f32 = f32::from_bits(x);
|
||||
/// ```
|
||||
declare_lint! {
|
||||
pub TRANSMUTE_INT_TO_FLOAT,
|
||||
Warn,
|
||||
"transmutes from an integer to a float"
|
||||
}
|
||||
|
||||
pub struct Transmute;
|
||||
|
||||
impl LintPass for Transmute {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE)
|
||||
lint_array!(
|
||||
CROSSPOINTER_TRANSMUTE,
|
||||
TRANSMUTE_PTR_TO_REF,
|
||||
USELESS_TRANSMUTE,
|
||||
WRONG_TRANSMUTE,
|
||||
TRANSMUTE_INT_TO_CHAR,
|
||||
TRANSMUTE_INT_TO_BOOL,
|
||||
TRANSMUTE_INT_TO_FLOAT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +241,50 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
|||
db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string());
|
||||
},
|
||||
),
|
||||
(&ty::TyInt(ast::IntTy::I32), &ty::TyChar) |
|
||||
(&ty::TyUint(ast::UintTy::U32), &ty::TyChar) => span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_CHAR,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `char`", from_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let arg = if let ty::TyInt(_) = from_ty.sty {
|
||||
arg.as_ty(ty::TyUint(ast::UintTy::U32))
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
db.span_suggestion(e.span, "consider using", format!("std::char::from_u32({})", arg.to_string()));
|
||||
}
|
||||
),
|
||||
(&ty::TyInt(ast::IntTy::I8), &ty::TyBool) |
|
||||
(&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_BOOL,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `bool`", from_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let zero = sugg::Sugg::NonParen(Cow::from("0"));
|
||||
db.span_suggestion(e.span, "consider using", sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string());
|
||||
}
|
||||
),
|
||||
(&ty::TyInt(_), &ty::TyFloat(_)) |
|
||||
(&ty::TyUint(_), &ty::TyFloat(_)) => span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_FLOAT,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let arg = if let ty::TyInt(int_ty) = from_ty.sty {
|
||||
arg.as_ty(format!("u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())))
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
db.span_suggestion(e.span, "consider using", format!("{}::from_bits({})", to_ty, arg.to_string()));
|
||||
}
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
|
@ -194,8 +302,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
|||
fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: Ty) -> String {
|
||||
let seg = last_path_segment(path);
|
||||
if_let_chain!{[
|
||||
!seg.parameters.parenthesized,
|
||||
let Some(to_ty) = seg.parameters.types.get(1),
|
||||
let Some(ref params) = seg.parameters,
|
||||
!params.parenthesized,
|
||||
let Some(to_ty) = params.types.get(1),
|
||||
let TyRptr(_, ref to_ty) = to_ty.node,
|
||||
], {
|
||||
return snippet(cx, to_ty.ty.span, &to_rty.to_string()).to_string();
|
||||
|
|
|
@ -154,8 +154,9 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
|
|||
if Some(def_id) == cx.tcx.lang_items().owned_box() {
|
||||
let last = last_path_segment(qpath);
|
||||
if_let_chain! {[
|
||||
!last.parameters.parenthesized,
|
||||
let Some(vec) = last.parameters.types.get(0),
|
||||
let Some(ref params) = last.parameters,
|
||||
!params.parenthesized,
|
||||
let Some(vec) = params.types.get(0),
|
||||
let TyPath(ref qpath) = vec.node,
|
||||
let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(vec.id))),
|
||||
match_def_path(cx.tcx, did, &paths::VEC),
|
||||
|
@ -183,67 +184,32 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
|
|||
check_ty(cx, ty, is_local);
|
||||
for ty in p.segments
|
||||
.iter()
|
||||
.flat_map(|seg| seg.parameters.types.iter())
|
||||
.flat_map(|seg| seg.parameters.as_ref()
|
||||
.map_or_else(|| [].iter(),
|
||||
|params| params.types.iter()))
|
||||
{
|
||||
check_ty(cx, ty, is_local);
|
||||
}
|
||||
},
|
||||
QPath::Resolved(None, ref p) => for ty in p.segments
|
||||
.iter()
|
||||
.flat_map(|seg| seg.parameters.types.iter())
|
||||
.flat_map(|seg| seg.parameters.as_ref()
|
||||
.map_or_else(|| [].iter(),
|
||||
|params| params.types.iter()))
|
||||
{
|
||||
check_ty(cx, ty, is_local);
|
||||
},
|
||||
QPath::TypeRelative(ref ty, ref seg) => {
|
||||
check_ty(cx, ty, is_local);
|
||||
for ty in seg.parameters.types.iter() {
|
||||
check_ty(cx, ty, is_local);
|
||||
if let Some(ref params) = seg.parameters {
|
||||
for ty in params.types.iter() {
|
||||
check_ty(cx, ty, is_local);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
TyRptr(ref lt, MutTy { ref ty, ref mutbl }) => {
|
||||
match ty.node {
|
||||
TyPath(ref qpath) => {
|
||||
let hir_id = cx.tcx.hir.node_to_hir_id(ty.id);
|
||||
let def = cx.tables.qpath_def(qpath, hir_id);
|
||||
if_let_chain! {[
|
||||
let Some(def_id) = opt_def_id(def),
|
||||
Some(def_id) == cx.tcx.lang_items().owned_box(),
|
||||
let QPath::Resolved(None, ref path) = *qpath,
|
||||
let [ref bx] = *path.segments,
|
||||
!bx.parameters.parenthesized,
|
||||
let [ref inner] = *bx.parameters.types
|
||||
], {
|
||||
if is_any_trait(inner) {
|
||||
// Ignore `Box<Any>` types, see #1884 for details.
|
||||
return;
|
||||
}
|
||||
|
||||
let ltopt = if lt.is_elided() {
|
||||
"".to_owned()
|
||||
} else {
|
||||
format!("{} ", lt.name.as_str())
|
||||
};
|
||||
let mutopt = if *mutbl == Mutability::MutMutable {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
span_lint_and_sugg(cx,
|
||||
BORROWED_BOX,
|
||||
ast_ty.span,
|
||||
"you seem to be trying to use `&Box<T>`. Consider using just `&T`",
|
||||
"try",
|
||||
format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, ".."))
|
||||
);
|
||||
return; // don't recurse into the type
|
||||
}};
|
||||
check_ty(cx, ty, is_local);
|
||||
},
|
||||
_ => check_ty(cx, ty, is_local),
|
||||
}
|
||||
},
|
||||
TyRptr(ref lt, ref mut_ty) => check_ty_rptr(cx, ast_ty, is_local, lt, mut_ty),
|
||||
// recurse
|
||||
TySlice(ref ty) | TyArray(ref ty, _) | TyPtr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local),
|
||||
TyTup(ref tys) => for ty in tys {
|
||||
|
@ -253,6 +219,50 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) {
|
||||
match mut_ty.ty.node {
|
||||
TyPath(ref qpath) => {
|
||||
let hir_id = cx.tcx.hir.node_to_hir_id(mut_ty.ty.id);
|
||||
let def = cx.tables.qpath_def(qpath, hir_id);
|
||||
if_let_chain! {[
|
||||
let Some(def_id) = opt_def_id(def),
|
||||
Some(def_id) == cx.tcx.lang_items().owned_box(),
|
||||
let QPath::Resolved(None, ref path) = *qpath,
|
||||
let [ref bx] = *path.segments,
|
||||
let Some(ref params) = bx.parameters,
|
||||
!params.parenthesized,
|
||||
let [ref inner] = *params.types
|
||||
], {
|
||||
if is_any_trait(inner) {
|
||||
// Ignore `Box<Any>` types, see #1884 for details.
|
||||
return;
|
||||
}
|
||||
|
||||
let ltopt = if lt.is_elided() {
|
||||
"".to_owned()
|
||||
} else {
|
||||
format!("{} ", lt.name.name().as_str())
|
||||
};
|
||||
let mutopt = if mut_ty.mutbl == Mutability::MutMutable {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
span_lint_and_sugg(cx,
|
||||
BORROWED_BOX,
|
||||
ast_ty.span,
|
||||
"you seem to be trying to use `&Box<T>`. Consider using just `&T`",
|
||||
"try",
|
||||
format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, ".."))
|
||||
);
|
||||
return; // don't recurse into the type
|
||||
}};
|
||||
check_ty(cx, &mut_ty.ty, is_local);
|
||||
},
|
||||
_ => check_ty(cx, &mut_ty.ty, is_local),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if given type is `Any` trait.
|
||||
fn is_any_trait(t: &hir::Ty) -> bool {
|
||||
if_let_chain! {[
|
||||
|
|
|
@ -59,7 +59,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
|
|||
let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node,
|
||||
], {
|
||||
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters;
|
||||
if !parameters.parenthesized && parameters.lifetimes.len() == 0 {
|
||||
let should_check = if let Some(ref params) = *parameters {
|
||||
!params.parenthesized && params.lifetimes.len() == 0
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if should_check {
|
||||
let visitor = &mut UseSelfVisitor {
|
||||
item_path: item_path,
|
||||
cx: cx,
|
||||
|
|
|
@ -82,7 +82,8 @@ macro_rules! define_Conf {
|
|||
#[serde(rename_all="kebab-case")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Conf {
|
||||
$(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)] pub $rust_name: define_Conf!(TY $($ty)+),)+
|
||||
$(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
|
||||
pub $rust_name: define_Conf!(TY $($ty)+),)+
|
||||
#[allow(dead_code)]
|
||||
#[serde(default)]
|
||||
third_party: Option<::toml::Value>,
|
||||
|
@ -91,10 +92,12 @@ macro_rules! define_Conf {
|
|||
mod $rust_name {
|
||||
use serde;
|
||||
use serde::Deserialize;
|
||||
pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<define_Conf!(TY $($ty)+), D::Error> {
|
||||
pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
||||
-> Result<define_Conf!(TY $($ty)+), D::Error> {
|
||||
type T = define_Conf!(TY $($ty)+);
|
||||
Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
|
||||
::utils::conf::ERRORS.lock().expect("no threading here").push(::utils::conf::Error::Toml(e.to_string()));
|
||||
::utils::conf::ERRORS.lock().expect("no threading here")
|
||||
.push(::utils::conf::Error::Toml(e.to_string()));
|
||||
super::$rust_name()
|
||||
}))
|
||||
}
|
||||
|
@ -154,10 +157,10 @@ define_Conf! {
|
|||
"JavaScript",
|
||||
"NaN",
|
||||
"OAuth",
|
||||
"OpenGL",
|
||||
"OpenGL", "OpenSSH", "OpenSSL",
|
||||
"TrueType",
|
||||
"iOS", "macOS",
|
||||
"TeX", "LaTeX", "BibTex", "BibLaTex",
|
||||
"TeX", "LaTeX", "BibTeX", "BibLaTeX",
|
||||
"MinGW",
|
||||
] => Vec<String>),
|
||||
/// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
|
||||
|
@ -172,6 +175,8 @@ define_Conf! {
|
|||
(enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
|
||||
/// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
|
||||
(enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
|
||||
/// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
|
||||
(verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
|
||||
}
|
||||
|
||||
/// Search for the configuration file.
|
||||
|
|
|
@ -214,7 +214,14 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
|||
fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool {
|
||||
// The == of idents doesn't work with different contexts,
|
||||
// we have to be explicit about hygiene
|
||||
left.name.as_str() == right.name.as_str() && self.eq_path_parameters(&left.parameters, &right.parameters)
|
||||
if left.name.as_str() != right.name.as_str() {
|
||||
return false;
|
||||
}
|
||||
match (&left.parameters, &right.parameters) {
|
||||
(&None, &None) => true,
|
||||
(&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
|
||||
|
|
|
@ -26,10 +26,13 @@ pub const DOUBLE_ENDED_ITERATOR: [&'static str; 4] = ["core", "iter", "traits",
|
|||
pub const DROP: [&'static str; 3] = ["core", "mem", "drop"];
|
||||
pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["core", "fmt", "Arguments", "new_v1"];
|
||||
pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["core", "fmt", "ArgumentV1", "new"];
|
||||
pub const FROM_FROM: [&'static str; 4] = ["core", "convert", "From", "from"];
|
||||
pub const HASH: [&'static str; 2] = ["hash", "Hash"];
|
||||
pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
|
||||
pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
|
||||
pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"];
|
||||
pub const INIT: [&'static str; 4] = ["core", "intrinsics", "", "init"];
|
||||
pub const INTO: [&'static str; 3] = ["core", "convert", "Into"];
|
||||
pub const INTO_ITERATOR: [&'static str; 4] = ["core", "iter", "traits", "IntoIterator"];
|
||||
pub const IO_PRINT: [&'static str; 4] = ["std", "io", "stdio", "_print"];
|
||||
pub const IO_READ: [&'static str; 3] = ["std", "io", "Read"];
|
||||
|
@ -39,6 +42,8 @@ pub const LINKED_LIST: [&'static str; 3] = ["alloc", "linked_list", "LinkedList"
|
|||
pub const LINT: [&'static str; 3] = ["rustc", "lint", "Lint"];
|
||||
pub const LINT_ARRAY: [&'static str; 3] = ["rustc", "lint", "LintArray"];
|
||||
pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"];
|
||||
pub const MEM_UNINIT: [&'static str; 3] = ["core", "mem", "uninitialized"];
|
||||
pub const MEM_ZEROED: [&'static str; 3] = ["core", "mem", "zeroed"];
|
||||
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
|
||||
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
|
||||
pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"];
|
||||
|
@ -80,6 +85,7 @@ pub const TO_OWNED: [&'static str; 3] = ["alloc", "borrow", "ToOwned"];
|
|||
pub const TO_STRING: [&'static str; 3] = ["alloc", "string", "ToString"];
|
||||
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
|
||||
pub const TRY_INTO_RESULT: [&'static str; 4] = ["std", "ops", "Try", "into_result"];
|
||||
pub const UNINIT: [&'static str; 4] = ["core", "intrinsics", "", "uninit"];
|
||||
pub const VEC: [&'static str; 3] = ["alloc", "vec", "Vec"];
|
||||
pub const VEC_DEQUE: [&'static str; 3] = ["alloc", "vec_deque", "VecDeque"];
|
||||
pub const VEC_FROM_ELEM: [&'static str; 3] = ["alloc", "vec", "from_elem"];
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'a> Sugg<'a> {
|
|||
ast::ExprKind::While(..) |
|
||||
ast::ExprKind::WhileLet(..) => Sugg::NonParen(snippet),
|
||||
ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
|
||||
ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotDot, snippet),
|
||||
ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet),
|
||||
ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
|
||||
ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet),
|
||||
ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet),
|
||||
|
@ -165,7 +165,7 @@ impl<'a> Sugg<'a> {
|
|||
pub fn range(self, end: Self, limit: ast::RangeLimits) -> Sugg<'static> {
|
||||
match limit {
|
||||
ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, &end),
|
||||
ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotDot, &self, &end),
|
||||
ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotEq, &self, &end),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,7 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
|
|||
AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_to_string(&token::BinOp(op)), rhs),
|
||||
AssocOp::As => format!("{} as {}", lhs, rhs),
|
||||
AssocOp::DotDot => format!("{}..{}", lhs, rhs),
|
||||
AssocOp::DotDotDot => format!("{}...{}", lhs, rhs),
|
||||
AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
|
||||
AssocOp::Colon => format!("{}: {}", lhs, rhs),
|
||||
};
|
||||
|
||||
|
@ -362,7 +362,7 @@ fn associativity(op: &AssocOp) -> Associativity {
|
|||
ShiftLeft |
|
||||
ShiftRight |
|
||||
Subtract => Associativity::Left,
|
||||
DotDot | DotDotDot => Associativity::None,
|
||||
DotDot | DotDotEq => Associativity::None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA
|
|||
.eval(len)
|
||||
.is_ok()
|
||||
{
|
||||
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
|
||||
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len"))
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA
|
|||
higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() {
|
||||
let span = args[0].span.to(last.span);
|
||||
|
||||
format!("&[{}]", snippet(cx, span, "..")).into()
|
||||
format!("&[{}]", snippet(cx, span, ".."))
|
||||
} else {
|
||||
"&[]".into()
|
||||
},
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,198 @@
|
|||
// error-pattern:yummy
|
||||
#![feature(box_syntax)]
|
||||
#![feature(rustc_private)]
|
||||
#![allow(unknown_lints, missing_docs_in_private_items)]
|
||||
|
||||
extern crate clippy_lints;
|
||||
extern crate getopts;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_plugin;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc::session::{config, CompileIncomplete, Session};
|
||||
use rustc::session::config::{ErrorOutputType, Input};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use syntax::ast;
|
||||
|
||||
struct ClippyCompilerCalls {
|
||||
default: RustcDefaultCalls,
|
||||
run_lints: bool,
|
||||
}
|
||||
|
||||
impl ClippyCompilerCalls {
|
||||
fn new(run_lints: bool) -> Self {
|
||||
Self {
|
||||
default: RustcDefaultCalls,
|
||||
run_lints: run_lints,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
|
||||
fn early_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
output: ErrorOutputType,
|
||||
) -> Compilation {
|
||||
self.default
|
||||
.early_callback(matches, sopts, cfg, descriptions, output)
|
||||
}
|
||||
fn no_input(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
) -> Option<(Input, Option<PathBuf>)> {
|
||||
self.default
|
||||
.no_input(matches, sopts, cfg, odir, ofile, descriptions)
|
||||
}
|
||||
fn late_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
crate_stores: &rustc::middle::cstore::CrateStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
self.default
|
||||
.late_callback(matches, sess, crate_stores, input, odir, ofile)
|
||||
}
|
||||
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
|
||||
let mut control = self.default.build_controller(sess, matches);
|
||||
|
||||
if self.run_lints {
|
||||
let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
|
||||
control.after_parse.callback = Box::new(move |state| {
|
||||
{
|
||||
let mut registry = rustc_plugin::registry::Registry::new(
|
||||
state.session,
|
||||
state
|
||||
.krate
|
||||
.as_ref()
|
||||
.expect(
|
||||
"at this compilation stage \
|
||||
the krate must be parsed",
|
||||
)
|
||||
.span,
|
||||
);
|
||||
registry.args_hidden = Some(Vec::new());
|
||||
clippy_lints::register_plugins(&mut registry);
|
||||
|
||||
let rustc_plugin::registry::Registry {
|
||||
early_lint_passes,
|
||||
late_lint_passes,
|
||||
lint_groups,
|
||||
llvm_passes,
|
||||
attributes,
|
||||
..
|
||||
} = registry;
|
||||
let sess = &state.session;
|
||||
let mut ls = sess.lint_store.borrow_mut();
|
||||
for pass in early_lint_passes {
|
||||
ls.register_early_pass(Some(sess), true, pass);
|
||||
}
|
||||
for pass in late_lint_passes {
|
||||
ls.register_late_pass(Some(sess), true, pass);
|
||||
}
|
||||
|
||||
for (name, to) in lint_groups {
|
||||
ls.register_group(Some(sess), true, name, to);
|
||||
}
|
||||
|
||||
sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
|
||||
sess.plugin_attributes.borrow_mut().extend(attributes);
|
||||
}
|
||||
old(state);
|
||||
});
|
||||
}
|
||||
|
||||
control
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(print_stdout)]
|
||||
fn show_version() {
|
||||
println!("{}", env!("CARGO_PKG_VERSION"));
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
use std::env;
|
||||
|
||||
if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
|
||||
panic!("yummy");
|
||||
}
|
||||
|
||||
if std::env::args().any(|a| a == "--version" || a == "-V") {
|
||||
show_version();
|
||||
return;
|
||||
}
|
||||
|
||||
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
|
||||
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
|
||||
let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
|
||||
format!("{}/toolchains/{}", home, toolchain)
|
||||
} else {
|
||||
option_env!("SYSROOT")
|
||||
.map(|s| s.to_owned())
|
||||
.or_else(|| {
|
||||
Command::new("rustc")
|
||||
.arg("--print")
|
||||
.arg("sysroot")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok())
|
||||
.map(|s| s.trim().to_owned())
|
||||
})
|
||||
.expect(
|
||||
"need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
|
||||
)
|
||||
};
|
||||
|
||||
rustc_driver::in_rustc_thread(|| {
|
||||
// Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
|
||||
// We're invoking the compiler programatically, so we ignore this/
|
||||
let mut orig_args: Vec<String> = env::args().collect();
|
||||
if orig_args[1] == "rustc" {
|
||||
// we still want to be able to invoke it normally though
|
||||
orig_args.remove(1);
|
||||
}
|
||||
// this conditional check for the --sysroot flag is there so users can call
|
||||
// `clippy_driver` directly
|
||||
// without having to pass --sysroot or anything
|
||||
let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
|
||||
orig_args.clone()
|
||||
} else {
|
||||
orig_args.clone().into_iter()
|
||||
.chain(Some("--sysroot".to_owned()))
|
||||
.chain(Some(sys_root))
|
||||
.collect()
|
||||
};
|
||||
|
||||
// this check ensures that dependencies are built but not linted and the final
|
||||
// crate is
|
||||
// linted but not built
|
||||
let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") ||
|
||||
orig_args.iter().any(|s| s == "--emit=metadata");
|
||||
|
||||
if clippy_enabled {
|
||||
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
|
||||
}
|
||||
|
||||
let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
|
||||
let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
|
||||
if let Err(CompileIncomplete::Errored(_)) = result {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}).expect("rustc_thread failed");
|
||||
}
|
347
src/main.rs
347
src/main.rs
|
@ -3,128 +3,12 @@
|
|||
#![feature(rustc_private)]
|
||||
#![allow(unknown_lints, missing_docs_in_private_items)]
|
||||
|
||||
extern crate clippy_lints;
|
||||
extern crate getopts;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_plugin;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc::session::{config, CompileIncomplete, Session};
|
||||
use rustc::session::config::{ErrorOutputType, Input};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command};
|
||||
use syntax::ast;
|
||||
use std::process;
|
||||
use std::io::{self, Write};
|
||||
|
||||
extern crate cargo_metadata;
|
||||
|
||||
struct ClippyCompilerCalls {
|
||||
default: RustcDefaultCalls,
|
||||
run_lints: bool,
|
||||
}
|
||||
|
||||
impl ClippyCompilerCalls {
|
||||
fn new(run_lints: bool) -> Self {
|
||||
Self {
|
||||
default: RustcDefaultCalls,
|
||||
run_lints: run_lints,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
|
||||
fn early_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
output: ErrorOutputType,
|
||||
) -> Compilation {
|
||||
self.default
|
||||
.early_callback(matches, sopts, cfg, descriptions, output)
|
||||
}
|
||||
fn no_input(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
) -> Option<(Input, Option<PathBuf>)> {
|
||||
self.default
|
||||
.no_input(matches, sopts, cfg, odir, ofile, descriptions)
|
||||
}
|
||||
fn late_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
crate_stores: &rustc::middle::cstore::CrateStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
self.default
|
||||
.late_callback(matches, sess, crate_stores, input, odir, ofile)
|
||||
}
|
||||
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
|
||||
let mut control = self.default.build_controller(sess, matches);
|
||||
|
||||
if self.run_lints {
|
||||
let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
|
||||
control.after_parse.callback = Box::new(move |state| {
|
||||
{
|
||||
let mut registry = rustc_plugin::registry::Registry::new(
|
||||
state.session,
|
||||
state
|
||||
.krate
|
||||
.as_ref()
|
||||
.expect(
|
||||
"at this compilation stage \
|
||||
the krate must be parsed",
|
||||
)
|
||||
.span,
|
||||
);
|
||||
registry.args_hidden = Some(Vec::new());
|
||||
clippy_lints::register_plugins(&mut registry);
|
||||
|
||||
let rustc_plugin::registry::Registry {
|
||||
early_lint_passes,
|
||||
late_lint_passes,
|
||||
lint_groups,
|
||||
llvm_passes,
|
||||
attributes,
|
||||
..
|
||||
} = registry;
|
||||
let sess = &state.session;
|
||||
let mut ls = sess.lint_store.borrow_mut();
|
||||
for pass in early_lint_passes {
|
||||
ls.register_early_pass(Some(sess), true, pass);
|
||||
}
|
||||
for pass in late_lint_passes {
|
||||
ls.register_late_pass(Some(sess), true, pass);
|
||||
}
|
||||
|
||||
for (name, to) in lint_groups {
|
||||
ls.register_group(Some(sess), true, name, to);
|
||||
}
|
||||
|
||||
sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
|
||||
sess.plugin_attributes.borrow_mut().extend(attributes);
|
||||
}
|
||||
old(state);
|
||||
});
|
||||
}
|
||||
|
||||
control
|
||||
}
|
||||
}
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
|
||||
|
@ -181,162 +65,105 @@ pub fn main() {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
|
||||
// this arm is executed on the initial call to `cargo clippy`
|
||||
let manifest_path_arg = std::env::args()
|
||||
.skip(2)
|
||||
.find(|val| val.starts_with("--manifest-path="));
|
||||
|
||||
let manifest_path_arg = std::env::args()
|
||||
.skip(2)
|
||||
.find(|val| val.starts_with("--manifest-path="));
|
||||
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
|
||||
{
|
||||
metadata
|
||||
} else {
|
||||
let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
|
||||
process::exit(101);
|
||||
};
|
||||
|
||||
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
|
||||
{
|
||||
metadata
|
||||
} else {
|
||||
let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
|
||||
process::exit(101);
|
||||
};
|
||||
let manifest_path = manifest_path_arg.map(|arg| {
|
||||
Path::new(&arg["--manifest-path=".len()..])
|
||||
.canonicalize()
|
||||
.expect("manifest path could not be canonicalized")
|
||||
});
|
||||
|
||||
let manifest_path = manifest_path_arg.map(|arg| {
|
||||
Path::new(&arg["--manifest-path=".len()..])
|
||||
.canonicalize()
|
||||
.expect("manifest path could not be canonicalized")
|
||||
});
|
||||
|
||||
let packages = if std::env::args().any(|a| a == "--all") {
|
||||
metadata.packages
|
||||
} else {
|
||||
let package_index = {
|
||||
if let Some(manifest_path) = manifest_path {
|
||||
metadata.packages.iter().position(|package| {
|
||||
let package_manifest_path = Path::new(&package.manifest_path)
|
||||
.canonicalize()
|
||||
.expect("package manifest path could not be canonicalized");
|
||||
package_manifest_path == manifest_path
|
||||
})
|
||||
} else {
|
||||
let package_manifest_paths: HashMap<_, _> = metadata
|
||||
.packages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, package)| {
|
||||
let package_manifest_path = Path::new(&package.manifest_path)
|
||||
.parent()
|
||||
.expect("could not find parent directory of package manifest")
|
||||
.canonicalize()
|
||||
.expect("package directory cannot be canonicalized");
|
||||
(package_manifest_path, i)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let current_dir = std::env::current_dir()
|
||||
.expect("could not read current directory")
|
||||
let packages = if std::env::args().any(|a| a == "--all") {
|
||||
metadata.packages
|
||||
} else {
|
||||
let package_index = {
|
||||
if let Some(manifest_path) = manifest_path {
|
||||
metadata.packages.iter().position(|package| {
|
||||
let package_manifest_path = Path::new(&package.manifest_path)
|
||||
.canonicalize()
|
||||
.expect("current directory cannot be canonicalized");
|
||||
.expect("package manifest path could not be canonicalized");
|
||||
package_manifest_path == manifest_path
|
||||
})
|
||||
} else {
|
||||
let package_manifest_paths: HashMap<_, _> = metadata
|
||||
.packages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, package)| {
|
||||
let package_manifest_path = Path::new(&package.manifest_path)
|
||||
.parent()
|
||||
.expect("could not find parent directory of package manifest")
|
||||
.canonicalize()
|
||||
.expect("package directory cannot be canonicalized");
|
||||
(package_manifest_path, i)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut current_path: &Path = ¤t_dir;
|
||||
let current_dir = std::env::current_dir()
|
||||
.expect("could not read current directory")
|
||||
.canonicalize()
|
||||
.expect("current directory cannot be canonicalized");
|
||||
|
||||
// This gets the most-recent parent (the one that takes the fewest `cd ..`s to
|
||||
// reach).
|
||||
loop {
|
||||
if let Some(&package_index) = package_manifest_paths.get(current_path) {
|
||||
break Some(package_index);
|
||||
} else {
|
||||
// We'll never reach the filesystem root, because to get to this point in the
|
||||
// code
|
||||
// the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
|
||||
// unwrap the current path's parent.
|
||||
current_path = current_path
|
||||
.parent()
|
||||
.unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
|
||||
}
|
||||
let mut current_path: &Path = ¤t_dir;
|
||||
|
||||
// This gets the most-recent parent (the one that takes the fewest `cd ..`s to
|
||||
// reach).
|
||||
loop {
|
||||
if let Some(&package_index) = package_manifest_paths.get(current_path) {
|
||||
break Some(package_index);
|
||||
} else {
|
||||
// We'll never reach the filesystem root, because to get to this point in the
|
||||
// code
|
||||
// the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
|
||||
// unwrap the current path's parent.
|
||||
current_path = current_path
|
||||
.parent()
|
||||
.unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
|
||||
}
|
||||
}
|
||||
}.expect("could not find matching package");
|
||||
}
|
||||
}.expect("could not find matching package");
|
||||
|
||||
vec![metadata.packages.remove(package_index)]
|
||||
};
|
||||
vec![metadata.packages.remove(package_index)]
|
||||
};
|
||||
|
||||
for package in packages {
|
||||
let manifest_path = package.manifest_path;
|
||||
for package in packages {
|
||||
let manifest_path = package.manifest_path;
|
||||
|
||||
for target in package.targets {
|
||||
let args = std::env::args()
|
||||
.skip(2)
|
||||
.filter(|a| a != "--all" && !a.starts_with("--manifest-path="));
|
||||
for target in package.targets {
|
||||
let args = std::env::args()
|
||||
.skip(2)
|
||||
.filter(|a| a != "--all" && !a.starts_with("--manifest-path="));
|
||||
|
||||
let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
|
||||
if let Some(first) = target.kind.get(0) {
|
||||
if target.kind.len() > 1 || first.ends_with("lib") {
|
||||
if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else if ["bin", "example", "test", "bench"].contains(&&**first) {
|
||||
if let Err(code) = process(
|
||||
vec![format!("--{}", first), target.name]
|
||||
.into_iter()
|
||||
.chain(args),
|
||||
) {
|
||||
std::process::exit(code);
|
||||
}
|
||||
let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
|
||||
if let Some(first) = target.kind.get(0) {
|
||||
if target.kind.len() > 1 || first.ends_with("lib") {
|
||||
if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else if ["bin", "example", "test", "bench"].contains(&&**first) {
|
||||
if let Err(code) = process(
|
||||
vec![format!("--{}", first), target.name]
|
||||
.into_iter()
|
||||
.chain(args),
|
||||
) {
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else {
|
||||
panic!("badly formatted cargo metadata: target::kind is an empty array");
|
||||
}
|
||||
} else {
|
||||
panic!("badly formatted cargo metadata: target::kind is an empty array");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
|
||||
// env var set to itself
|
||||
|
||||
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
|
||||
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
|
||||
let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
|
||||
format!("{}/toolchains/{}", home, toolchain)
|
||||
} else {
|
||||
option_env!("SYSROOT")
|
||||
.map(|s| s.to_owned())
|
||||
.or_else(|| {
|
||||
Command::new("rustc")
|
||||
.arg("--print")
|
||||
.arg("sysroot")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok())
|
||||
.map(|s| s.trim().to_owned())
|
||||
})
|
||||
.expect(
|
||||
"need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
|
||||
)
|
||||
};
|
||||
|
||||
rustc_driver::in_rustc_thread(|| {
|
||||
// this conditional check for the --sysroot flag is there so users can call
|
||||
// `cargo-clippy` directly
|
||||
// without having to pass --sysroot or anything
|
||||
let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
|
||||
env::args().collect()
|
||||
} else {
|
||||
env::args()
|
||||
.chain(Some("--sysroot".to_owned()))
|
||||
.chain(Some(sys_root))
|
||||
.collect()
|
||||
};
|
||||
|
||||
// this check ensures that dependencies are built but not linted and the final
|
||||
// crate is
|
||||
// linted but not built
|
||||
let clippy_enabled = env::args().any(|s| s == "--emit=metadata");
|
||||
|
||||
if clippy_enabled {
|
||||
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
|
||||
}
|
||||
|
||||
let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
|
||||
let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
|
||||
if let Err(CompileIncomplete::Errored(_)) = result {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}).expect("rustc_thread failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,10 +185,12 @@ where
|
|||
args.push("--cfg".to_owned());
|
||||
args.push(r#"feature="cargo-clippy""#.to_owned());
|
||||
|
||||
let path = std::env::current_exe().expect("current executable path invalid");
|
||||
let path = std::env::current_exe()
|
||||
.expect("current executable path invalid")
|
||||
.with_file_name("clippy-driver");
|
||||
let exit_status = std::process::Command::new("cargo")
|
||||
.args(&args)
|
||||
.env("RUSTC", path)
|
||||
.env("RUSTC_WRAPPER", path)
|
||||
.spawn()
|
||||
.expect("could not run cargo")
|
||||
.wait()
|
||||
|
|
|
@ -3,6 +3,14 @@ extern crate compiletest_rs as compiletest;
|
|||
use std::path::PathBuf;
|
||||
use std::env::{set_var, var};
|
||||
|
||||
fn clippy_driver_path() -> PathBuf {
|
||||
if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
|
||||
PathBuf::from(path)
|
||||
} else {
|
||||
PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
|
||||
}
|
||||
}
|
||||
|
||||
fn run_mode(dir: &'static str, mode: &'static str) {
|
||||
let mut config = compiletest::Config::default();
|
||||
|
||||
|
@ -16,12 +24,15 @@ fn run_mode(dir: &'static str, mode: &'static str) {
|
|||
config.mode = cfg_mode;
|
||||
config.build_base = PathBuf::from("target/debug/test_build_base");
|
||||
config.src_base = PathBuf::from(format!("tests/{}", dir));
|
||||
config.rustc_path = clippy_driver_path();
|
||||
|
||||
compiletest::run_tests(&config);
|
||||
}
|
||||
|
||||
fn prepare_env() {
|
||||
set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
|
||||
set_var("CLIPPY_TESTS", "true");
|
||||
set_var("RUST_BACKTRACE", "0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -29,8 +40,4 @@ fn compile_test() {
|
|||
prepare_env();
|
||||
run_mode("run-pass", "run-pass");
|
||||
run_mode("ui", "ui");
|
||||
#[cfg(target_os = "windows")]
|
||||
run_mode("ui-windows", "ui");
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
run_mode("ui-posix", "ui");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))]
|
||||
|
||||
fn main() {}
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
pub trait Trait {
|
||||
const CONSTANT: u8;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![deny(clippy)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![allow(clippy)]
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![allow(clippy)]
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![deny(clippy)]
|
||||
|
||||
fn core() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![deny(mut_mut, zero_ptr, cmp_nan)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![feature(conservative_impl_trait)]
|
||||
#![deny(needless_lifetimes)]
|
||||
#![allow(dead_code)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy, clippy_mini_macro_test)]
|
||||
#![plugin(clippy_mini_macro_test)]
|
||||
|
||||
#[deny(warnings)]
|
||||
fn main() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![allow(blacklisted_name)]
|
||||
|
||||
pub fn foo(bar: *const u8) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![warn(single_match_else)]
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// error-pattern: error reading Clippy's configuration file
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(clippy(conf_file="./tests/auxiliary/non_existant_conf.toml"))]
|
||||
|
||||
fn main() {}
|
|
@ -1,4 +0,0 @@
|
|||
error: error reading Clippy's configuration file: No such file or directory (os error 2)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# A script to update the references for all tests. The idea is that
|
||||
# you do a run, which will generate files in the build directory
|
||||
# containing the (normalized) actual output of the compiler. You then
|
||||
# run this script, which will copy those files over. If you find
|
||||
# yourself manually editing a foo.stderr file, you're doing it wrong.
|
||||
#
|
||||
# See all `update-references.sh`, if you just want to update a single test.
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" ]]; then
|
||||
echo "usage: $0"
|
||||
fi
|
||||
|
||||
BUILD_DIR=$PWD/target/debug/test_build_base
|
||||
MY_DIR=$(dirname $0)
|
||||
cd $MY_DIR
|
||||
find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# A script to update the references for particular tests. The idea is
|
||||
# that you do a run, which will generate files in the build directory
|
||||
# containing the (normalized) actual output of the compiler. This
|
||||
# script will then copy that output and replace the "expected output"
|
||||
# files. You can then commit the changes.
|
||||
#
|
||||
# If you find yourself manually editing a foo.stderr file, you're
|
||||
# doing it wrong.
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then
|
||||
echo "usage: $0 <build-directory> <relative-path-to-rs-files>"
|
||||
echo ""
|
||||
echo "For example:"
|
||||
echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs"
|
||||
fi
|
||||
|
||||
MYDIR=$(dirname $0)
|
||||
|
||||
BUILD_DIR="$1"
|
||||
shift
|
||||
|
||||
while [[ "$1" != "" ]]; do
|
||||
STDERR_NAME="${1/%.rs/.stderr}"
|
||||
STDOUT_NAME="${1/%.rs/.stdout}"
|
||||
shift
|
||||
if [ -f $BUILD_DIR/$STDOUT_NAME ] && \
|
||||
! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then
|
||||
echo updating $MYDIR/$STDOUT_NAME
|
||||
cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME
|
||||
fi
|
||||
if [ -f $BUILD_DIR/$STDERR_NAME ] && \
|
||||
! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then
|
||||
echo updating $MYDIR/$STDERR_NAME
|
||||
cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// error-pattern: error reading Clippy's configuration file
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(clippy(conf_file="./tests/auxiliary/non_existant_conf.toml"))]
|
||||
|
||||
fn main() {}
|
|
@ -1,4 +0,0 @@
|
|||
error: error reading Clippy's configuration file: The system cannot find the file specified. (os error 2)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# A script to update the references for all tests. The idea is that
|
||||
# you do a run, which will generate files in the build directory
|
||||
# containing the (normalized) actual output of the compiler. You then
|
||||
# run this script, which will copy those files over. If you find
|
||||
# yourself manually editing a foo.stderr file, you're doing it wrong.
|
||||
#
|
||||
# See all `update-references.sh`, if you just want to update a single test.
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" ]]; then
|
||||
echo "usage: $0"
|
||||
fi
|
||||
|
||||
BUILD_DIR=$PWD/target/debug/test_build_base
|
||||
MY_DIR=$(dirname $0)
|
||||
cd $MY_DIR
|
||||
find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# A script to update the references for particular tests. The idea is
|
||||
# that you do a run, which will generate files in the build directory
|
||||
# containing the (normalized) actual output of the compiler. This
|
||||
# script will then copy that output and replace the "expected output"
|
||||
# files. You can then commit the changes.
|
||||
#
|
||||
# If you find yourself manually editing a foo.stderr file, you're
|
||||
# doing it wrong.
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then
|
||||
echo "usage: $0 <build-directory> <relative-path-to-rs-files>"
|
||||
echo ""
|
||||
echo "For example:"
|
||||
echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs"
|
||||
fi
|
||||
|
||||
MYDIR=$(dirname $0)
|
||||
|
||||
BUILD_DIR="$1"
|
||||
shift
|
||||
|
||||
while [[ "$1" != "" ]]; do
|
||||
STDERR_NAME="${1/%.rs/.stderr}"
|
||||
STDOUT_NAME="${1/%.rs/.stdout}"
|
||||
shift
|
||||
if [ -f $BUILD_DIR/$STDOUT_NAME ] && \
|
||||
! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then
|
||||
echo updating $MYDIR/$STDOUT_NAME
|
||||
cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME
|
||||
fi
|
||||
if [ -f $BUILD_DIR/$STDERR_NAME ] && \
|
||||
! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then
|
||||
echo updating $MYDIR/$STDERR_NAME
|
||||
cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![warn(absurd_extreme_comparisons)]
|
||||
#![allow(unused, eq_op, no_effect, unnecessary_operation, needless_pass_by_value)]
|
||||
|
|
|
@ -143,5 +143,3 @@ error: <-comparison of unit values detected. This will always be false
|
|||
|
|
||||
= note: `-D unit-cmp` implied by `-D warnings`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(approx_constant)]
|
||||
#[allow(unused, shadow_unrelated, similar_names)]
|
||||
|
|
|
@ -114,5 +114,3 @@ error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it
|
|||
55 | let my_sq2 = 1.4142;
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![warn(integer_arithmetic, float_arithmetic)]
|
||||
#![allow(unused, shadow_reuse, shadow_unrelated, no_effect, unnecessary_operation)]
|
||||
|
|
|
@ -69,5 +69,3 @@ error: floating-point arithmetic detected
|
|||
29 | -f;
|
||||
| ^^
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(inclusive_range_syntax, plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![warn(indexing_slicing)]
|
||||
#![warn(out_of_bounds_indexing)]
|
||||
|
@ -13,8 +13,8 @@ fn main() {
|
|||
x[1 << 3];
|
||||
&x[1..5];
|
||||
&x[0..3];
|
||||
&x[0...4];
|
||||
&x[...4];
|
||||
&x[0..=4];
|
||||
&x[..=4];
|
||||
&x[..];
|
||||
&x[1..];
|
||||
&x[4..];
|
||||
|
@ -26,19 +26,19 @@ fn main() {
|
|||
y[0];
|
||||
&y[1..2];
|
||||
&y[..];
|
||||
&y[0...4];
|
||||
&y[...4];
|
||||
&y[0..=4];
|
||||
&y[..=4];
|
||||
|
||||
let empty: [i8; 0] = [];
|
||||
empty[0];
|
||||
&empty[1..5];
|
||||
&empty[0...4];
|
||||
&empty[...4];
|
||||
&empty[0..=4];
|
||||
&empty[..=4];
|
||||
&empty[..];
|
||||
&empty[0..];
|
||||
&empty[0..0];
|
||||
&empty[0...0];
|
||||
&empty[...0];
|
||||
&empty[0..=0];
|
||||
&empty[..=0];
|
||||
&empty[..0];
|
||||
&empty[1..];
|
||||
&empty[..4];
|
||||
|
|
|
@ -21,13 +21,13 @@ error: range is out of bounds
|
|||
error: range is out of bounds
|
||||
--> $DIR/array_indexing.rs:16:6
|
||||
|
|
||||
16 | &x[0...4];
|
||||
16 | &x[0..=4];
|
||||
| ^^^^^^^^
|
||||
|
||||
error: range is out of bounds
|
||||
--> $DIR/array_indexing.rs:17:6
|
||||
|
|
||||
17 | &x[...4];
|
||||
17 | &x[..=4];
|
||||
| ^^^^^^^
|
||||
|
||||
error: range is out of bounds
|
||||
|
@ -59,13 +59,13 @@ error: slicing may panic
|
|||
error: slicing may panic
|
||||
--> $DIR/array_indexing.rs:29:6
|
||||
|
|
||||
29 | &y[0...4];
|
||||
29 | &y[0..=4];
|
||||
| ^^^^^^^^
|
||||
|
||||
error: slicing may panic
|
||||
--> $DIR/array_indexing.rs:30:6
|
||||
|
|
||||
30 | &y[...4];
|
||||
30 | &y[..=4];
|
||||
| ^^^^^^^
|
||||
|
||||
error: const index is out of bounds
|
||||
|
@ -83,25 +83,25 @@ error: range is out of bounds
|
|||
error: range is out of bounds
|
||||
--> $DIR/array_indexing.rs:35:6
|
||||
|
|
||||
35 | &empty[0...4];
|
||||
35 | &empty[0..=4];
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: range is out of bounds
|
||||
--> $DIR/array_indexing.rs:36:6
|
||||
|
|
||||
36 | &empty[...4];
|
||||
36 | &empty[..=4];
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: range is out of bounds
|
||||
--> $DIR/array_indexing.rs:40:6
|
||||
|
|
||||
40 | &empty[0...0];
|
||||
40 | &empty[0..=0];
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: range is out of bounds
|
||||
--> $DIR/array_indexing.rs:41:6
|
||||
|
|
||||
41 | &empty[...0];
|
||||
41 | &empty[..=0];
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: range is out of bounds
|
||||
|
@ -116,5 +116,3 @@ error: range is out of bounds
|
|||
44 | &empty[..4];
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(assign_ops)]
|
||||
#[allow(unused_assignments)]
|
||||
|
|
|
@ -134,5 +134,3 @@ error: manual implementation of an assign operation
|
|||
40 | s = s + "bla";
|
||||
| ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
#[warn(misrefactored_assign_op)]
|
||||
|
|
|
@ -48,5 +48,3 @@ error: variable appears on both sides of an assignment operation
|
|||
15 | a &= a & 1;
|
||||
| ^^^^^^^^^^ help: replace it with: `a &= 1`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![warn(inline_always, deprecated_semver)]
|
||||
|
||||
|
|
|
@ -20,5 +20,3 @@ error: the since field must contain a semver-compliant version
|
|||
30 | #[deprecated(since = "1")]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
const THREE_BITS : i64 = 7;
|
||||
const EVEN_MORE_REDIRECTION : i64 = THREE_BITS;
|
||||
|
|
|
@ -6,20 +6,6 @@ error: &-masking with zero
|
|||
|
|
||||
= note: `-D bad-bit-mask` implied by `-D warnings`
|
||||
|
||||
error: bit mask could be simplified with a call to `trailing_zeros`
|
||||
--> $DIR/bit_masks.rs:12:5
|
||||
|
|
||||
12 | x & 0 == 0;
|
||||
| ^^^^^^^^^^ help: try: `x.trailing_zeros() >= 0`
|
||||
|
|
||||
= note: `-D verbose-bit-mask` implied by `-D warnings`
|
||||
|
||||
error: bit mask could be simplified with a call to `trailing_zeros`
|
||||
--> $DIR/bit_masks.rs:14:5
|
||||
|
|
||||
14 | x & 1 == 0; //ok, compared with zero
|
||||
| ^^^^^^^^^^ help: try: `x.trailing_zeros() >= 1`
|
||||
|
||||
error: incompatible bit mask: `_ & 2` can never be equal to `1`
|
||||
--> $DIR/bit_masks.rs:15:5
|
||||
|
|
||||
|
@ -106,5 +92,3 @@ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared
|
|||
55 | x | 1 >= 8;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![allow(dead_code, similar_names, single_match, toplevel_ref_arg, unused_mut, unused_variables)]
|
||||
#![warn(blacklisted_name)]
|
||||
|
|
|
@ -84,5 +84,3 @@ error: use of a blacklisted/placeholder name `baz`
|
|||
35 | if let Some(ref mut baz) = Some(42) {}
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![warn(block_in_if_condition_expr)]
|
||||
#![warn(block_in_if_condition_stmt)]
|
||||
|
|
|
@ -50,5 +50,3 @@ error: this boolean expression can be simplified
|
|||
|
|
||||
= note: `-D nonminimal-bool` implied by `-D warnings`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(bool_comparison)]
|
||||
fn main() {
|
||||
|
|
|
@ -24,5 +24,3 @@ error: equality checks against false can be replaced by a negation
|
|||
10 | if false == x { "yes" } else { "no" };
|
||||
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![warn(nonminimal_bool, logic_bug)]
|
||||
|
||||
#[allow(unused, many_single_char_names)]
|
||||
|
|
|
@ -130,5 +130,3 @@ help: try
|
|||
39 | let _ = !(a == b && c == d);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![deny(borrowed_box)]
|
||||
#![allow(blacklisted_name)]
|
||||
|
|
|
@ -28,5 +28,3 @@ error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
|||
22 | fn test4(a: &Box<bool>);
|
||||
| ^^^^^^^^^^ help: try: `&bool`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![warn(clippy)]
|
||||
#![allow(boxed_local, needless_pass_by_value)]
|
||||
|
|
|
@ -7,5 +7,3 @@ error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`
|
|||
= note: `-D box-vec` implied by `-D warnings`
|
||||
= help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![warn(builtin_type_shadow)]
|
||||
|
||||
fn foo<u32>(a: u32) -> u32 {
|
||||
|
|
|
@ -17,5 +17,3 @@ error[E0308]: mismatched types
|
|||
= note: expected type `u32`
|
||||
found type `{integer}`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[deny(naive_bytecount)]
|
||||
fn main() {
|
||||
|
|
|
@ -22,5 +22,3 @@ error: You appear to be counting bytes the naive way
|
|||
22 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap, cast_lossless)]
|
||||
#[allow(no_effect, unnecessary_operation)]
|
||||
|
|
|
@ -460,5 +460,3 @@ error: casting to the same type is unnecessary (`bool` -> `bool`)
|
|||
88 | false as bool;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 75 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#![warn(char_lit_as_u8)]
|
||||
#![allow(unused_variables)]
|
||||
|
|
|
@ -8,5 +8,3 @@ error: casting character literal to u8. `char`s are 4 bytes wide in rust, so cas
|
|||
= help: Consider using a byte literal instead:
|
||||
b'a'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(cmp_nan)]
|
||||
#[allow(float_cmp, no_effect, unnecessary_operation)]
|
||||
|
|
|
@ -72,5 +72,3 @@ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
|
|||
21 | y >= std::f64::NAN;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![warn(cmp_null)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
|
|
|
@ -12,5 +12,3 @@ error: Comparing with null is better expressed by the .is_null() method
|
|||
16 | if m == ptr::null_mut() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(cmp_owned)]
|
||||
#[allow(unnecessary_operation)]
|
||||
|
|
|
@ -36,5 +36,3 @@ error: this creates an owned instance just for comparison
|
|||
30 | self.to_owned() == *other
|
||||
| ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
|
||||
#[warn(collapsible_if)]
|
||||
fn main() {
|
||||
|
|
|
@ -252,5 +252,3 @@ help: try
|
|||
112 | }
|
||||
|
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
|
||||
#![warn(clippy)]
|
||||
#![allow(unused, needless_pass_by_value)]
|
||||
#![feature(associated_type_defaults)]
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue