|
1 |
| -use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext}; |
| 1 | +use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext, Number}; |
| 2 | +use ruff_text_size::{Ranged, TextRange}; |
2 | 3 |
|
3 |
| -use crate::TokenKind; |
| 4 | +use crate::{error::RelaxedDecoratorError, TokenKind}; |
4 | 5 |
|
5 | 6 | /// Set the `ctx` for `Expr::Id`, `Expr::Attribute`, `Expr::Subscript`, `Expr::Starred`,
|
6 | 7 | /// `Expr::Tuple` and `Expr::List`. If `expr` is either `Expr::Tuple` or `Expr::List`,
|
@@ -47,11 +48,56 @@ pub(super) const fn token_kind_to_cmp_op(tokens: [TokenKind; 2]) -> Option<CmpOp
|
47 | 48 | /// Helper for `parse_decorators` to determine if `expr` is a [`dotted_name`] from the decorator
|
48 | 49 | /// grammar before Python 3.9.
|
49 | 50 | ///
|
| 51 | +/// Returns `Some((error, range))` if `expr` is not a `dotted_name`, or `None` if it is a `dotted_name`. |
| 52 | +/// |
50 | 53 | /// [`dotted_name`]: https://docs.python.org/3.8/reference/compound_stmts.html#grammar-token-dotted-name
|
51 |
| -pub(super) fn is_name_or_attribute_expression(expr: &Expr) -> bool { |
52 |
| - match expr { |
53 |
| - Expr::Attribute(attr) => is_name_or_attribute_expression(&attr.value), |
54 |
| - Expr::Name(_) => true, |
55 |
| - _ => false, |
56 |
| - } |
| 54 | +pub(super) fn detect_invalid_pre_py39_decorator_node( |
| 55 | + expr: &Expr, |
| 56 | +) -> Option<(RelaxedDecoratorError, TextRange)> { |
| 57 | + let description = match expr { |
| 58 | + Expr::Name(_) => return None, |
| 59 | + |
| 60 | + Expr::Attribute(attribute) => { |
| 61 | + return detect_invalid_pre_py39_decorator_node(&attribute.value) |
| 62 | + } |
| 63 | + |
| 64 | + Expr::Call(_) => return Some((RelaxedDecoratorError::CallExpression, expr.range())), |
| 65 | + |
| 66 | + Expr::NumberLiteral(number) => match &number.value { |
| 67 | + Number::Int(_) => "an int literal", |
| 68 | + Number::Float(_) => "a float literal", |
| 69 | + Number::Complex { .. } => "a complex literal", |
| 70 | + }, |
| 71 | + |
| 72 | + Expr::BoolOp(_) => "boolean expression", |
| 73 | + Expr::BinOp(_) => "binary-operation expression", |
| 74 | + Expr::UnaryOp(_) => "unary-operation expression", |
| 75 | + Expr::Await(_) => "`await` expression", |
| 76 | + Expr::Lambda(_) => "lambda expression", |
| 77 | + Expr::If(_) => "conditional expression", |
| 78 | + Expr::Dict(_) => "a dict literal", |
| 79 | + Expr::Set(_) => "a set literal", |
| 80 | + Expr::List(_) => "a list literal", |
| 81 | + Expr::Tuple(_) => "a tuple literal", |
| 82 | + Expr::Starred(_) => "starred expression", |
| 83 | + Expr::Slice(_) => "slice expression", |
| 84 | + Expr::BytesLiteral(_) => "a bytes literal", |
| 85 | + Expr::StringLiteral(_) => "a string literal", |
| 86 | + Expr::EllipsisLiteral(_) => "an ellipsis literal", |
| 87 | + Expr::NoneLiteral(_) => "a `None` literal", |
| 88 | + Expr::BooleanLiteral(_) => "a boolean literal", |
| 89 | + Expr::ListComp(_) => "a list comprehension", |
| 90 | + Expr::SetComp(_) => "a set comprehension", |
| 91 | + Expr::DictComp(_) => "a dict comprehension", |
| 92 | + Expr::Generator(_) => "generator expression", |
| 93 | + Expr::Yield(_) => "`yield` expression", |
| 94 | + Expr::YieldFrom(_) => "`yield from` expression", |
| 95 | + Expr::Compare(_) => "comparison expression", |
| 96 | + Expr::FString(_) => "f-string", |
| 97 | + Expr::Named(_) => "assignment expression", |
| 98 | + Expr::Subscript(_) => "subscript expression", |
| 99 | + Expr::IpyEscapeCommand(_) => "IPython escape command", |
| 100 | + }; |
| 101 | + |
| 102 | + Some((RelaxedDecoratorError::Other(description), expr.range())) |
57 | 103 | }
|
0 commit comments