Skip to content

Commit c066807

Browse files
committed
Auto merge of #5148 - krishna-veerareddy:issue-5147-option-env-unwrap, r=flip1995
Add `option-env-unwrap` lint changelog: Add `option-env-unwrap` lint Fixes #5147
2 parents 701a579 + b48b221 commit c066807

File tree

8 files changed

+163
-2
lines changed

8 files changed

+163
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,7 @@ Released 2018-09-13
12761276
[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
12771277
[`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some
12781278
[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
1279+
[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
12791280
[`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used
12801281
[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
12811282
[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are 354 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 355 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1212

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ pub mod no_effect;
267267
pub mod non_copy_const;
268268
pub mod non_expressive_names;
269269
pub mod open_options;
270+
pub mod option_env_unwrap;
270271
pub mod overflow_check_conditional;
271272
pub mod panic_unimplemented;
272273
pub mod partialeq_ne_impl;
@@ -713,6 +714,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
713714
&non_expressive_names::MANY_SINGLE_CHAR_NAMES,
714715
&non_expressive_names::SIMILAR_NAMES,
715716
&open_options::NONSENSICAL_OPEN_OPTIONS,
717+
&option_env_unwrap::OPTION_ENV_UNWRAP,
716718
&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
717719
&panic_unimplemented::PANIC,
718720
&panic_unimplemented::PANIC_PARAMS,
@@ -1003,6 +1005,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10031005
let max_fn_params_bools = conf.max_fn_params_bools;
10041006
let max_struct_bools = conf.max_struct_bools;
10051007
store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
1008+
store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
10061009

10071010
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
10081011
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1285,6 +1288,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12851288
LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
12861289
LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
12871290
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
1291+
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
12881292
LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
12891293
LintId::of(&panic_unimplemented::PANIC_PARAMS),
12901294
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
@@ -1590,6 +1594,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15901594
LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
15911595
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
15921596
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
1597+
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
15931598
LintId::of(&ptr::MUT_FROM_REF),
15941599
LintId::of(&regex::INVALID_REGEX),
15951600
LintId::of(&serde_api::SERDE_API_MISUSE),

clippy_lints/src/option_env_unwrap.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use crate::utils::{is_direct_expn_of, span_lint_and_help};
2+
use if_chain::if_chain;
3+
use rustc_lint::{EarlyContext, EarlyLintPass};
4+
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
use syntax::ast::*;
6+
7+
declare_clippy_lint! {
8+
/// **What it does:** Checks for usage of `option_env!(...).unwrap()` and
9+
/// suggests usage of the `env!` macro.
10+
///
11+
/// **Why is this bad?** Unwrapping the result of `option_env!` will panic
12+
/// at run-time if the environment variable doesn't exist, whereas `env!`
13+
/// catches it at compile-time.
14+
///
15+
/// **Known problems:** None.
16+
///
17+
/// **Example:**
18+
///
19+
/// ```rust,no_run
20+
/// let _ = option_env!("HOME").unwrap();
21+
/// ```
22+
///
23+
/// Is better expressed as:
24+
///
25+
/// ```rust,no_run
26+
/// let _ = env!("HOME");
27+
/// ```
28+
pub OPTION_ENV_UNWRAP,
29+
correctness,
30+
"using `option_env!(...).unwrap()` to get environment variable"
31+
}
32+
33+
declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
34+
35+
impl EarlyLintPass for OptionEnvUnwrap {
36+
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
37+
if_chain! {
38+
if let ExprKind::MethodCall(path_segment, args) = &expr.kind;
39+
let method_name = path_segment.ident.as_str();
40+
if method_name == "expect" || method_name == "unwrap";
41+
if let ExprKind::Call(caller, _) = &args[0].kind;
42+
if is_direct_expn_of(caller.span, "option_env").is_some();
43+
then {
44+
span_lint_and_help(
45+
cx,
46+
OPTION_ENV_UNWRAP,
47+
expr.span,
48+
"this will panic at run-time if the environment variable doesn't exist at compile-time",
49+
"consider using the `env!` macro instead"
50+
);
51+
}
52+
}
53+
}
54+
}

src/lintlist/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use lint::Lint;
66
pub use lint::LINT_LEVELS;
77

88
// begin lint list, do not remove this comment, it’s used in `update_lints`
9-
pub const ALL_LINTS: [Lint; 354] = [
9+
pub const ALL_LINTS: [Lint; 355] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -1498,6 +1498,13 @@ pub const ALL_LINTS: [Lint; 354] = [
14981498
deprecation: None,
14991499
module: "methods",
15001500
},
1501+
Lint {
1502+
name: "option_env_unwrap",
1503+
group: "correctness",
1504+
desc: "using `option_env!(...).unwrap()` to get environment variable",
1505+
deprecation: None,
1506+
module: "option_env_unwrap",
1507+
},
15011508
Lint {
15021509
name: "option_expect_used",
15031510
group: "restriction",

tests/ui/auxiliary/macro_rules.rs

+10
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,13 @@ macro_rules! take_external {
4646
std::mem::replace($s, Default::default())
4747
};
4848
}
49+
50+
#[macro_export]
51+
macro_rules! option_env_unwrap_external {
52+
($env: expr) => {
53+
option_env!($env).unwrap()
54+
};
55+
($env: expr, $message: expr) => {
56+
option_env!($env).expect($message)
57+
};
58+
}

tests/ui/option_env_unwrap.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// aux-build:macro_rules.rs
2+
#![warn(clippy::option_env_unwrap)]
3+
4+
#[macro_use]
5+
extern crate macro_rules;
6+
7+
macro_rules! option_env_unwrap {
8+
($env: expr) => {
9+
option_env!($env).unwrap()
10+
};
11+
($env: expr, $message: expr) => {
12+
option_env!($env).expect($message)
13+
};
14+
}
15+
16+
fn main() {
17+
let _ = option_env!("PATH").unwrap();
18+
let _ = option_env!("PATH").expect("environment variable PATH isn't set");
19+
let _ = option_env_unwrap!("PATH");
20+
let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set");
21+
let _ = option_env_unwrap_external!("PATH");
22+
let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
23+
}

tests/ui/option_env_unwrap.stderr

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
error: this will panic at run-time if the environment variable doesn't exist at compile-time
2+
--> $DIR/option_env_unwrap.rs:17:13
3+
|
4+
LL | let _ = option_env!("PATH").unwrap();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::option-env-unwrap` implied by `-D warnings`
8+
= help: consider using the `env!` macro instead
9+
10+
error: this will panic at run-time if the environment variable doesn't exist at compile-time
11+
--> $DIR/option_env_unwrap.rs:18:13
12+
|
13+
LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set");
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: consider using the `env!` macro instead
17+
18+
error: this will panic at run-time if the environment variable doesn't exist at compile-time
19+
--> $DIR/option_env_unwrap.rs:9:9
20+
|
21+
LL | option_env!($env).unwrap()
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
...
24+
LL | let _ = option_env_unwrap!("PATH");
25+
| -------------------------- in this macro invocation
26+
|
27+
= help: consider using the `env!` macro instead
28+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
29+
30+
error: this will panic at run-time if the environment variable doesn't exist at compile-time
31+
--> $DIR/option_env_unwrap.rs:12:9
32+
|
33+
LL | option_env!($env).expect($message)
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
...
36+
LL | let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set");
37+
| ----------------------------------------------------------------- in this macro invocation
38+
|
39+
= help: consider using the `env!` macro instead
40+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
41+
42+
error: this will panic at run-time if the environment variable doesn't exist at compile-time
43+
--> $DIR/option_env_unwrap.rs:21:13
44+
|
45+
LL | let _ = option_env_unwrap_external!("PATH");
46+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
47+
|
48+
= help: consider using the `env!` macro instead
49+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
50+
51+
error: this will panic at run-time if the environment variable doesn't exist at compile-time
52+
--> $DIR/option_env_unwrap.rs:22:13
53+
|
54+
LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
|
57+
= help: consider using the `env!` macro instead
58+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
59+
60+
error: aborting due to 6 previous errors
61+

0 commit comments

Comments
 (0)