mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:24 +00:00
Rename ruff_python_semantic's Context
struct to SemanticModel
(#4565)
This commit is contained in:
parent
3238743a7b
commit
19c4b7bee6
304 changed files with 1253 additions and 1142 deletions
|
@ -13,7 +13,7 @@ use ruff_python_ast::helpers;
|
|||
use ruff_python_ast::imports::{AnyImport, Import};
|
||||
use ruff_python_ast::newlines::NewlineWithTrailingNewline;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_semantic::context::Context;
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
|
||||
use crate::cst::helpers::compose_module_path;
|
||||
use crate::cst::matchers::match_module;
|
||||
|
@ -435,11 +435,11 @@ pub(crate) fn get_or_import_symbol(
|
|||
module: &str,
|
||||
member: &str,
|
||||
at: TextSize,
|
||||
context: &Context,
|
||||
model: &SemanticModel,
|
||||
importer: &Importer,
|
||||
locator: &Locator,
|
||||
) -> Result<(Edit, String)> {
|
||||
if let Some((source, binding)) = context.resolve_qualified_import_name(module, member) {
|
||||
if let Some((source, binding)) = model.resolve_qualified_import_name(module, member) {
|
||||
// If the symbol is already available in the current scope, use it.
|
||||
|
||||
// The exception: the symbol source (i.e., the import statement) comes after the current
|
||||
|
@ -477,7 +477,7 @@ pub(crate) fn get_or_import_symbol(
|
|||
// Case 1: `from functools import lru_cache` is in scope, and we're trying to reference
|
||||
// `functools.cache`; thus, we add `cache` to the import, and return `"cache"` as the
|
||||
// bound name.
|
||||
if context
|
||||
if model
|
||||
.find_binding(member)
|
||||
.map_or(true, |binding| binding.kind.is_builtin())
|
||||
{
|
||||
|
@ -489,7 +489,7 @@ pub(crate) fn get_or_import_symbol(
|
|||
} else {
|
||||
// Case 2: No `functools` import is in scope; thus, we add `import functools`, and
|
||||
// return `"functools.cache"` as the bound name.
|
||||
if context
|
||||
if model
|
||||
.find_binding(module)
|
||||
.map_or(true, |binding| binding.kind.is_builtin())
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use ruff_python_semantic::context::Snapshot;
|
||||
use ruff_python_semantic::model::Snapshot;
|
||||
|
||||
/// A collection of AST nodes that are deferred for later analysis.
|
||||
/// Used to, e.g., store functions, whose bodies shouldn't be analyzed until all
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,14 @@
|
|||
use ruff_python_ast::newlines::{StrExt, UniversalNewlineIterator};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use ruff_python_ast::newlines::{StrExt, UniversalNewlineIterator};
|
||||
use ruff_python_ast::whitespace;
|
||||
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
use crate::docstrings::{Docstring, DocstringBody};
|
||||
use ruff_python_ast::whitespace;
|
||||
|
||||
#[derive(EnumIter, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum SectionKind {
|
||||
|
|
|
@ -3,9 +3,6 @@ use std::collections::{HashMap, HashSet};
|
|||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::external_config::ExternalConfig;
|
||||
use super::plugin::Plugin;
|
||||
use super::{parser, plugin};
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::rules::flake8_pytest_style::types::{
|
||||
|
@ -23,6 +20,10 @@ use crate::settings::pyproject::Pyproject;
|
|||
use crate::settings::types::PythonVersion;
|
||||
use crate::warn_user;
|
||||
|
||||
use super::external_config::ExternalConfig;
|
||||
use super::plugin::Plugin;
|
||||
use super::{parser, plugin};
|
||||
|
||||
const DEFAULT_SELECTORS: &[RuleSelector] = &[
|
||||
RuleSelector::Linter(Linter::Pyflakes),
|
||||
RuleSelector::Linter(Linter::Pycodestyle),
|
||||
|
@ -456,8 +457,6 @@ mod tests {
|
|||
use pep440_rs::VersionSpecifiers;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::super::plugin::Plugin;
|
||||
use super::convert;
|
||||
use crate::flake8_to_ruff::converter::DEFAULT_SELECTORS;
|
||||
use crate::flake8_to_ruff::pep621::Project;
|
||||
use crate::flake8_to_ruff::ExternalConfig;
|
||||
|
@ -469,6 +468,9 @@ mod tests {
|
|||
use crate::settings::pyproject::Pyproject;
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
use super::super::plugin::Plugin;
|
||||
use super::convert;
|
||||
|
||||
fn default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> Options {
|
||||
Options {
|
||||
ignore: Some(vec![]),
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
pub use converter::convert;
|
||||
pub use external_config::ExternalConfig;
|
||||
pub use plugin::Plugin;
|
||||
pub use pyproject::parse;
|
||||
|
||||
mod black;
|
||||
mod converter;
|
||||
mod external_config;
|
||||
|
@ -6,8 +11,3 @@ mod parser;
|
|||
pub mod pep621;
|
||||
mod plugin;
|
||||
mod pyproject;
|
||||
|
||||
pub use converter::convert;
|
||||
pub use external_config::ExternalConfig;
|
||||
pub use plugin::Plugin;
|
||||
pub use pyproject::parse;
|
||||
|
|
|
@ -195,12 +195,13 @@ pub(crate) fn collect_per_file_ignores(
|
|||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||
use crate::codes;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::settings::types::PatternPrefixPair;
|
||||
|
||||
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||
|
||||
#[test]
|
||||
fn it_parses_prefix_codes() {
|
||||
let actual = parse_prefix_codes("");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use ruff_diagnostics::Edit;
|
||||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{Ranged, Stmt};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Utils for reading and writing jupyter notebooks
|
||||
|
||||
mod notebook;
|
||||
mod schema;
|
||||
|
||||
pub use notebook::*;
|
||||
pub use schema::*;
|
||||
|
||||
mod notebook;
|
||||
mod schema;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_text_size::TextRange;
|
||||
use serde::Serialize;
|
||||
use serde_json::error::Category;
|
||||
|
||||
|
|
|
@ -2,15 +2,17 @@ use std::fmt::{Display, Formatter, Write};
|
|||
use std::path::Path;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::fs;
|
||||
use anyhow::Result;
|
||||
use colored::Colorize;
|
||||
use fern;
|
||||
use log::Level;
|
||||
use once_cell::sync::Lazy;
|
||||
use ruff_python_ast::source_code::SourceCode;
|
||||
use rustpython_parser::{ParseError, ParseErrorType};
|
||||
|
||||
use ruff_python_ast::source_code::SourceCode;
|
||||
|
||||
use crate::fs;
|
||||
|
||||
pub(crate) static WARNINGS: Lazy<Mutex<Vec<&'static str>>> = Lazy::new(Mutex::default);
|
||||
|
||||
/// Warn a user once, with uniqueness determined by the given ID.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use std::io::Write;
|
||||
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
use std::io::Write;
|
||||
|
||||
/// Generate error logging commands for Azure Pipelines format.
|
||||
/// See [documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#logissue-log-an-error-or-warning)
|
||||
|
@ -42,9 +44,10 @@ impl Emitter for AzureEmitter {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::AzureEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn output() {
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use crate::message::Message;
|
||||
use colored::{Color, ColoredString, Colorize, Styles};
|
||||
use ruff_diagnostics::{Applicability, Fix};
|
||||
use ruff_python_ast::source_code::{OneIndexed, SourceFile};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use colored::{Color, ColoredString, Colorize, Styles};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
|
||||
use ruff_diagnostics::{Applicability, Fix};
|
||||
use ruff_python_ast::source_code::{OneIndexed, SourceFile};
|
||||
|
||||
use crate::message::Message;
|
||||
|
||||
/// Renders a diff that shows the code fixes.
|
||||
///
|
||||
/// The implementation isn't fully fledged out and only used by tests. Before using in production, try
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use std::io::Write;
|
||||
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
|
||||
use crate::fs::relativize_path;
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
use std::io::Write;
|
||||
|
||||
/// Generate error workflow command in GitHub Actions format.
|
||||
/// See: [GitHub documentation](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message)
|
||||
|
@ -57,9 +59,10 @@ impl Emitter for GithubEmitter {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::GithubEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn output() {
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use crate::fs::{relativize_path, relativize_path_to};
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde_json::json;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::Write;
|
||||
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde_json::json;
|
||||
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
|
||||
use crate::fs::{relativize_path, relativize_path_to};
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// Generate JSON with violations in GitLab CI format
|
||||
// https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool
|
||||
pub struct GitlabEmitter {
|
||||
|
@ -122,9 +125,10 @@ fn fingerprint(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::GitlabEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn output() {
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::io::Write;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use colored::Colorize;
|
||||
|
||||
use ruff_python_ast::source_code::OneIndexed;
|
||||
|
||||
use crate::fs::relativize_path;
|
||||
use crate::jupyter::JupyterIndex;
|
||||
use crate::message::diff::calculate_print_width;
|
||||
|
@ -5,11 +13,6 @@ use crate::message::text::{MessageCodeFrame, RuleCodeAndBody};
|
|||
use crate::message::{
|
||||
group_messages_by_filename, Emitter, EmitterContext, Message, MessageWithLocation,
|
||||
};
|
||||
use colored::Colorize;
|
||||
use ruff_python_ast::source_code::OneIndexed;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io::Write;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GroupedEmitter {
|
||||
|
@ -175,9 +178,10 @@ impl std::fmt::Write for PadAdapter<'_> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::GroupedEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::source_code::SourceCode;
|
||||
use std::io::Write;
|
||||
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde_json::json;
|
||||
use std::io::Write;
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::source_code::SourceCode;
|
||||
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct JsonEmitter;
|
||||
|
@ -94,9 +97,10 @@ impl Serialize for ExpandedEdits<'_> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::JsonEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn output() {
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite};
|
||||
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
|
||||
use crate::message::{
|
||||
group_messages_by_filename, Emitter, EmitterContext, Message, MessageWithLocation,
|
||||
};
|
||||
use crate::registry::AsRule;
|
||||
use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite};
|
||||
use ruff_python_ast::source_code::SourceLocation;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct JunitEmitter;
|
||||
|
@ -83,9 +86,10 @@ impl Emitter for JunitEmitter {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::JunitEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn output() {
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
pub use azure::AzureEmitter;
|
||||
pub use github::GithubEmitter;
|
||||
pub use gitlab::GitlabEmitter;
|
||||
pub use grouped::GroupedEmitter;
|
||||
pub use json::JsonEmitter;
|
||||
pub use junit::JunitEmitter;
|
||||
pub use pylint::PylintEmitter;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
|
||||
use ruff_python_ast::source_code::{SourceFile, SourceLocation};
|
||||
pub use text::TextEmitter;
|
||||
|
||||
use crate::jupyter::JupyterIndex;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
mod azure;
|
||||
mod diff;
|
||||
mod github;
|
||||
|
@ -8,27 +30,6 @@ mod junit;
|
|||
mod pylint;
|
||||
mod text;
|
||||
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub use azure::AzureEmitter;
|
||||
pub use github::GithubEmitter;
|
||||
pub use gitlab::GitlabEmitter;
|
||||
pub use grouped::GroupedEmitter;
|
||||
pub use json::JsonEmitter;
|
||||
pub use junit::JunitEmitter;
|
||||
pub use pylint::PylintEmitter;
|
||||
pub use text::TextEmitter;
|
||||
|
||||
use crate::jupyter::JupyterIndex;
|
||||
use crate::registry::AsRule;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
|
||||
use ruff_python_ast::source_code::{SourceFile, SourceLocation};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Message {
|
||||
pub kind: DiagnosticKind,
|
||||
|
@ -152,13 +153,15 @@ impl<'a> EmitterContext<'a> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::rules::pyflakes::rules::{UndefinedName, UnusedImport, UnusedVariable};
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_python_ast::source_code::SourceFileBuilder;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_python_ast::source_code::SourceFileBuilder;
|
||||
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::rules::pyflakes::rules::{UndefinedName, UnusedImport, UnusedVariable};
|
||||
|
||||
pub(super) fn create_messages() -> Vec<Message> {
|
||||
let fib = r#"import os
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use std::io::Write;
|
||||
|
||||
use ruff_python_ast::source_code::OneIndexed;
|
||||
|
||||
use crate::fs::relativize_path;
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
use ruff_python_ast::source_code::OneIndexed;
|
||||
use std::io::Write;
|
||||
|
||||
/// Generate violations in Pylint format.
|
||||
/// See: [Flake8 documentation](https://flake8.pycqa.org/en/latest/internal/formatters.html#pylint-formatter)
|
||||
|
@ -40,9 +42,10 @@ impl Emitter for PylintEmitter {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::PylintEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn output() {
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
use crate::fs::relativize_path;
|
||||
use crate::message::diff::Diff;
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io::Write;
|
||||
|
||||
use annotate_snippets::display_list::{DisplayList, FormatOptions};
|
||||
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
|
||||
use bitflags::bitflags;
|
||||
use colored::Colorize;
|
||||
use ruff_python_ast::source_code::{OneIndexed, SourceLocation};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io::Write;
|
||||
|
||||
use ruff_python_ast::source_code::{OneIndexed, SourceLocation};
|
||||
|
||||
use crate::fs::relativize_path;
|
||||
use crate::message::diff::Diff;
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
|
@ -292,9 +295,10 @@ struct SourceCode<'a> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::message::tests::{capture_emitter_output, create_messages};
|
||||
use crate::message::TextEmitter;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
//! Registry of all [`Rule`] implementations.
|
||||
|
||||
mod rule_set;
|
||||
|
||||
use strum_macros::{AsRefStr, EnumIter};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_macros::RuleNamespace;
|
||||
pub use rule_set::{RuleSet, RuleSetIterator};
|
||||
|
||||
use crate::codes::{self, RuleCodePrefix};
|
||||
use crate::rules;
|
||||
pub use rule_set::{RuleSet, RuleSetIterator};
|
||||
|
||||
mod rule_set;
|
||||
|
||||
ruff_macros::register_rules!(
|
||||
// pycodestyle errors
|
||||
|
@ -1003,6 +1003,7 @@ pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::size_of;
|
||||
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::{Linter, Rule, RuleNamespace};
|
||||
|
|
|
@ -7,7 +7,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -6,7 +6,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -115,7 +115,7 @@ impl Violation for SysVersionSlice1 {
|
|||
|
||||
fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool {
|
||||
checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["sys", target])
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara
|
|||
/// YTT202
|
||||
pub(crate) fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["six", "PY3"])
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ pub(crate) fn overloaded_name(checker: &Checker, definition: &Definition) -> Opt
|
|||
..
|
||||
}) = definition
|
||||
{
|
||||
if visibility::is_overload(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if visibility::is_overload(&checker.model, cast::decorator_list(stmt)) {
|
||||
let (name, ..) = match_function_def(stmt);
|
||||
Some(name.to_string())
|
||||
} else {
|
||||
|
@ -68,7 +68,7 @@ pub(crate) fn is_overload_impl(
|
|||
..
|
||||
}) = definition
|
||||
{
|
||||
if visibility::is_overload(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if visibility::is_overload(&checker.model, cast::decorator_list(stmt)) {
|
||||
false
|
||||
} else {
|
||||
let (name, ..) = match_function_def(stmt);
|
||||
|
|
|
@ -8,9 +8,9 @@ pub mod settings;
|
|||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use crate::assert_messages;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::assert_messages;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::Settings;
|
||||
use crate::test::test_path;
|
||||
|
|
|
@ -438,7 +438,7 @@ fn check_dynamically_typed<F>(
|
|||
) where
|
||||
F: FnOnce() -> String,
|
||||
{
|
||||
if !is_overridden && checker.ctx.match_typing_expr(annotation, "Any") {
|
||||
if !is_overridden && checker.model.match_typing_expr(annotation, "Any") {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
AnyType { name: func() },
|
||||
annotation.range(),
|
||||
|
@ -479,7 +479,7 @@ pub(crate) fn definition(
|
|||
// unless configured to suppress ANN* for declarations that are fully untyped.
|
||||
let mut diagnostics = Vec::new();
|
||||
|
||||
let is_overridden = visibility::is_override(&checker.ctx, decorator_list);
|
||||
let is_overridden = visibility::is_override(&checker.model, decorator_list);
|
||||
|
||||
// ANN001, ANN401
|
||||
for arg in args
|
||||
|
@ -490,7 +490,8 @@ pub(crate) fn definition(
|
|||
.skip(
|
||||
// If this is a non-static method, skip `cls` or `self`.
|
||||
usize::from(
|
||||
is_method && !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)),
|
||||
is_method
|
||||
&& !visibility::is_staticmethod(&checker.model, cast::decorator_list(stmt)),
|
||||
),
|
||||
)
|
||||
{
|
||||
|
@ -591,10 +592,10 @@ pub(crate) fn definition(
|
|||
}
|
||||
|
||||
// ANN101, ANN102
|
||||
if is_method && !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if is_method && !visibility::is_staticmethod(&checker.model, cast::decorator_list(stmt)) {
|
||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||
if arg.annotation.is_none() {
|
||||
if visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if visibility::is_classmethod(&checker.model, cast::decorator_list(stmt)) {
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeCls) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeCls {
|
||||
|
@ -636,7 +637,7 @@ pub(crate) fn definition(
|
|||
// (explicitly or implicitly).
|
||||
checker.settings.flake8_annotations.suppress_none_returning && is_none_returning(body)
|
||||
) {
|
||||
if is_method && visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if is_method && visibility::is_classmethod(&checker.model, cast::decorator_list(stmt)) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
|
@ -649,7 +650,8 @@ pub(crate) fn definition(
|
|||
helpers::identifier_range(stmt, checker.locator),
|
||||
));
|
||||
}
|
||||
} else if is_method && visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt))
|
||||
} else if is_method
|
||||
&& visibility::is_staticmethod(&checker.model, cast::decorator_list(stmt))
|
||||
{
|
||||
if checker
|
||||
.settings
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustpython_parser::ast::{Expr, Ranged};
|
|||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_semantic::context::Context;
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
use ruff_python_semantic::scope::{FunctionDef, ScopeKind};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -66,9 +66,9 @@ const BLOCKING_HTTP_CALLS: &[&[&str]] = &[
|
|||
|
||||
/// ASYNC100
|
||||
pub(crate) fn blocking_http_call(checker: &mut Checker, expr: &Expr) {
|
||||
if in_async_function(&checker.ctx) {
|
||||
if in_async_function(&checker.model) {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
if let Some(call_path) = checker.ctx.resolve_call_path(func) {
|
||||
if let Some(call_path) = checker.model.resolve_call_path(func) {
|
||||
if BLOCKING_HTTP_CALLS.contains(&call_path.as_slice()) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BlockingHttpCallInAsyncFunction,
|
||||
|
@ -133,9 +133,9 @@ const OPEN_SLEEP_OR_SUBPROCESS_CALL: &[&[&str]] = &[
|
|||
|
||||
/// ASYNC101
|
||||
pub(crate) fn open_sleep_or_subprocess_call(checker: &mut Checker, expr: &Expr) {
|
||||
if in_async_function(&checker.ctx) {
|
||||
if in_async_function(&checker.model) {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
if let Some(call_path) = checker.ctx.resolve_call_path(func) {
|
||||
if let Some(call_path) = checker.model.resolve_call_path(func) {
|
||||
if OPEN_SLEEP_OR_SUBPROCESS_CALL.contains(&call_path.as_slice()) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
OpenSleepOrSubprocessInAsyncFunction,
|
||||
|
@ -197,9 +197,9 @@ const UNSAFE_OS_METHODS: &[&[&str]] = &[
|
|||
|
||||
/// ASYNC102
|
||||
pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) {
|
||||
if in_async_function(&checker.ctx) {
|
||||
if in_async_function(&checker.model) {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
if let Some(call_path) = checker.ctx.resolve_call_path(func) {
|
||||
if let Some(call_path) = checker.model.resolve_call_path(func) {
|
||||
if UNSAFE_OS_METHODS.contains(&call_path.as_slice()) {
|
||||
checker
|
||||
.diagnostics
|
||||
|
@ -210,9 +210,9 @@ pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the [`Context`] is inside an async function definition.
|
||||
fn in_async_function(context: &Context) -> bool {
|
||||
context
|
||||
/// Return `true` if the [`SemanticModel`] is inside an async function definition.
|
||||
fn in_async_function(model: &SemanticModel) -> bool {
|
||||
model
|
||||
.scopes()
|
||||
.find_map(|scope| {
|
||||
if let ScopeKind::Function(FunctionDef { async_, .. }) = &scope.kind {
|
||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> b
|
|||
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_ {
|
||||
elts.iter().any(|type_| {
|
||||
checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(type_)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "Exception"]
|
||||
|
@ -36,7 +36,7 @@ pub(crate) fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> b
|
|||
})
|
||||
} else {
|
||||
checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(type_)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "Exception"]
|
||||
|
|
|
@ -7,11 +7,10 @@ pub mod settings;
|
|||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use crate::assert_messages;
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::assert_messages;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::Settings;
|
||||
use crate::test::test_path;
|
||||
|
|
|
@ -108,7 +108,7 @@ pub(crate) fn bad_file_permissions(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["os", "chmod"])
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use ruff_text_size::TextRange;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
#[violation]
|
||||
pub struct HardcodedBindAllInterfaces;
|
||||
|
|
|
@ -60,7 +60,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
|
|||
op: Operator::Add | Operator::Mod,
|
||||
..
|
||||
}) => {
|
||||
let Some(parent) = checker.ctx.expr_parent() else {
|
||||
let Some(parent) = checker.model.expr_parent() else {
|
||||
if any_over_expr(expr, &has_string_literal) {
|
||||
return Some(checker.generator().expr(expr));
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ pub(crate) fn hashlib_insecure_hash_functions(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if let Some(hashlib_call) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
if let Some(hashlib_call) = checker.model.resolve_call_path(func).and_then(|call_path| {
|
||||
if call_path.as_slice() == ["hashlib", "new"] {
|
||||
Some(HashlibCall::New)
|
||||
} else {
|
||||
|
|
|
@ -37,7 +37,7 @@ pub(crate) fn jinja2_autoescape_false(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["jinja2", "Environment"]
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn logging_config_insecure_listen(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["logging", "config", "listen"]
|
||||
|
|
|
@ -18,7 +18,7 @@ impl Violation for ParamikoCall {
|
|||
/// S601
|
||||
pub(crate) fn paramiko_call(checker: &mut Checker, func: &Expr) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["paramiko", "exec_command"]
|
||||
|
|
|
@ -43,7 +43,7 @@ pub(crate) fn request_with_no_cert_validation(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if let Some(target) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
if let Some(target) = checker.model.resolve_call_path(func).and_then(|call_path| {
|
||||
if call_path.len() == 2 {
|
||||
if call_path[0] == "requests" && REQUESTS_HTTP_VERBS.contains(&call_path[1]) {
|
||||
return Some("requests");
|
||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) fn request_without_timeout(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
HTTP_VERBS
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::Truthiness;
|
||||
use ruff_python_semantic::context::Context;
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
|
||||
use crate::{
|
||||
checkers::ast::Checker, registry::Rule, rules::flake8_bandit::helpers::string_literal,
|
||||
|
@ -97,8 +97,8 @@ enum CallKind {
|
|||
}
|
||||
|
||||
/// Return the [`CallKind`] of the given function call.
|
||||
fn get_call_kind(func: &Expr, context: &Context) -> Option<CallKind> {
|
||||
context
|
||||
fn get_call_kind(func: &Expr, model: &SemanticModel) -> Option<CallKind> {
|
||||
model
|
||||
.resolve_call_path(func)
|
||||
.and_then(|call_path| match call_path.as_slice() {
|
||||
&[module, submodule] => match module {
|
||||
|
@ -138,12 +138,15 @@ struct ShellKeyword<'a> {
|
|||
}
|
||||
|
||||
/// Return the `shell` keyword argument to the given function call, if any.
|
||||
fn find_shell_keyword<'a>(ctx: &Context, keywords: &'a [Keyword]) -> Option<ShellKeyword<'a>> {
|
||||
fn find_shell_keyword<'a>(
|
||||
model: &SemanticModel,
|
||||
keywords: &'a [Keyword],
|
||||
) -> Option<ShellKeyword<'a>> {
|
||||
keywords
|
||||
.iter()
|
||||
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "shell"))
|
||||
.map(|keyword| ShellKeyword {
|
||||
truthiness: Truthiness::from_expr(&keyword.value, |id| ctx.is_builtin(id)),
|
||||
truthiness: Truthiness::from_expr(&keyword.value, |id| model.is_builtin(id)),
|
||||
keyword,
|
||||
})
|
||||
}
|
||||
|
@ -181,11 +184,11 @@ pub(crate) fn shell_injection(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let call_kind = get_call_kind(func, &checker.ctx);
|
||||
let call_kind = get_call_kind(func, &checker.model);
|
||||
|
||||
if matches!(call_kind, Some(CallKind::Subprocess)) {
|
||||
if let Some(arg) = args.first() {
|
||||
match find_shell_keyword(&checker.ctx, keywords) {
|
||||
match find_shell_keyword(&checker.model, keywords) {
|
||||
// S602
|
||||
Some(ShellKeyword {
|
||||
truthiness: Truthiness::Truthy,
|
||||
|
@ -238,7 +241,7 @@ pub(crate) fn shell_injection(
|
|||
} else if let Some(ShellKeyword {
|
||||
truthiness: Truthiness::Truthy,
|
||||
keyword,
|
||||
}) = find_shell_keyword(&checker.ctx, keywords)
|
||||
}) = find_shell_keyword(&checker.model, keywords)
|
||||
{
|
||||
// S604
|
||||
if checker
|
||||
|
|
|
@ -25,7 +25,7 @@ pub(crate) fn snmp_insecure_version(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pysnmp", "hlapi", "CommunityData"]
|
||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) fn snmp_weak_cryptography(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pysnmp", "hlapi", "UsmUserData"]
|
||||
|
|
|
@ -470,7 +470,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
|
|||
return;
|
||||
};
|
||||
|
||||
let Some(reason) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
let Some(reason) = checker.model.resolve_call_path(func).and_then(|call_path| {
|
||||
for module in SUSPICIOUS_MEMBERS {
|
||||
for member in module.members {
|
||||
if call_path.as_slice() == *member {
|
||||
|
|
|
@ -38,14 +38,14 @@ pub(crate) fn unsafe_yaml_load(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["yaml", "load"])
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(loader_arg) = call_args.argument("Loader", 1) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(loader_arg)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["yaml", "SafeLoader"]
|
||||
|
|
|
@ -6,7 +6,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) fn blind_except(
|
|||
return;
|
||||
};
|
||||
for exception in ["BaseException", "Exception"] {
|
||||
if id == exception && checker.ctx.is_builtin(exception) {
|
||||
if id == exception && checker.model.is_builtin(exception) {
|
||||
// If the exception is re-raised, don't flag an error.
|
||||
if body.iter().any(|stmt| {
|
||||
if let Stmt::Raise(ast::StmtRaise { exc, .. }) = stmt {
|
||||
|
@ -58,7 +58,7 @@ pub(crate) fn blind_except(
|
|||
if body.iter().any(|stmt| {
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||
if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() {
|
||||
if logging::is_logger_candidate(&checker.ctx, func) {
|
||||
if logging::is_logger_candidate(&checker.model, func) {
|
||||
if let Some(attribute) = func.as_attribute_expr() {
|
||||
let attr = attribute.attr.as_str();
|
||||
if attr == "exception" {
|
||||
|
|
|
@ -6,7 +6,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -6,11 +6,10 @@ pub mod settings;
|
|||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use crate::assert_messages;
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::assert_messages;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::Settings;
|
||||
use crate::test::test_path;
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged, Stmt};
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload};
|
||||
use ruff_python_semantic::context::Context;
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
@ -35,16 +35,16 @@ impl Violation for EmptyMethodWithoutAbstractDecorator {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_abc_class(context: &Context, bases: &[Expr], keywords: &[Keyword]) -> bool {
|
||||
fn is_abc_class(model: &SemanticModel, bases: &[Expr], keywords: &[Keyword]) -> bool {
|
||||
keywords.iter().any(|keyword| {
|
||||
keyword.arg.as_ref().map_or(false, |arg| arg == "metaclass")
|
||||
&& context
|
||||
&& model
|
||||
.resolve_call_path(&keyword.value)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["abc", "ABCMeta"]
|
||||
})
|
||||
}) || bases.iter().any(|base| {
|
||||
context
|
||||
model
|
||||
.resolve_call_path(base)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["abc", "ABC"])
|
||||
})
|
||||
|
@ -79,7 +79,7 @@ pub(crate) fn abstract_base_class(
|
|||
if bases.len() + keywords.len() != 1 {
|
||||
return;
|
||||
}
|
||||
if !is_abc_class(&checker.ctx, bases, keywords) {
|
||||
if !is_abc_class(&checker.model, bases, keywords) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ pub(crate) fn abstract_base_class(
|
|||
continue;
|
||||
};
|
||||
|
||||
let has_abstract_decorator = is_abstract(&checker.ctx, decorator_list);
|
||||
let has_abstract_decorator = is_abstract(&checker.model, decorator_list);
|
||||
has_abstract_method |= has_abstract_decorator;
|
||||
|
||||
if !checker
|
||||
|
@ -121,7 +121,7 @@ pub(crate) fn abstract_base_class(
|
|||
|
||||
if !has_abstract_decorator
|
||||
&& is_empty_body(body)
|
||||
&& !is_overload(&checker.ctx, decorator_list)
|
||||
&& !is_overload(&checker.model, decorator_list)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
EmptyMethodWithoutAbstractDecorator {
|
||||
|
|
|
@ -66,7 +66,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
|||
}
|
||||
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(args.first().unwrap())
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["", "Exception"])
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
|||
{
|
||||
AssertionKind::AssertRaises
|
||||
} else if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pytest", "raises"]
|
||||
|
|
|
@ -20,7 +20,7 @@ impl Violation for CachedInstanceMethod {
|
|||
|
||||
fn is_cache_func(checker: &Checker, expr: &Expr) -> bool {
|
||||
checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["functools", "lru_cache"]
|
||||
|
@ -30,7 +30,7 @@ fn is_cache_func(checker: &Checker, expr: &Expr) -> bool {
|
|||
|
||||
/// B019
|
||||
pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
if !matches!(checker.ctx.scope().kind, ScopeKind::Class(_)) {
|
||||
if !matches!(checker.model.scope().kind, ScopeKind::Class(_)) {
|
||||
return;
|
||||
}
|
||||
for decorator in decorator_list {
|
||||
|
|
|
@ -86,7 +86,7 @@ where
|
|||
match expr {
|
||||
Expr::Call(ast::ExprCall { func, args, .. }) => {
|
||||
if !is_mutable_func(self.checker, func)
|
||||
&& !is_immutable_func(&self.checker.ctx, func, &self.extend_immutable_calls)
|
||||
&& !is_immutable_func(&self.checker.model, func, &self.extend_immutable_calls)
|
||||
&& !is_nan_or_infinity(func, args)
|
||||
{
|
||||
self.diagnostics.push((
|
||||
|
|
|
@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged};
|
|||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
|
|
@ -27,7 +27,7 @@ const MUTABLE_FUNCS: &[&[&str]] = &[
|
|||
|
||||
pub(crate) fn is_mutable_func(checker: &Checker, func: &Expr) -> bool {
|
||||
checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
MUTABLE_FUNCS
|
||||
|
@ -70,7 +70,7 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, arguments: &Argume
|
|||
&& !arg
|
||||
.annotation
|
||||
.as_ref()
|
||||
.map_or(false, |expr| is_immutable_annotation(&checker.ctx, expr))
|
||||
.map_or(false, |expr| is_immutable_annotation(&checker.model, expr))
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
|
|
|
@ -45,7 +45,7 @@ pub(crate) fn no_explicit_stacklevel(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["warnings", "warn"]
|
||||
|
|
|
@ -342,7 +342,7 @@ pub(crate) fn reuse_of_groupby_generator(
|
|||
};
|
||||
// Check if the function call is `itertools.groupby`
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["itertools", "groupby"]
|
||||
|
|
|
@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt};
|
|||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use ruff_python_ast::source_code::Generator;
|
||||
use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
|
||||
|
||||
|
@ -76,7 +75,7 @@ pub(crate) fn setattr_with_constant(
|
|||
if let Stmt::Expr(ast::StmtExpr {
|
||||
value: child,
|
||||
range: _,
|
||||
}) = &checker.ctx.stmt()
|
||||
}) = &checker.model.stmt()
|
||||
{
|
||||
if expr == child.as_ref() {
|
||||
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());
|
||||
|
|
|
@ -129,7 +129,7 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr,
|
|||
|
||||
// Avoid fixing any variables that _may_ be used, but undetectably so.
|
||||
let certainty = Certainty::from(!helpers::uses_magic_variable_access(body, |id| {
|
||||
checker.ctx.is_builtin(id)
|
||||
checker.model.is_builtin(id)
|
||||
}));
|
||||
|
||||
// Attempt to rename the variable by prepending an underscore, but avoid
|
||||
|
@ -153,12 +153,12 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr,
|
|||
if let Some(rename) = rename {
|
||||
if certainty.into() && checker.patch(diagnostic.kind.rule()) {
|
||||
// Find the `BindingKind::LoopVar` corresponding to the name.
|
||||
let scope = checker.ctx.scope();
|
||||
let scope = checker.model.scope();
|
||||
let binding = scope.bindings_for_name(name).find_map(|index| {
|
||||
let binding = &checker.ctx.bindings[*index];
|
||||
binding
|
||||
.source
|
||||
.and_then(|source| (Some(source) == checker.ctx.stmt_id).then_some(binding))
|
||||
let binding = &checker.model.bindings[*index];
|
||||
binding.source.and_then(|source| {
|
||||
(Some(source) == checker.model.stmt_id).then_some(binding)
|
||||
})
|
||||
});
|
||||
if let Some(binding) = binding {
|
||||
if binding.kind.is_loop_var() {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
#[violation]
|
||||
pub struct UselessContextlibSuppress;
|
||||
|
||||
|
@ -26,7 +27,7 @@ pub(crate) fn useless_contextlib_suppress(
|
|||
) {
|
||||
if args.is_empty()
|
||||
&& checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["contextlib", "suppress"]
|
||||
|
|
|
@ -53,7 +53,7 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) {
|
|||
}
|
||||
|
||||
// Ignore statements that have side effects.
|
||||
if contains_effect(value, |id| checker.ctx.is_builtin(id)) {
|
||||
if contains_effect(value, |id| checker.model.is_builtin(id)) {
|
||||
// Flag attributes as useless expressions, even if they're attached to calls or other
|
||||
// expressions.
|
||||
if matches!(value, Expr::Attribute(_)) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
#[violation]
|
||||
pub struct ZipWithoutExplicitStrict;
|
||||
|
||||
|
@ -23,7 +24,7 @@ pub(crate) fn zip_without_explicit_strict(
|
|||
) {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func {
|
||||
if id == "zip"
|
||||
&& checker.ctx.is_builtin("zip")
|
||||
&& checker.model.is_builtin("zip")
|
||||
&& !kwargs
|
||||
.iter()
|
||||
.any(|keyword| keyword.arg.as_ref().map_or(false, |name| name == "strict"))
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use rustpython_parser::ast::Ranged;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_stdlib::builtins::BUILTINS;
|
||||
use rustpython_parser::ast::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -7,11 +7,10 @@ pub mod settings;
|
|||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use crate::assert_messages;
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::assert_messages;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::Settings;
|
||||
use crate::test::test_path;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -74,7 +75,7 @@ pub(crate) fn unnecessary_call_around_sorted(
|
|||
if inner != "sorted" {
|
||||
return;
|
||||
}
|
||||
if !checker.ctx.is_builtin(inner) || !checker.ctx.is_builtin(outer) {
|
||||
if !checker.model.is_builtin(inner) || !checker.model.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -79,7 +79,7 @@ pub(crate) fn unnecessary_collection_call(
|
|||
}
|
||||
_ => return,
|
||||
};
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -56,7 +56,7 @@ fn add_diagnostic(checker: &mut Checker, expr: &Expr) {
|
|||
Expr::DictComp(_) => "dict",
|
||||
_ => return,
|
||||
};
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -76,7 +76,7 @@ pub(crate) fn unnecessary_comprehension_any_all(
|
|||
if is_async_generator(elt) {
|
||||
return;
|
||||
}
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, args[0].range());
|
||||
|
|
|
@ -90,7 +90,7 @@ pub(crate) fn unnecessary_double_cast_or_process(
|
|||
let Some(inner) = helpers::expr_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin(inner) || !checker.ctx.is_builtin(outer) {
|
||||
if !checker.model.is_builtin(inner) || !checker.model.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn unnecessary_generator_list(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("list", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("list") {
|
||||
if !checker.model.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if let Expr::GeneratorExp(_) = argument {
|
||||
|
|
|
@ -53,7 +53,7 @@ pub(crate) fn unnecessary_generator_set(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("set") {
|
||||
if !checker.model.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let Expr::GeneratorExp(_) = argument {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -47,7 +48,7 @@ pub(crate) fn unnecessary_list_call(
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("list") {
|
||||
if !checker.model.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if !argument.is_list_comp_expr() {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -49,7 +50,7 @@ pub(crate) fn unnecessary_list_comprehension_dict(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("dict") {
|
||||
if !checker.model.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else {
|
||||
|
|
|
@ -50,7 +50,7 @@ pub(crate) fn unnecessary_list_comprehension_set(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("set") {
|
||||
if !checker.model.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if argument.is_list_comp_expr() {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -56,7 +57,7 @@ pub(crate) fn unnecessary_literal_dict(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("dict") {
|
||||
if !checker.model.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let (kind, elts) = match argument {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -57,7 +58,7 @@ pub(crate) fn unnecessary_literal_set(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("set") {
|
||||
if !checker.model.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
let kind = match argument {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
use std::fmt;
|
||||
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
|
@ -75,7 +76,7 @@ pub(crate) fn unnecessary_literal_within_dict_call(
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("dict", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("dict") {
|
||||
if !checker.model.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -78,7 +79,7 @@ pub(crate) fn unnecessary_literal_within_list_call(
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("list") {
|
||||
if !checker.model.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
|
@ -79,7 +80,7 @@ pub(crate) fn unnecessary_literal_within_tuple_call(
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("tuple", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.ctx.is_builtin("tuple") {
|
||||
if !checker.model.is_builtin("tuple") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
|
|
|
@ -88,7 +88,7 @@ pub(crate) fn unnecessary_map(
|
|||
};
|
||||
match id {
|
||||
"map" => {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ pub(crate) fn unnecessary_map(
|
|||
}
|
||||
}
|
||||
"list" | "set" => {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ pub(crate) fn unnecessary_map(
|
|||
}
|
||||
}
|
||||
"dict" => {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use num_bigint::BigInt;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged, Unaryop};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
use super::helpers;
|
||||
|
||||
/// ## What it does
|
||||
|
@ -57,7 +58,7 @@ pub(crate) fn unnecessary_subscript_reversal(
|
|||
if !(id == "set" || id == "sorted" || id == "reversed") {
|
||||
return;
|
||||
}
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
if !checker.model.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let Expr::Subscript(ast::ExprSubscript { slice, .. }) = first_arg else {
|
||||
|
|
|
@ -6,7 +6,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -125,7 +125,7 @@ pub(crate) fn call_datetime_without_tzinfo(
|
|||
location: TextRange,
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime"]
|
||||
|
@ -158,7 +158,7 @@ pub(crate) fn call_datetime_without_tzinfo(
|
|||
/// Use `datetime.datetime.now(tz=)` instead.
|
||||
pub(crate) fn call_datetime_today(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "today"]
|
||||
|
@ -180,7 +180,7 @@ pub(crate) fn call_datetime_today(checker: &mut Checker, func: &Expr, location:
|
|||
/// current time in UTC is by calling `datetime.now(timezone.utc)`.
|
||||
pub(crate) fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "utcnow"]
|
||||
|
@ -207,7 +207,7 @@ pub(crate) fn call_datetime_utcfromtimestamp(
|
|||
location: TextRange,
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "utcfromtimestamp"]
|
||||
|
@ -228,7 +228,7 @@ pub(crate) fn call_datetime_now_without_tzinfo(
|
|||
location: TextRange,
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "now"]
|
||||
|
@ -270,7 +270,7 @@ pub(crate) fn call_datetime_fromtimestamp(
|
|||
location: TextRange,
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "fromtimestamp"]
|
||||
|
@ -311,7 +311,7 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
|||
location: TextRange,
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "strptime"]
|
||||
|
@ -332,7 +332,7 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
|||
}
|
||||
};
|
||||
|
||||
let (Some(grandparent), Some(parent)) = (checker.ctx.expr_grandparent(), checker.ctx.expr_parent()) else {
|
||||
let (Some(grandparent), Some(parent)) = (checker.model.expr_grandparent(), checker.model.expr_parent()) else {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
CallDatetimeStrptimeWithoutZone,
|
||||
location,
|
||||
|
@ -370,7 +370,7 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
|||
/// Use `datetime.datetime.now(tz=).date()` instead.
|
||||
pub(crate) fn call_date_today(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "date", "today"]
|
||||
|
@ -390,7 +390,7 @@ pub(crate) fn call_date_today(checker: &mut Checker, func: &Expr, location: Text
|
|||
/// Use `datetime.datetime.fromtimestamp(, tz=).date()` instead.
|
||||
pub(crate) fn call_date_fromtimestamp(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||
if checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "date", "fromtimestamp"]
|
||||
|
|
|
@ -7,7 +7,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use rustpython_parser::ast::{Expr, Ranged, Stmt};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_debugger::types::DebuggerUsingType;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::{format_call_path, from_unqualified_name, CallPath};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_debugger::types::DebuggerUsingType;
|
||||
|
||||
#[violation]
|
||||
pub struct Debugger {
|
||||
using_type: DebuggerUsingType,
|
||||
|
@ -42,7 +43,7 @@ const DEBUGGERS: &[&[&str]] = &[
|
|||
|
||||
/// Checks for the presence of a debugger call.
|
||||
pub(crate) fn debugger_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||
if let Some(target) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
if let Some(target) = checker.model.resolve_call_path(func).and_then(|call_path| {
|
||||
DEBUGGERS
|
||||
.iter()
|
||||
.find(|target| call_path.as_slice() == **target)
|
||||
|
|
|
@ -6,7 +6,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn all_with_model_form(
|
|||
bases: &[Expr],
|
||||
body: &[Stmt],
|
||||
) -> Option<Diagnostic> {
|
||||
if !bases.iter().any(|base| is_model_form(&checker.ctx, base)) {
|
||||
if !bases.iter().any(|base| is_model_form(&checker.model, base)) {
|
||||
return None;
|
||||
}
|
||||
for element in body.iter() {
|
||||
|
|
|
@ -50,7 +50,7 @@ pub(crate) fn exclude_with_model_form(
|
|||
bases: &[Expr],
|
||||
body: &[Stmt],
|
||||
) -> Option<Diagnostic> {
|
||||
if !bases.iter().any(|base| is_model_form(&checker.ctx, base)) {
|
||||
if !bases.iter().any(|base| is_model_form(&checker.model, base)) {
|
||||
return None;
|
||||
}
|
||||
for element in body.iter() {
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use ruff_python_semantic::context::Context;
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
|
||||
/// Return `true` if a Python class appears to be a Django model, based on its base classes.
|
||||
pub(crate) fn is_model(context: &Context, base: &Expr) -> bool {
|
||||
context.resolve_call_path(base).map_or(false, |call_path| {
|
||||
pub(crate) fn is_model(model: &SemanticModel, base: &Expr) -> bool {
|
||||
model.resolve_call_path(base).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "db", "models", "Model"]
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if a Python class appears to be a Django model form, based on its base classes.
|
||||
pub(crate) fn is_model_form(context: &Context, base: &Expr) -> bool {
|
||||
context.resolve_call_path(base).map_or(false, |call_path| {
|
||||
pub(crate) fn is_model_form(model: &SemanticModel, base: &Expr) -> bool {
|
||||
model.resolve_call_path(base).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "forms", "ModelForm"]
|
||||
|| call_path.as_slice() == ["django", "forms", "models", "ModelForm"]
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if the expression is constructor for a Django model field.
|
||||
pub(crate) fn is_model_field(context: &Context, expr: &Expr) -> bool {
|
||||
context.resolve_call_path(expr).map_or(false, |call_path| {
|
||||
pub(crate) fn is_model_field(model: &SemanticModel, expr: &Expr) -> bool {
|
||||
model.resolve_call_path(expr).map_or(false, |call_path| {
|
||||
call_path
|
||||
.as_slice()
|
||||
.starts_with(&["django", "db", "models"])
|
||||
|
@ -27,8 +27,11 @@ pub(crate) fn is_model_field(context: &Context, expr: &Expr) -> bool {
|
|||
}
|
||||
|
||||
/// Return the name of the field type, if the expression is constructor for a Django model field.
|
||||
pub(crate) fn get_model_field_name<'a>(context: &'a Context, expr: &'a Expr) -> Option<&'a str> {
|
||||
context.resolve_call_path(expr).and_then(|call_path| {
|
||||
pub(crate) fn get_model_field_name<'a>(
|
||||
model: &'a SemanticModel,
|
||||
expr: &'a Expr,
|
||||
) -> Option<&'a str> {
|
||||
model.resolve_call_path(expr).and_then(|call_path| {
|
||||
let call_path = call_path.as_slice();
|
||||
if !call_path.starts_with(&["django", "db", "models"]) {
|
||||
return None;
|
||||
|
|
|
@ -50,7 +50,7 @@ pub(crate) fn locals_in_render_function(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "shortcuts", "render"]
|
||||
|
@ -87,7 +87,7 @@ fn is_locals_call(checker: &Checker, expr: &Expr) -> bool {
|
|||
return false
|
||||
};
|
||||
checker
|
||||
.ctx
|
||||
.model
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["", "locals"])
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ fn checker_applies(checker: &Checker, bases: &[Expr], body: &[Stmt]) -> bool {
|
|||
if is_model_abstract(body) {
|
||||
continue;
|
||||
}
|
||||
if helpers::is_model(&checker.ctx, base) {
|
||||
if helpers::is_model(&checker.model, base) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a st
|
|||
return None;
|
||||
};
|
||||
|
||||
let Some(valid_field_name) = helpers::get_model_field_name(&checker.ctx, func) else {
|
||||
let Some(valid_field_name) = helpers::get_model_field_name(&checker.model, func) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ fn get_element_type(checker: &Checker, element: &Stmt) -> Option<ContentType> {
|
|||
match element {
|
||||
Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||
if helpers::is_model_field(&checker.ctx, func) {
|
||||
if helpers::is_model_field(&checker.model, func) {
|
||||
return Some(ContentType::FieldDeclaration);
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ pub(crate) fn unordered_body_content_in_model(
|
|||
) {
|
||||
if !bases
|
||||
.iter()
|
||||
.any(|base| helpers::is_model(&checker.ctx, base))
|
||||
.any(|base| helpers::is_model(&checker.model, base))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt};
|
|||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use ruff_python_ast::source_code::{Generator, Stylist};
|
||||
use ruff_python_ast::whitespace;
|
||||
|
||||
|
@ -234,7 +233,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
if string.len() > checker.settings.flake8_errmsg.max_string_length {
|
||||
let indentation = whitespace::indentation(checker.locator, stmt)
|
||||
.and_then(|indentation| {
|
||||
if checker.ctx.find_binding("msg").is_none() {
|
||||
if checker.model.find_binding("msg").is_none() {
|
||||
Some(indentation)
|
||||
} else {
|
||||
None
|
||||
|
@ -262,7 +261,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
if checker.settings.rules.enabled(Rule::FStringInException) {
|
||||
let indentation = whitespace::indentation(checker.locator, stmt).and_then(
|
||||
|indentation| {
|
||||
if checker.ctx.find_binding("msg").is_none() {
|
||||
if checker.model.find_binding("msg").is_none() {
|
||||
Some(indentation)
|
||||
} else {
|
||||
None
|
||||
|
@ -293,7 +292,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
if attr == "format" && value.is_constant_expr() {
|
||||
let indentation = whitespace::indentation(checker.locator, stmt)
|
||||
.and_then(|indentation| {
|
||||
if checker.ctx.find_binding("msg").is_none() {
|
||||
if checker.model.find_binding("msg").is_none() {
|
||||
Some(indentation)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -51,12 +51,12 @@ pub(crate) fn is_executable(filepath: &Path) -> Result<bool> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
use crate::rules::flake8_executable::helpers::{
|
||||
extract_shebang, ShebangDirective, SHEBANG_REGEX,
|
||||
};
|
||||
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
#[test]
|
||||
fn shebang_regex() {
|
||||
// Positive cases
|
||||
|
|
|
@ -8,7 +8,6 @@ mod tests {
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#![allow(unused_imports)]
|
||||
|
||||
use ruff_text_size::TextRange;
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#![allow(unused_imports)]
|
||||
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ impl Violation for MissingFutureAnnotationsImport {
|
|||
|
||||
/// FA100
|
||||
pub(crate) fn missing_future_annotations(checker: &mut Checker, expr: &Expr) {
|
||||
if let Some(binding) = checker.ctx.resolve_call_path(expr) {
|
||||
if let Some(binding) = checker.model.resolve_call_path(expr) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
MissingFutureAnnotationsImport {
|
||||
name: format_call_path(&binding),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue