Reduce unnecessary allocations for keyword detection (#5817)

This commit is contained in:
Charlie Marsh 2023-07-16 22:22:30 -04:00 committed by GitHub
parent 1c0376a72d
commit 94998aedef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 77 deletions

View file

@ -2623,7 +2623,7 @@ where
} }
} }
if self.enabled(Rule::NoExplicitStacklevel) { if self.enabled(Rule::NoExplicitStacklevel) {
flake8_bugbear::rules::no_explicit_stacklevel(self, func, args, keywords); flake8_bugbear::rules::no_explicit_stacklevel(self, func, keywords);
} }
if self.enabled(Rule::UnnecessaryDictKwargs) { if self.enabled(Rule::UnnecessaryDictKwargs) {
flake8_pie::rules::unnecessary_dict_kwargs(self, expr, keywords); flake8_pie::rules::unnecessary_dict_kwargs(self, expr, keywords);
@ -2647,7 +2647,7 @@ where
flake8_bandit::rules::snmp_weak_cryptography(self, func, args, keywords); flake8_bandit::rules::snmp_weak_cryptography(self, func, args, keywords);
} }
if self.enabled(Rule::Jinja2AutoescapeFalse) { if self.enabled(Rule::Jinja2AutoescapeFalse) {
flake8_bandit::rules::jinja2_autoescape_false(self, func, args, keywords); flake8_bandit::rules::jinja2_autoescape_false(self, func, keywords);
} }
if self.enabled(Rule::HardcodedPasswordFuncArg) { if self.enabled(Rule::HardcodedPasswordFuncArg) {
flake8_bandit::rules::hardcoded_password_func_arg(self, keywords); flake8_bandit::rules::hardcoded_password_func_arg(self, keywords);
@ -2661,15 +2661,13 @@ where
); );
} }
if self.enabled(Rule::RequestWithoutTimeout) { if self.enabled(Rule::RequestWithoutTimeout) {
flake8_bandit::rules::request_without_timeout(self, func, args, keywords); flake8_bandit::rules::request_without_timeout(self, func, keywords);
} }
if self.enabled(Rule::ParamikoCall) { if self.enabled(Rule::ParamikoCall) {
flake8_bandit::rules::paramiko_call(self, func); flake8_bandit::rules::paramiko_call(self, func);
} }
if self.enabled(Rule::LoggingConfigInsecureListen) { if self.enabled(Rule::LoggingConfigInsecureListen) {
flake8_bandit::rules::logging_config_insecure_listen( flake8_bandit::rules::logging_config_insecure_listen(self, func, keywords);
self, func, args, keywords,
);
} }
if self.any_enabled(&[ if self.any_enabled(&[
Rule::SubprocessWithoutShellEqualsTrue, Rule::SubprocessWithoutShellEqualsTrue,

View file

@ -2,7 +2,6 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::SimpleCallArgs;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -30,12 +29,7 @@ impl Violation for Jinja2AutoescapeFalse {
} }
/// S701 /// S701
pub(crate) fn jinja2_autoescape_false( pub(crate) fn jinja2_autoescape_false(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
checker: &mut Checker,
func: &Expr,
args: &[Expr],
keywords: &[Keyword],
) {
if checker if checker
.semantic() .semantic()
.resolve_call_path(func) .resolve_call_path(func)
@ -43,10 +37,13 @@ pub(crate) fn jinja2_autoescape_false(
matches!(call_path.as_slice(), ["jinja2", "Environment"]) matches!(call_path.as_slice(), ["jinja2", "Environment"])
}) })
{ {
let call_args = SimpleCallArgs::new(args, keywords); if let Some(keyword) = keywords.iter().find(|keyword| {
keyword
if let Some(autoescape_arg) = call_args.keyword_argument("autoescape") { .arg
match autoescape_arg { .as_ref()
.map_or(false, |arg| arg.as_str() == "autoescape")
}) {
match &keyword.value {
Expr::Constant(ast::ExprConstant { Expr::Constant(ast::ExprConstant {
value: Constant::Bool(true), value: Constant::Bool(true),
.. ..
@ -56,14 +53,14 @@ pub(crate) fn jinja2_autoescape_false(
if id != "select_autoescape" { if id != "select_autoescape" {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
Jinja2AutoescapeFalse { value: true }, Jinja2AutoescapeFalse { value: true },
autoescape_arg.range(), keyword.range(),
)); ));
} }
} }
} }
_ => checker.diagnostics.push(Diagnostic::new( _ => checker.diagnostics.push(Diagnostic::new(
Jinja2AutoescapeFalse { value: true }, Jinja2AutoescapeFalse { value: true },
autoescape_arg.range(), keyword.range(),
)), )),
} }
} else { } else {

View file

@ -2,7 +2,6 @@ use rustpython_parser::ast::{Expr, Keyword, Ranged};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::SimpleCallArgs;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -20,7 +19,6 @@ impl Violation for LoggingConfigInsecureListen {
pub(crate) fn logging_config_insecure_listen( pub(crate) fn logging_config_insecure_listen(
checker: &mut Checker, checker: &mut Checker,
func: &Expr, func: &Expr,
args: &[Expr],
keywords: &[Keyword], keywords: &[Keyword],
) { ) {
if checker if checker
@ -30,12 +28,17 @@ pub(crate) fn logging_config_insecure_listen(
matches!(call_path.as_slice(), ["logging", "config", "listen"]) matches!(call_path.as_slice(), ["logging", "config", "listen"])
}) })
{ {
let call_args = SimpleCallArgs::new(args, keywords); if keywords.iter().any(|keyword| {
keyword
.arg
.as_ref()
.map_or(false, |arg| arg.as_str() == "verify")
}) {
return;
}
if call_args.keyword_argument("verify").is_none() {
checker checker
.diagnostics .diagnostics
.push(Diagnostic::new(LoggingConfigInsecureListen, func.range())); .push(Diagnostic::new(LoggingConfigInsecureListen, func.range()));
} }
} }
}

View file

@ -63,18 +63,18 @@ pub(crate) fn request_with_no_cert_validation(
_ => None, _ => None,
}) })
{ {
if let Some(arg) = keywords.iter().find(|keyword| { if let Some(keyword) = keywords.iter().find(|keyword| {
keyword keyword
.arg .arg
.as_ref() .as_ref()
.map_or(false, |arg| arg.as_str() == "verify") .map_or(false, |arg| arg.as_str() == "verify")
}) { }) {
if is_const_false(&arg.value) { if is_const_false(&keyword.value) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
RequestWithNoCertValidation { RequestWithNoCertValidation {
string: target.to_string(), string: target.to_string(),
}, },
arg.range(), keyword.range(),
)); ));
} }
} }

View file

@ -2,7 +2,7 @@ use rustpython_parser::ast::{Expr, Keyword, Ranged};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{is_const_none, SimpleCallArgs}; use ruff_python_ast::helpers::is_const_none;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -49,12 +49,7 @@ impl Violation for RequestWithoutTimeout {
} }
/// S113 /// S113
pub(crate) fn request_without_timeout( pub(crate) fn request_without_timeout(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
checker: &mut Checker,
func: &Expr,
args: &[Expr],
keywords: &[Keyword],
) {
if checker if checker
.semantic() .semantic()
.resolve_call_path(func) .resolve_call_path(func)
@ -68,12 +63,16 @@ pub(crate) fn request_without_timeout(
) )
}) })
{ {
let call_args = SimpleCallArgs::new(args, keywords); if let Some(keyword) = keywords.iter().find(|keyword| {
if let Some(timeout) = call_args.keyword_argument("timeout") { keyword
if is_const_none(timeout) { .arg
.as_ref()
.map_or(false, |arg| arg.as_str() == "timeout")
}) {
if is_const_none(&keyword.value) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
RequestWithoutTimeout { implicit: false }, RequestWithoutTimeout { implicit: false },
timeout.range(), keyword.range(),
)); ));
} }
} else { } else {

View file

@ -50,7 +50,7 @@ pub(crate) fn snmp_insecure_version(checker: &mut Checker, func: &Expr, keywords
matches!(call_path.as_slice(), ["pysnmp", "hlapi", "CommunityData"]) matches!(call_path.as_slice(), ["pysnmp", "hlapi", "CommunityData"])
}) })
{ {
if let Some(arg) = keywords.iter().find(|keyword| { if let Some(keyword) = keywords.iter().find(|keyword| {
keyword keyword
.arg .arg
.as_ref() .as_ref()
@ -59,12 +59,12 @@ pub(crate) fn snmp_insecure_version(checker: &mut Checker, func: &Expr, keywords
if let Expr::Constant(ast::ExprConstant { if let Expr::Constant(ast::ExprConstant {
value: Constant::Int(value), value: Constant::Int(value),
.. ..
}) = &arg.value }) = &keyword.value
{ {
if value.is_zero() || value.is_one() { if value.is_zero() || value.is_one() {
checker checker
.diagnostics .diagnostics
.push(Diagnostic::new(SnmpInsecureVersion, arg.range())); .push(Diagnostic::new(SnmpInsecureVersion, keyword.range()));
} }
} }
} }

View file

@ -11,11 +11,11 @@ S113.py:3:1: S113 Probable use of requests call without timeout
5 | requests.get('https://gmail.com', timeout=5) 5 | requests.get('https://gmail.com', timeout=5)
| |
S113.py:4:43: S113 Probable use of requests call with timeout set to `None` S113.py:4:35: S113 Probable use of requests call with timeout set to `None`
| |
3 | requests.get('https://gmail.com') 3 | requests.get('https://gmail.com')
4 | requests.get('https://gmail.com', timeout=None) 4 | requests.get('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
5 | requests.get('https://gmail.com', timeout=5) 5 | requests.get('https://gmail.com', timeout=5)
6 | requests.post('https://gmail.com') 6 | requests.post('https://gmail.com')
| |
@ -30,12 +30,12 @@ S113.py:6:1: S113 Probable use of requests call without timeout
8 | requests.post('https://gmail.com', timeout=5) 8 | requests.post('https://gmail.com', timeout=5)
| |
S113.py:7:44: S113 Probable use of requests call with timeout set to `None` S113.py:7:36: S113 Probable use of requests call with timeout set to `None`
| |
5 | requests.get('https://gmail.com', timeout=5) 5 | requests.get('https://gmail.com', timeout=5)
6 | requests.post('https://gmail.com') 6 | requests.post('https://gmail.com')
7 | requests.post('https://gmail.com', timeout=None) 7 | requests.post('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
8 | requests.post('https://gmail.com', timeout=5) 8 | requests.post('https://gmail.com', timeout=5)
9 | requests.put('https://gmail.com') 9 | requests.put('https://gmail.com')
| |
@ -50,12 +50,12 @@ S113.py:9:1: S113 Probable use of requests call without timeout
11 | requests.put('https://gmail.com', timeout=5) 11 | requests.put('https://gmail.com', timeout=5)
| |
S113.py:10:43: S113 Probable use of requests call with timeout set to `None` S113.py:10:35: S113 Probable use of requests call with timeout set to `None`
| |
8 | requests.post('https://gmail.com', timeout=5) 8 | requests.post('https://gmail.com', timeout=5)
9 | requests.put('https://gmail.com') 9 | requests.put('https://gmail.com')
10 | requests.put('https://gmail.com', timeout=None) 10 | requests.put('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
11 | requests.put('https://gmail.com', timeout=5) 11 | requests.put('https://gmail.com', timeout=5)
12 | requests.delete('https://gmail.com') 12 | requests.delete('https://gmail.com')
| |
@ -70,12 +70,12 @@ S113.py:12:1: S113 Probable use of requests call without timeout
14 | requests.delete('https://gmail.com', timeout=5) 14 | requests.delete('https://gmail.com', timeout=5)
| |
S113.py:13:46: S113 Probable use of requests call with timeout set to `None` S113.py:13:38: S113 Probable use of requests call with timeout set to `None`
| |
11 | requests.put('https://gmail.com', timeout=5) 11 | requests.put('https://gmail.com', timeout=5)
12 | requests.delete('https://gmail.com') 12 | requests.delete('https://gmail.com')
13 | requests.delete('https://gmail.com', timeout=None) 13 | requests.delete('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
14 | requests.delete('https://gmail.com', timeout=5) 14 | requests.delete('https://gmail.com', timeout=5)
15 | requests.patch('https://gmail.com') 15 | requests.patch('https://gmail.com')
| |
@ -90,12 +90,12 @@ S113.py:15:1: S113 Probable use of requests call without timeout
17 | requests.patch('https://gmail.com', timeout=5) 17 | requests.patch('https://gmail.com', timeout=5)
| |
S113.py:16:45: S113 Probable use of requests call with timeout set to `None` S113.py:16:37: S113 Probable use of requests call with timeout set to `None`
| |
14 | requests.delete('https://gmail.com', timeout=5) 14 | requests.delete('https://gmail.com', timeout=5)
15 | requests.patch('https://gmail.com') 15 | requests.patch('https://gmail.com')
16 | requests.patch('https://gmail.com', timeout=None) 16 | requests.patch('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
17 | requests.patch('https://gmail.com', timeout=5) 17 | requests.patch('https://gmail.com', timeout=5)
18 | requests.options('https://gmail.com') 18 | requests.options('https://gmail.com')
| |
@ -110,12 +110,12 @@ S113.py:18:1: S113 Probable use of requests call without timeout
20 | requests.options('https://gmail.com', timeout=5) 20 | requests.options('https://gmail.com', timeout=5)
| |
S113.py:19:47: S113 Probable use of requests call with timeout set to `None` S113.py:19:39: S113 Probable use of requests call with timeout set to `None`
| |
17 | requests.patch('https://gmail.com', timeout=5) 17 | requests.patch('https://gmail.com', timeout=5)
18 | requests.options('https://gmail.com') 18 | requests.options('https://gmail.com')
19 | requests.options('https://gmail.com', timeout=None) 19 | requests.options('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
20 | requests.options('https://gmail.com', timeout=5) 20 | requests.options('https://gmail.com', timeout=5)
21 | requests.head('https://gmail.com') 21 | requests.head('https://gmail.com')
| |
@ -130,12 +130,12 @@ S113.py:21:1: S113 Probable use of requests call without timeout
23 | requests.head('https://gmail.com', timeout=5) 23 | requests.head('https://gmail.com', timeout=5)
| |
S113.py:22:44: S113 Probable use of requests call with timeout set to `None` S113.py:22:36: S113 Probable use of requests call with timeout set to `None`
| |
20 | requests.options('https://gmail.com', timeout=5) 20 | requests.options('https://gmail.com', timeout=5)
21 | requests.head('https://gmail.com') 21 | requests.head('https://gmail.com')
22 | requests.head('https://gmail.com', timeout=None) 22 | requests.head('https://gmail.com', timeout=None)
| ^^^^ S113 | ^^^^^^^^^^^^ S113
23 | requests.head('https://gmail.com', timeout=5) 23 | requests.head('https://gmail.com', timeout=5)
| |

View file

@ -1,32 +1,32 @@
--- ---
source: crates/ruff/src/rules/flake8_bandit/mod.rs source: crates/ruff/src/rules/flake8_bandit/mod.rs
--- ---
S701.py:9:68: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function. S701.py:9:57: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
| |
7 | templateEnv = jinja2.Environment(autoescape=True, 7 | templateEnv = jinja2.Environment(autoescape=True,
8 | loader=templateLoader ) 8 | loader=templateLoader )
9 | Environment(loader=templateLoader, load=templateLoader, autoescape=something) # S701 9 | Environment(loader=templateLoader, load=templateLoader, autoescape=something) # S701
| ^^^^^^^^^ S701 | ^^^^^^^^^^^^^^^^^^^^ S701
10 | templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) # S701 10 | templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) # S701
11 | Environment(loader=templateLoader, 11 | Environment(loader=templateLoader,
| |
S701.py:10:45: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function. S701.py:10:34: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
| |
8 | loader=templateLoader ) 8 | loader=templateLoader )
9 | Environment(loader=templateLoader, load=templateLoader, autoescape=something) # S701 9 | Environment(loader=templateLoader, load=templateLoader, autoescape=something) # S701
10 | templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) # S701 10 | templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) # S701
| ^^^^^ S701 | ^^^^^^^^^^^^^^^^ S701
11 | Environment(loader=templateLoader, 11 | Environment(loader=templateLoader,
12 | load=templateLoader, 12 | load=templateLoader,
| |
S701.py:13:24: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function. S701.py:13:13: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
| |
11 | Environment(loader=templateLoader, 11 | Environment(loader=templateLoader,
12 | load=templateLoader, 12 | load=templateLoader,
13 | autoescape=False) # S701 13 | autoescape=False) # S701
| ^^^^^ S701 | ^^^^^^^^^^^^^^^^ S701
14 | 14 |
15 | Environment(loader=templateLoader, # S701 15 | Environment(loader=templateLoader, # S701
| |
@ -40,12 +40,12 @@ S701.py:15:1: S701 By default, jinja2 sets `autoescape` to `False`. Consider usi
16 | load=templateLoader) 16 | load=templateLoader)
| |
S701.py:29:47: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function. S701.py:29:36: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
| |
27 | def fake_func(): 27 | def fake_func():
28 | return 'foobar' 28 | return 'foobar'
29 | Environment(loader=templateLoader, autoescape=fake_func()) # S701 29 | Environment(loader=templateLoader, autoescape=fake_func()) # S701
| ^^^^^^^^^^^ S701 | ^^^^^^^^^^^^^^^^^^^^^^ S701
| |

View file

@ -2,7 +2,6 @@ use rustpython_parser::ast::{Expr, Keyword, Ranged};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::SimpleCallArgs;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -38,12 +37,7 @@ impl Violation for NoExplicitStacklevel {
} }
/// B028 /// B028
pub(crate) fn no_explicit_stacklevel( pub(crate) fn no_explicit_stacklevel(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
checker: &mut Checker,
func: &Expr,
args: &[Expr],
keywords: &[Keyword],
) {
if !checker if !checker
.semantic() .semantic()
.resolve_call_path(func) .resolve_call_path(func)
@ -54,10 +48,12 @@ pub(crate) fn no_explicit_stacklevel(
return; return;
} }
if SimpleCallArgs::new(args, keywords) if keywords.iter().any(|keyword| {
.keyword_argument("stacklevel") keyword
.is_some() .arg
{ .as_ref()
.map_or(false, |arg| arg.as_str() == "stacklevel")
}) {
return; return;
} }