From 28507ca34bdce58a371e9bc671495975f3a34d1d Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 21 Oct 2023 12:21:58 +0900 Subject: [PATCH] Recognize full path to std types/functions --- src/auto_enum/expr.rs | 13 +++++++--- src/auto_enum/mod.rs | 6 +++-- src/utils.rs | 18 ++++++++++++++ tests/auto_enum.rs | 57 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/auto_enum/expr.rs b/src/auto_enum/expr.rs index 3264a98d..581b1410 100644 --- a/src/auto_enum/expr.rs +++ b/src/auto_enum/expr.rs @@ -8,7 +8,7 @@ use syn::{ }; use super::{visitor, Context, NAME, NESTED, NEVER}; -use crate::utils::{expr_block, replace_block, replace_expr, Attrs}; +use crate::utils::{expr_block, path_eq, replace_block, replace_expr, Attrs}; /// Visits last expression. /// @@ -57,9 +57,13 @@ pub(super) fn is_unreachable(cx: &Context, expr: &Expr) -> bool { // `Err(expr)?` or `None?`. Expr::Try(ExprTry { expr, .. }) => match &**expr { - Expr::Path(ExprPath { path, qself: None, .. }) => path.is_ident("None"), + Expr::Path(ExprPath { path, qself: None, .. }) => { + path_eq(path, &["std", "core"], &["option", "Option", "None"]) + } Expr::Call(ExprCall { args, func, .. }) if args.len() == 1 => match &**func { - Expr::Path(ExprPath { path, qself: None, .. }) => path.is_ident("Err"), + Expr::Path(ExprPath { path, qself: None, .. }) => { + path_eq(path, &["std", "core"], &["result", "Result", "Err"]) + } _ => false, }, _ => false, @@ -77,7 +81,8 @@ fn is_unreachable_macro(cx: &Context, mac: &Macro) -> bool { const UNREACHABLE_MACROS: &[&str] = &["unreachable", "panic"]; // `unreachable!`, `panic!` or an expression level marker (`marker!` macro). - UNREACHABLE_MACROS.iter().any(|i| mac.path.is_ident(i)) || cx.is_marker_macro(mac) + UNREACHABLE_MACROS.iter().any(|i| path_eq(&mac.path, &["std", "core"], &[i])) + || cx.is_marker_macro(mac) } fn is_unreachable_stmt(cx: &Context, stmt: Option<&Stmt>) -> bool { diff --git a/src/auto_enum/mod.rs b/src/auto_enum/mod.rs index faac3d76..cd13105d 100644 --- a/src/auto_enum/mod.rs +++ b/src/auto_enum/mod.rs @@ -19,7 +19,7 @@ use self::{ context::{Context, VisitLastMode, VisitMode, DEFAULT_MARKER}, expr::child_expr, }; -use crate::utils::{block, expr_block, replace_expr}; +use crate::utils::{block, expr_block, path_eq, replace_expr}; /// The attribute name. const NAME: &str = "auto_enum"; @@ -173,7 +173,9 @@ fn expand_parent_item_fn(cx: &mut Context, item: &mut ItemFn) { colon2_token: None, args, .. - }) if args.len() == 2 && ty.ident == "Result" => { + }) if args.len() == 2 + && path_eq(path, &["std", "core"], &["result", "Result"]) => + { if let ( GenericArgument::Type(_), GenericArgument::Type(Type::ImplTrait(_)), diff --git a/src/utils.rs b/src/utils.rs index 0f4f1a99..3ff49ccd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -49,6 +49,24 @@ pub(crate) fn replace_block(this: &mut Block, f: impl FnOnce(Block) -> Expr) { this.stmts = vec![Stmt::Expr(f(block(stmts)), None)]; } +pub(crate) fn path_eq(path: &syn::Path, expected_crates: &[&str], expected_path: &[&str]) -> bool { + if path.segments.len() == 1 && path.segments[0].ident == expected_path.last().unwrap() { + return true; + } + if path.segments.len() == expected_path.len() + 1 { + if !expected_crates.iter().any(|&c| path.segments[0].ident == c) { + return false; + } + for i in 1..path.segments.len() { + if path.segments[i].ident != expected_path[i - 1] { + return false; + } + } + return true; + } + false +} + // ================================================================================================= // extension traits diff --git a/tests/auto_enum.rs b/tests/auto_enum.rs index 327e3e72..0d0d76a1 100644 --- a/tests/auto_enum.rs +++ b/tests/auto_enum.rs @@ -133,11 +133,21 @@ fn stable() { assert_eq!(no_return3(i).sum::(), *x); } #[auto_enum(Iterator)] - fn no_return4(x: usize) -> impl Iterator { - if x == 0 { + fn no_return4(i: usize) -> impl Iterator { + if i == 0 { 1..8 - } else if x > 3 { + } else if i > 6 { panic!(); + } else if i > 5 { + std::panic!("5"); + } else if i > 4 { + core::panic!("4"); + } else if i > 3 { + unreachable!("3"); + } else if i > 2 { + std::unreachable!("2"); + } else if i > 1 { + core::unreachable!(); } else { (0..2).map(|x| x + 1) } @@ -257,6 +267,9 @@ fn stable() { #[auto_enum(Iterator)] let iter = match x { 0 => 2..8, + 1 => None?, + 2 => std::option::Option::None?, + 3 => core::option::Option::None?, _ => 2..=10, }; @@ -264,6 +277,25 @@ fn stable() { } assert_eq!(return3(10).unwrap().sum::(), 54); + #[auto_enum] + fn return4(x: i32) -> Result, ()> { + if x < 0 { + return Err(()); + } + + #[auto_enum(Iterator)] + let iter = match x { + 0 => 2..8, + 1 => Err(())?, + 2 => std::result::Result::Err(())?, + 3 => core::result::Result::Err(())?, + _ => 2..=10, + }; + + Ok(iter) + } + assert_eq!(return4(10).unwrap().sum::(), 54); + #[auto_enum(Debug, Display)] fn try_operator1(x: i32) -> Result, impl core::fmt::Debug> { if x < 0 { @@ -280,7 +312,9 @@ fn stable() { assert_eq!(try_operator1(10).unwrap().sum::(), 54); #[auto_enum(Debug)] - fn try_operator2(x: i32) -> Result, impl core::fmt::Debug> { + fn try_operator2( + x: i32, + ) -> std::result::Result, impl core::fmt::Debug> { if x < 0 { Err(1_i32)?; } @@ -292,6 +326,21 @@ fn stable() { } assert_eq!(try_operator2(10).unwrap().sum::(), 54); + #[auto_enum(Debug)] + fn try_operator3( + x: i32, + ) -> core::result::Result, impl core::fmt::Debug> { + if x < 0 { + Err(1_i32)?; + } + + match x { + 0 => Err(())?, + _ => Ok(2..=10), + } + } + assert_eq!(try_operator3(10).unwrap().sum::(), 54); + #[auto_enum] fn closure() { #[auto_enum(Iterator)]