Merge branch 'master' into no_effect_with_drop

This commit is contained in:
Chris Emerson 2017-10-07 23:24:36 +01:00
commit fcdce8fc1d
348 changed files with 2221 additions and 1475 deletions

View File

@ -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 ../..

View File

@ -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

108
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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"`.

8
build.rs Normal file
View File

@ -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");
}

View File

@ -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 = []

View File

@ -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)
})

View File

@ -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() {

View File

@ -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,

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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());
}
}
}
}

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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 &params.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;
}
}

View File

@ -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);

View File

@ -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,
}
}

View File

@ -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

View File

@ -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(&params.types[0])
|| is_ty(&*params.types[0], self_ty))
}
} else {
false
}
})
} else {
false

View File

@ -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;

View File

@ -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| &params.types[0]),
], {
let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
db.span_suggestion(input.span,

View File

@ -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
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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! {[

View File

@ -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,

View File

@ -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.

View 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 {

View File

@ -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"];

View File

@ -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,
}
}

View File

@ -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()
},

BIN
mut_range_bound Executable file

Binary file not shown.

198
src/driver.rs Normal file
View File

@ -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");
}

View File

@ -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 = &current_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 = &current_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()

View File

@ -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");
}

View File

@ -1,4 +1,3 @@
#![feature(plugin)]
#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))]
fn main() {}

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
pub trait Trait {
const CONSTANT: u8;

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy)]
#![allow(unused_imports)]

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(clippy)]
fn main() {

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(clippy)]
fn main() { }

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy)]
fn core() {}

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(mut_mut, zero_ptr, cmp_nan)]
#![allow(dead_code)]

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![feature(conservative_impl_trait)]
#![deny(needless_lifetimes)]
#![allow(dead_code)]

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy, clippy_mini_macro_test)]
#![plugin(clippy_mini_macro_test)]
#[deny(warnings)]
fn main() {

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(blacklisted_name)]
pub fn foo(bar: *const u8) {

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(single_match_else)]
fn main() {

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(absurd_extreme_comparisons)]
#![allow(unused, eq_op, no_effect, unnecessary_operation, needless_pass_by_value)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(approx_constant)]
#[allow(unused, shadow_unrelated, similar_names)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(integer_arithmetic, float_arithmetic)]
#![allow(unused, shadow_reuse, shadow_unrelated, no_effect, unnecessary_operation)]

View File

@ -69,5 +69,3 @@ error: floating-point arithmetic detected
29 | -f;
| ^^
error: aborting due to 11 previous errors

View File

@ -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];

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(assign_ops)]
#[allow(unused_assignments)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[allow(unused_assignments)]
#[warn(misrefactored_assign_op)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(inline_always, deprecated_semver)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
const THREE_BITS : i64 = 7;
const EVEN_MORE_REDIRECTION : i64 = THREE_BITS;

View File

@ -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

View File

@ -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)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(block_in_if_condition_expr)]
#![warn(block_in_if_condition_stmt)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(bool_comparison)]
fn main() {

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(nonminimal_bool, logic_bug)]
#[allow(unused, many_single_char_names)]

View File

@ -130,5 +130,3 @@ help: try
39 | let _ = !(a == b && c == d);
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 13 previous errors

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(borrowed_box)]
#![allow(blacklisted_name)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(clippy)]
#![allow(boxed_local, needless_pass_by_value)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(builtin_type_shadow)]
fn foo<u32>(a: u32) -> u32 {

View File

@ -17,5 +17,3 @@ error[E0308]: mismatched types
= note: expected type `u32`
found type `{integer}`
error: aborting due to 2 previous errors

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[deny(naive_bytecount)]
fn main() {

View File

@ -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

View File

@ -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)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(char_lit_as_u8)]
#![allow(unused_variables)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(cmp_nan)]
#[allow(float_cmp, no_effect, unnecessary_operation)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(cmp_null)]
#![allow(unused_mut)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(cmp_owned)]
#[allow(unnecessary_operation)]

View File

@ -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

View File

@ -1,5 +1,5 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(collapsible_if)]
fn main() {

View File

@ -252,5 +252,3 @@ help: try
112 | }
|
error: aborting due to 13 previous errors

View File

@ -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