2021-03-25 13:29:11 -05:00
use clippy_utils ::diagnostics ::span_lint_and_help ;
use clippy_utils ::is_direct_expn_of ;
2022-09-07 19:52:51 -05:00
use rustc_ast ::ast ::{ Expr , ExprKind , MethodCall } ;
2020-02-08 18:44:35 -06:00
use rustc_lint ::{ EarlyContext , EarlyLintPass } ;
use rustc_session ::{ declare_lint_pass , declare_tool_lint } ;
2023-07-31 16:53:53 -05:00
use rustc_span ::{ sym , Span } ;
2020-02-08 18:44:35 -06:00
declare_clippy_lint! {
2021-07-29 05:16:06 -05:00
/// ### What it does
/// Checks for usage of `option_env!(...).unwrap()` and
2020-02-08 18:44:35 -06:00
/// suggests usage of the `env!` macro.
///
2021-07-29 05:16:06 -05:00
/// ### Why is this bad?
/// Unwrapping the result of `option_env!` will panic
2020-02-08 18:44:35 -06:00
/// at run-time if the environment variable doesn't exist, whereas `env!`
/// catches it at compile-time.
///
2021-07-29 05:16:06 -05:00
/// ### Example
2020-02-08 18:44:35 -06:00
/// ```rust,no_run
/// let _ = option_env!("HOME").unwrap();
/// ```
///
/// Is better expressed as:
///
/// ```rust,no_run
/// let _ = env!("HOME");
/// ```
2021-12-06 05:33:31 -06:00
#[ clippy::version = " 1.43.0 " ]
2020-02-08 18:44:35 -06:00
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 ) {
2023-07-31 16:53:53 -05:00
fn lint ( cx : & EarlyContext < '_ > , span : Span ) {
span_lint_and_help (
cx ,
OPTION_ENV_UNWRAP ,
span ,
" this will panic at run-time if the environment variable doesn't exist at compile-time " ,
None ,
" consider using the `env!` macro instead " ,
) ;
2020-02-08 18:44:35 -06:00
}
2023-07-31 16:53:53 -05:00
if let ExprKind ::MethodCall ( box MethodCall { seg , receiver , .. } ) = & expr . kind & &
matches! ( seg . ident . name , sym ::expect | sym ::unwrap ) {
if let ExprKind ::Call ( caller , _ ) = & receiver . kind & &
// If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
is_direct_expn_of ( caller . span , " option_env " ) . is_some ( ) {
lint ( cx , expr . span ) ;
} else if let ExprKind ::Path ( _ , caller ) = & receiver . kind & & // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
is_direct_expn_of ( caller . span , " option_env " ) . is_some ( ) {
lint ( cx , expr . span ) ;
}
}
2020-02-08 18:44:35 -06:00
}
}