mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-17 00:50:33 +00:00
[syntax-errors] Improve error message and range for pre-PEP-614 decorator syntax errors (#16581)
## Summary A small followup to https://github.com/astral-sh/ruff/pull/16386. We now tell the user exactly what it was about their decorator that constituted invalid syntax on Python <3.9, and the range now highlights the specific sub-expression that is invalid rather than highlighting the whole decorator ## Test Plan Inline snapshots are updated, and new ones are added.
This commit is contained in:
parent
4da6936ec4
commit
38bfda94ce
15 changed files with 574 additions and 19 deletions
|
@ -1,6 +1,7 @@
|
|||
use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext, Number};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::TokenKind;
|
||||
use crate::{error::RelaxedDecoratorError, TokenKind};
|
||||
|
||||
/// Set the `ctx` for `Expr::Id`, `Expr::Attribute`, `Expr::Subscript`, `Expr::Starred`,
|
||||
/// `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
|
|||
/// Helper for `parse_decorators` to determine if `expr` is a [`dotted_name`] from the decorator
|
||||
/// grammar before Python 3.9.
|
||||
///
|
||||
/// Returns `Some((error, range))` if `expr` is not a `dotted_name`, or `None` if it is a `dotted_name`.
|
||||
///
|
||||
/// [`dotted_name`]: https://docs.python.org/3.8/reference/compound_stmts.html#grammar-token-dotted-name
|
||||
pub(super) fn is_name_or_attribute_expression(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Attribute(attr) => is_name_or_attribute_expression(&attr.value),
|
||||
Expr::Name(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
pub(super) fn detect_invalid_pre_py39_decorator_node(
|
||||
expr: &Expr,
|
||||
) -> Option<(RelaxedDecoratorError, TextRange)> {
|
||||
let description = match expr {
|
||||
Expr::Name(_) => return None,
|
||||
|
||||
Expr::Attribute(attribute) => {
|
||||
return detect_invalid_pre_py39_decorator_node(&attribute.value)
|
||||
}
|
||||
|
||||
Expr::Call(_) => return Some((RelaxedDecoratorError::CallExpression, expr.range())),
|
||||
|
||||
Expr::NumberLiteral(number) => match &number.value {
|
||||
Number::Int(_) => "an int literal",
|
||||
Number::Float(_) => "a float literal",
|
||||
Number::Complex { .. } => "a complex literal",
|
||||
},
|
||||
|
||||
Expr::BoolOp(_) => "boolean expression",
|
||||
Expr::BinOp(_) => "binary-operation expression",
|
||||
Expr::UnaryOp(_) => "unary-operation expression",
|
||||
Expr::Await(_) => "`await` expression",
|
||||
Expr::Lambda(_) => "lambda expression",
|
||||
Expr::If(_) => "conditional expression",
|
||||
Expr::Dict(_) => "a dict literal",
|
||||
Expr::Set(_) => "a set literal",
|
||||
Expr::List(_) => "a list literal",
|
||||
Expr::Tuple(_) => "a tuple literal",
|
||||
Expr::Starred(_) => "starred expression",
|
||||
Expr::Slice(_) => "slice expression",
|
||||
Expr::BytesLiteral(_) => "a bytes literal",
|
||||
Expr::StringLiteral(_) => "a string literal",
|
||||
Expr::EllipsisLiteral(_) => "an ellipsis literal",
|
||||
Expr::NoneLiteral(_) => "a `None` literal",
|
||||
Expr::BooleanLiteral(_) => "a boolean literal",
|
||||
Expr::ListComp(_) => "a list comprehension",
|
||||
Expr::SetComp(_) => "a set comprehension",
|
||||
Expr::DictComp(_) => "a dict comprehension",
|
||||
Expr::Generator(_) => "generator expression",
|
||||
Expr::Yield(_) => "`yield` expression",
|
||||
Expr::YieldFrom(_) => "`yield from` expression",
|
||||
Expr::Compare(_) => "comparison expression",
|
||||
Expr::FString(_) => "f-string",
|
||||
Expr::Named(_) => "assignment expression",
|
||||
Expr::Subscript(_) => "subscript expression",
|
||||
Expr::IpyEscapeCommand(_) => "IPython escape command",
|
||||
};
|
||||
|
||||
Some((RelaxedDecoratorError::Other(description), expr.range()))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue