Skip to content

Commit

Permalink
Merge branch 'main' into PYI049
Browse files Browse the repository at this point in the history
  • Loading branch information
LaBatata101 committed Jul 28, 2023
2 parents 55f4a6e + 134d447 commit 0ef5c7b
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 665 deletions.
15 changes: 5 additions & 10 deletions crates/ruff/resources/test/fixtures/perflint/PERF203.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
# PERF203
for i in range(10):
try: # PERF203
try:
print(f"{i}")
except:
print("error")

# OK
try:
for i in range(10):
print(f"{i}")
except:
print("error")

# OK
i = 0
while i < 10: # PERF203
while i < 10:
try:
print(f"{i}")
except:
print("error")

i += 1

try:
i = 0
while i < 10:
print(f"{i}")
i += 1
except:
print("error")
15 changes: 3 additions & 12 deletions crates/ruff/resources/test/fixtures/ruff/RUF015.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,9 @@

# RUF015
list(x)[0]
list(x)[:1]
list(x)[:1:1]
list(x)[:1:2]
tuple(x)[0]
tuple(x)[:1]
tuple(x)[:1:1]
tuple(x)[:1:2]
list(i for i in x)[0]
list(i for i in x)[:1]
list(i for i in x)[:1:1]
list(i for i in x)[:1:2]
[i for i in x][0]
[i for i in x][:1]
[i for i in x][:1:1]
[i for i in x][:1:2]

# OK (not indexing (solely) the first element)
list(x)
Expand All @@ -29,6 +17,9 @@
[i for i in x]
[i for i in x][1]
[i for i in x][-1]
[i for i in x][:1]
[i for i in x][:1:1]
[i for i in x][:1:2]
[i for i in x][1:]
[i for i in x][:3:2]
[i for i in x][::2]
Expand Down
27 changes: 2 additions & 25 deletions crates/ruff/src/checkers/ast/analyze/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use ruff_diagnostics::{Diagnostic, Fix};

use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::{flake8_import_conventions, flake8_pyi, pyflakes, pylint};
use ruff_diagnostics::{Diagnostic, Fix};

/// Run lint rules over the [`Binding`]s.
pub(crate) fn bindings(checker: &mut Checker) {
Expand All @@ -10,10 +11,7 @@ pub(crate) fn bindings(checker: &mut Checker) {
Rule::InvalidAllObject,
Rule::UnaliasedCollectionsAbcSetImport,
Rule::UnconventionalImportAlias,
Rule::UnusedPrivateTypeVar,
Rule::UnusedVariable,
Rule::UnusedPrivateProtocol,
Rule::UnusedPrivateTypedDict,
]) {
return;
}
Expand Down Expand Up @@ -66,27 +64,6 @@ pub(crate) fn bindings(checker: &mut Checker) {
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::UnusedPrivateTypeVar) {
if let Some(diagnostic) =
flake8_pyi::rules::unused_private_type_var(checker, binding)
{
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::UnusedPrivateProtocol) {
if let Some(diagnostic) =
flake8_pyi::rules::unused_private_protocol(checker, binding)
{
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::UnusedPrivateTypedDict) {
if let Some(diagnostic) =
flake8_pyi::rules::unused_private_typed_dict(checker, binding)
{
checker.diagnostics.push(diagnostic);
}
}
}
}
}
13 changes: 12 additions & 1 deletion crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ruff_python_semantic::{Binding, BindingKind, ScopeKind};

use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::{flake8_type_checking, flake8_unused_arguments, pyflakes, pylint};
use crate::rules::{flake8_pyi, flake8_type_checking, flake8_unused_arguments, pyflakes, pylint};

/// Run lint rules over all deferred scopes in the [`SemanticModel`].
pub(crate) fn deferred_scopes(checker: &mut Checker) {
Expand All @@ -24,6 +24,8 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
Rule::UnusedImport,
Rule::UnusedLambdaArgument,
Rule::UnusedMethodArgument,
Rule::UnusedPrivateProtocol,
Rule::UnusedPrivateTypeVar,
Rule::UnusedStaticMethodArgument,
Rule::UnusedVariable,
]) {
Expand Down Expand Up @@ -214,6 +216,15 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
}
}

if checker.is_stub {
if checker.enabled(Rule::UnusedPrivateTypeVar) {
flake8_pyi::rules::unused_private_type_var(checker, scope, &mut diagnostics);
}
if checker.enabled(Rule::UnusedPrivateProtocol) {
flake8_pyi::rules::unused_private_protocol(checker, scope, &mut diagnostics);
}
}

if matches!(
scope.kind,
ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Lambda(_)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_semantic::Binding;
use ruff_python_semantic::Scope;

use crate::checkers::ast::Checker;

Expand Down Expand Up @@ -116,69 +116,88 @@ impl Violation for UnusedPrivateTypedDict {
}

/// PYI018
pub(crate) fn unused_private_type_var(checker: &Checker, binding: &Binding) -> Option<Diagnostic> {
if !(binding.kind.is_assignment() && binding.is_private_declaration()) {
return None;
}
if binding.is_used() {
return None;
}

let Some(source) = binding.source else {
return None;
};
let Stmt::Assign(ast::StmtAssign { targets, value, .. }) = checker.semantic().stmts[source]
else {
return None;
};
let [Expr::Name(ast::ExprName { id, .. })] = &targets[..] else {
return None;
};
let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else {
return None;
};
if !checker.semantic().match_typing_expr(func, "TypeVar") {
return None;
pub(crate) fn unused_private_type_var(
checker: &Checker,
scope: &Scope,
diagnostics: &mut Vec<Diagnostic>,
) {
for binding in scope
.binding_ids()
.map(|binding_id| checker.semantic().binding(binding_id))
{
if !(binding.kind.is_assignment() && binding.is_private_declaration()) {
continue;
}
if binding.is_used() {
continue;
}

let Some(source) = binding.source else {
continue;
};
let Stmt::Assign(ast::StmtAssign { targets, value, .. }) = checker.semantic().stmts[source]
else {
continue;
};
let [Expr::Name(ast::ExprName { id, .. })] = &targets[..] else {
continue;
};
let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else {
continue;
};
if !checker.semantic().match_typing_expr(func, "TypeVar") {
continue;
}

diagnostics.push(Diagnostic::new(
UnusedPrivateTypeVar {
name: id.to_string(),
},
binding.range,
));
}

Some(Diagnostic::new(
UnusedPrivateTypeVar {
name: id.to_string(),
},
binding.range,
))
}

/// PYI046
pub(crate) fn unused_private_protocol(checker: &Checker, binding: &Binding) -> Option<Diagnostic> {
if !(binding.kind.is_class_definition() && binding.is_private_declaration()) {
return None;
}
if binding.is_used() {
return None;
}

let Some(source) = binding.source else {
return None;
};
let Stmt::ClassDef(ast::StmtClassDef { name, bases, .. }) = checker.semantic().stmts[source]
else {
return None;
};

if !bases
.iter()
.any(|base| checker.semantic().match_typing_expr(base, "Protocol"))
pub(crate) fn unused_private_protocol(
checker: &Checker,
scope: &Scope,
diagnostics: &mut Vec<Diagnostic>,
) {
for binding in scope
.binding_ids()
.map(|binding_id| checker.semantic().binding(binding_id))
{
return None;
if !(binding.kind.is_class_definition() && binding.is_private_declaration()) {
continue;
}
if binding.is_used() {
continue;
}

let Some(source) = binding.source else {
continue;
};
let Stmt::ClassDef(ast::StmtClassDef { name, bases, .. }) =
checker.semantic().stmts[source]
else {
continue;
};

if !bases
.iter()
.any(|base| checker.semantic().match_typing_expr(base, "Protocol"))
{
continue;
}

diagnostics.push(Diagnostic::new(
UnusedPrivateProtocol {
name: name.to_string(),
},
binding.range,
));
}

Some(Diagnostic::new(
UnusedPrivateProtocol {
name: name.to_string(),
},
binding.range,
))
}

/// PYI049
Expand Down
21 changes: 11 additions & 10 deletions crates/ruff/src/rules/perflint/rules/try_except_in_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ pub(crate) fn try_except_in_loop(checker: &mut Checker, body: &[Stmt]) {
return;
}

checker.diagnostics.extend(body.iter().filter_map(|stmt| {
if let Stmt::Try(ast::StmtTry { handlers, .. }) = stmt {
handlers
.iter()
.next()
.map(|handler| Diagnostic::new(TryExceptInLoop, handler.range()))
} else {
None
}
}));
let [Stmt::Try(ast::StmtTry { handlers, .. })] = body else {
return;
};

let Some(handler) = handlers.first() else {
return;
};

checker
.diagnostics
.push(Diagnostic::new(TryExceptInLoop, handler.range()));
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
---
source: crates/ruff/src/rules/perflint/mod.rs
---
PERF203.py:4:5: PERF203 `try`-`except` within a loop incurs performance overhead
PERF203.py:5:5: PERF203 `try`-`except` within a loop incurs performance overhead
|
2 | try: # PERF203
3 | print(f"{i}")
4 | except:
3 | try:
4 | print(f"{i}")
5 | except:
| _____^
5 | | print("error")
6 | | print("error")
| |______________________^ PERF203
6 |
7 | try:
7 |
8 | # OK
|

PERF203.py:17:5: PERF203 `try`-`except` within a loop incurs performance overhead
|
15 | try:
16 | print(f"{i}")
17 | except:
| _____^
18 | | print("error")
| |______________________^ PERF203
19 |
20 | i += 1
|


Loading

0 comments on commit 0ef5c7b

Please sign in to comment.