diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index a5639404fafd4..77132341b9c99 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -31,6 +31,9 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values .map_label = after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items .suggestion = you might have meant to use `Iterator::for_each` +lint_option_env_unwrap = incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + .suggestion = consider using the `env!` macro instead + lint_non_binding_let_on_sync_lock = non-binding let on a synchronization lock diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index dfddfe09ab3c1..ddd5222b63c31 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -72,6 +72,7 @@ mod non_fmt_panic; mod nonstandard_style; mod noop_method_call; mod opaque_hidden_inferred_bound; +mod option_env_unwrap; mod pass_by_value; mod passes; mod redundant_semicolon; @@ -111,6 +112,7 @@ use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; use noop_method_call::*; use opaque_hidden_inferred_bound::*; +use option_env_unwrap::*; use pass_by_value::*; use redundant_semicolon::*; use traits::*; @@ -211,6 +213,7 @@ late_lint_methods!( BoxPointers: BoxPointers, PathStatements: PathStatements, LetUnderscore: LetUnderscore, + OptionEnvUnwrap: OptionEnvUnwrap, // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, NonUpperCaseGlobals: NonUpperCaseGlobals, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 8e48806b50447..a9aeb019713ea 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -801,6 +801,27 @@ pub struct MappingToUnit { pub replace: String, } +// option_env_unwrap.rs +#[derive(LintDiagnostic)] +#[diag(lint_option_env_unwrap)] +pub struct OptionEnvUnwrapDiag { + #[subdiagnostic] + pub suggestion: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion( + lint_suggestion, + style = "verbose", + code = "env!({replace})", + applicability = "machine-applicable" +)] +pub struct OptionEnvUnwrapSuggestion { + #[primary_span] + pub span: Span, + pub replace: String, +} + // internal.rs #[derive(LintDiagnostic)] #[diag(lint_default_hash_types)] diff --git a/compiler/rustc_lint/src/option_env_unwrap.rs b/compiler/rustc_lint/src/option_env_unwrap.rs new file mode 100644 index 0000000000000..658ed8ce5c10b --- /dev/null +++ b/compiler/rustc_lint/src/option_env_unwrap.rs @@ -0,0 +1,95 @@ +use rustc_hir::{Expr, ExprKind}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::{sym, ExpnKind, MacroKind, Span}; + +use crate::{ + lints::{OptionEnvUnwrapDiag, OptionEnvUnwrapSuggestion}, + LateContext, LateLintPass, LintContext, +}; + +declare_lint! { + /// The `incorrect_option_env_unwraps` lint checks for usage of + /// `option_env!(...).unwrap()` and suggests using the `env!` macro instead. + /// + /// ### Example + /// + /// ```rust,no_run + /// let _ = option_env!("HOME").unwrap(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unwrapping the result of `option_env!` will panic + /// at run-time if the environment variable doesn't exist, whereas `env!` + /// catches it at compile-time. + INCORRECT_OPTION_ENV_UNWRAPS, + Warn, + "using `option_env!(...).unwrap()` to get environment variable" +} + +declare_lint_pass!(OptionEnvUnwrap => [INCORRECT_OPTION_ENV_UNWRAPS]); + +impl<'tcx> LateLintPass<'tcx> for OptionEnvUnwrap { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + let ExprKind::MethodCall(_, receiver, _, _) = expr.kind else { return; }; + + let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { return; }; + + if !matches!( + cx.tcx.get_diagnostic_name(method_def_id), + Some(sym::option_unwrap | sym::option_expect) + ) { + return; + } + + // Handle found environment variable `Option::Some(...)` + let caller_span = if let ExprKind::Call(caller, _) = &receiver.kind { + caller.span + // Handle not found environment variable `Option::None` + } else if let ExprKind::Path(qpath) = &receiver.kind { + qpath.span() + } else { + return; + }; + + if is_direct_expn_of_option_env(caller_span) { + cx.emit_spanned_lint( + INCORRECT_OPTION_ENV_UNWRAPS, + expr.span, + OptionEnvUnwrapDiag { + suggestion: extract_inner_macro_call(cx, caller_span) + .map(|replace| OptionEnvUnwrapSuggestion { span: expr.span, replace }), + }, + ) + } + } +} + +fn is_direct_expn_of_option_env(span: Span) -> bool { + if span.from_expansion() { + let data = span.ctxt().outer_expn_data(); + + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind { + return mac_name == sym::option_env; + } + } + + false +} + +/// Given a Span representing a macro call: `option_env! ( \"j)j\")` get the inner +/// content, ie. ` \"j)j\"` +fn extract_inner_macro_call(cx: &LateContext<'_>, span: Span) -> Option { + let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?; + + let mut inner = snippet.chars().skip_while(|c| !"([{".contains(*c)).collect::(); + + // remove last character, ie one of `)]}` + inner.pop()?; + // remove first character, ie one of `([{` + inner.remove(0); + + Some(inner) +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a328447aca9de..4bed6b1e252ba 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -786,7 +786,7 @@ pub fn host_triple() -> &'static str { // Instead of grabbing the host triple (for the current host), we grab (at // compile time) the target triple that this rustc is built with and // calling that (at runtime) the host triple. - (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE") + env!("CFG_COMPILER_HOST_TRIPLE") } impl Default for Options { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 874d578fe1db3..14e038c411cd9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1061,7 +1061,9 @@ symbols! { optin_builtin_traits, option, option_env, + option_expect, option_payload_ptr, + option_unwrap, options, or, or_patterns, diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ec1ef3cf43d12..ae0fe856b03b0 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -892,6 +892,7 @@ impl Option { #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_diagnostic_item = "option_expect"] pub const fn expect(self, msg: &str) -> T { match self { Some(val) => val, @@ -929,6 +930,7 @@ impl Option { #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_diagnostic_item = "option_unwrap"] pub const fn unwrap(self) -> T { match self { Some(val) => val, diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 04993e4928799..25057ea689b26 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -495,7 +495,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::PTR_EQ_INFO, crate::operators::SELF_ASSIGNMENT_INFO, crate::operators::VERBOSE_BIT_MASK_INFO, - crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO, crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO, crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO, crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 3517842a01e7b..3ff0f842008c9 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -237,7 +237,6 @@ mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; mod operators; -mod option_env_unwrap; mod option_if_let_else; mod overflow_check_conditional; mod panic_in_result_fn; @@ -811,7 +810,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: max_fn_params_bools, )) }); - store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); store.register_late_pass(|_| Box::::default()); diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs deleted file mode 100644 index 377bddeaa5fea..0000000000000 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ /dev/null @@ -1,56 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_direct_expn_of; -use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, MethodCall}; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `option_env!(...).unwrap()` and - /// suggests usage of the `env!` macro. - /// - /// ### Why is this bad? - /// Unwrapping the result of `option_env!` will panic - /// at run-time if the environment variable doesn't exist, whereas `env!` - /// catches it at compile-time. - /// - /// ### Example - /// ```rust,no_run - /// let _ = option_env!("HOME").unwrap(); - /// ``` - /// - /// Is better expressed as: - /// - /// ```rust,no_run - /// let _ = env!("HOME"); - /// ``` - #[clippy::version = "1.43.0"] - pub OPTION_ENV_UNWRAP, - correctness, - "using `option_env!(...).unwrap()` to get environment variable" -} - -declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]); - -impl EarlyLintPass for OptionEnvUnwrap { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if_chain! { - if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap); - if let ExprKind::Call(caller, _) = &receiver.kind; - if is_direct_expn_of(caller.span, "option_env").is_some(); - then { - span_lint_and_help( - cx, - OPTION_ENV_UNWRAP, - expr.span, - "this will panic at run-time if the environment variable doesn't exist at compile-time", - None, - "consider using the `env!` macro instead" - ); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 52e22c0c6303c..2810afdd1fa4d 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -49,4 +49,5 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"), ("clippy::unknown_clippy_lints", "unknown_lints"), ("clippy::unused_label", "unused_labels"), + ("clippy::option_env_unwrap", "incorrect_option_env_unwraps"), ]; diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs deleted file mode 100644 index ee1fe3f1fc0fc..0000000000000 --- a/src/tools/clippy/tests/ui/option_env_unwrap.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@aux-build:proc_macros.rs -#![warn(clippy::option_env_unwrap)] -#![allow(clippy::map_flatten)] - -extern crate proc_macros; -use proc_macros::{external, inline_macros}; - -#[inline_macros] -fn main() { - let _ = option_env!("PATH").unwrap(); - let _ = option_env!("PATH").expect("environment variable PATH isn't set"); - let _ = inline!(option_env!($"PATH").unwrap()); - let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); - let _ = external!(option_env!($"PATH").unwrap()); - let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); -} diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr deleted file mode 100644 index 7bba62686eecf..0000000000000 --- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:10:13 - | -LL | let _ = option_env!("PATH").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using the `env!` macro instead - = note: `-D clippy::option-env-unwrap` implied by `-D warnings` - -error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:11:13 - | -LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using the `env!` macro instead - -error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:12:21 - | -LL | let _ = inline!(option_env!($"PATH").unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using the `env!` macro instead - = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:13:21 - | -LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using the `env!` macro instead - = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:14:13 - | -LL | let _ = external!(option_env!($"PATH").unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using the `env!` macro instead - = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:15:13 - | -LL | let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using the `env!` macro instead - = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 6 previous errors - diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 9036f89261288..4f0fb563e3532 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -45,6 +45,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![allow(option_env_unwrap)] #![warn(clippy::almost_complete_range)] #![warn(clippy::disallowed_names)] #![warn(clippy::blocks_in_if_conditions)] @@ -92,5 +93,6 @@ #![warn(temporary_cstring_as_ptr)] #![warn(unknown_lints)] #![warn(unused_labels)] +#![warn(incorrect_option_env_unwraps)] fn main() {} diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 43cabe810f344..7e784b31319a7 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -45,6 +45,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![allow(option_env_unwrap)] #![warn(clippy::almost_complete_letter_range)] #![warn(clippy::blacklisted_name)] #![warn(clippy::block_in_if_condition_expr)] @@ -92,5 +93,6 @@ #![warn(clippy::temporary_cstring_as_ptr)] #![warn(clippy::unknown_clippy_lints)] #![warn(clippy::unused_label)] +#![warn(clippy::incorrect_option_env_unwraps)] fn main() {} diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 1ad7cf412c896..096a1c9b19f66 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,280 +7,288 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `drop_copy` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `drop_copy` error: lint `clippy::drop_ref` has been renamed to `drop_ref` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `drop_ref` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forget_copy` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_copy` error: lint `clippy::forget_ref` has been renamed to `forget_ref` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_ref` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 47 previous errors +error: unknown lint: `clippy::incorrect_option_env_unwraps` + --> $DIR/rename.rs:96:9 + | +LL | #![warn(clippy::incorrect_option_env_unwraps)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `incorrect_option_env_unwraps` + | + = note: `-D unknown-lints` implied by `-D warnings` + +error: aborting due to 48 previous errors diff --git a/tests/ui/lint/option_env_unwrap.rs b/tests/ui/lint/option_env_unwrap.rs new file mode 100644 index 0000000000000..916e537d6fb6f --- /dev/null +++ b/tests/ui/lint/option_env_unwrap.rs @@ -0,0 +1,30 @@ +// check-pass + +fn main() { + let _ = option_env!("PATH").unwrap(); + //~^ WARN incorrect usage of `option_env!` + let _ = option_env!("PATH").expect("environment variable PATH isn't set"); + //~^ WARN incorrect usage of `option_env!` + let _ = option_env!("NOT_IN_ENV").unwrap(); + //~^ WARN incorrect usage of `option_env!` + let _ = option_env!("NOT_IN_ENV").expect("environment variable NOT_IN_ENV isn't set"); + //~^ WARN incorrect usage of `option_env!` + let _ = assert_ne!(option_env!("PATH").unwrap(), "a"); + //~^ WARN incorrect usage of `option_env!` + + // just verify suggestion + let _ = option_env!("PATH") + //~^ WARN incorrect usage of `option_env!` + .unwrap(); + let _ = option_env!( + //~^ WARN incorrect usage of `option_env!` + "PATH" + ) + . unwrap(); + let _ = (option_env!("NOT_IN_ENV")).expect("aaa"); + //~^ WARN incorrect usage of `option_env!` + + // should not lint + let _ = option_env!("PATH").unwrap_or("..."); + let _ = option_env!("PATH").unwrap_or_else(|| "..."); +} diff --git a/tests/ui/lint/option_env_unwrap.stderr b/tests/ui/lint/option_env_unwrap.stderr new file mode 100644 index 0000000000000..23b499a38cfd1 --- /dev/null +++ b/tests/ui/lint/option_env_unwrap.stderr @@ -0,0 +1,102 @@ +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:4:13 + | +LL | let _ = option_env!("PATH").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incorrect_option_env_unwraps)]` on by default +help: consider using the `env!` macro instead + | +LL | let _ = env!("PATH"); + | ~~~~~~~~~~~~ + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:6:13 + | +LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the `env!` macro instead + | +LL | let _ = env!("PATH"); + | ~~~~~~~~~~~~ + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:8:13 + | +LL | let _ = option_env!("NOT_IN_ENV").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the `env!` macro instead + | +LL | let _ = env!("NOT_IN_ENV"); + | ~~~~~~~~~~~~~~~~~~ + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:10:13 + | +LL | let _ = option_env!("NOT_IN_ENV").expect("environment variable NOT_IN_ENV isn't set"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the `env!` macro instead + | +LL | let _ = env!("NOT_IN_ENV"); + | ~~~~~~~~~~~~~~~~~~ + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:12:24 + | +LL | let _ = assert_ne!(option_env!("PATH").unwrap(), "a"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the `env!` macro instead + | +LL | let _ = assert_ne!(env!("PATH"), "a"); + | ~~~~~~~~~~~~ + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:16:13 + | +LL | let _ = option_env!("PATH") + | _____________^ +LL | | +LL | | .unwrap(); + | |_________________^ + | +help: consider using the `env!` macro instead + | +LL | let _ = env!("PATH"); + | ~~~~~~~~~~~~ + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:19:13 + | +LL | let _ = option_env!( + | _____________^ +LL | | +LL | | "PATH" +LL | | ) +LL | | . unwrap(); + | |__________________^ + | +help: consider using the `env!` macro instead + | +LL ~ let _ = env!( +LL + +LL + "PATH" +LL ~ ); + | + +warning: incorrect usage of `option_env!`, it will panic at run-time if the environment variable doesn't exist at compile-time + --> $DIR/option_env_unwrap.rs:24:13 + | +LL | let _ = (option_env!("NOT_IN_ENV")).expect("aaa"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the `env!` macro instead + | +LL | let _ = env!("NOT_IN_ENV"); + | ~~~~~~~~~~~~~~~~~~ + +warning: 8 warnings emitted +