[flake8-pyi] Implement PYI062 (duplicate-literal-member) (#11269)

This commit is contained in:
Tushar Sadhwani 2024-05-07 23:58:06 +05:30 committed by GitHub
parent 1a392d34e1
commit 56b4c47d74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 451 additions and 0 deletions

View file

@ -418,6 +418,49 @@ where
inner(func, semantic, expr, None);
}
/// Traverse a "literal" type annotation, applying `func` to each literal member.
///
/// The function is called with each expression in the literal (excluding declarations of nested
/// literals) and the parent expression.
pub fn traverse_literal<'a, F>(func: &mut F, semantic: &SemanticModel, expr: &'a Expr)
where
F: FnMut(&'a Expr, &'a Expr),
{
fn inner<'a, F>(
func: &mut F,
semantic: &SemanticModel,
expr: &'a Expr,
parent: Option<&'a Expr>,
) where
F: FnMut(&'a Expr, &'a Expr),
{
// Ex) Literal[x, y]
if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr {
if semantic.match_typing_expr(value, "Literal") {
match &**slice {
Expr::Tuple(ast::ExprTuple { elts, .. }) => {
// Traverse each element of the tuple within the literal recursively to handle cases
// such as `Literal[..., Literal[...]]
for elt in elts {
inner(func, semantic, elt, Some(expr));
}
}
other => {
inner(func, semantic, other, Some(expr));
}
}
}
} else {
// Otherwise, call the function on expression, if it's not the top-level expression.
if let Some(parent) = parent {
func(expr, parent);
}
}
}
inner(func, semantic, expr, None);
}
/// Abstraction for a type checker, conservatively checks for the intended type(s).
pub trait TypeChecker {
/// Check annotation expression to match the intended type(s).

View file

@ -1350,6 +1350,15 @@ impl<'a> SemanticModel<'a> {
false
}
/// Return `true` if the model is in a nested literal expression (e.g., the inner `Literal` in
/// `Literal[Literal[int, str], float]`).
pub fn in_nested_literal(&self) -> bool {
// Ex) `Literal[Literal[int, str], float]`
self.current_expression_grandparent()
.and_then(Expr::as_subscript_expr)
.is_some_and(|parent| self.match_typing_expr(&parent.value, "Literal"))
}
/// Returns `true` if `left` and `right` are in the same branches of an `if`, `match`, or
/// `try` statement.
///