Re-integrate RustPython parser repository (#4359)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Jeong, YunWon 2023-05-11 16:47:17 +09:00 committed by GitHub
parent 865205d992
commit be6e00ef6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
270 changed files with 3061 additions and 3361 deletions

271
Cargo.lock generated
View file

@ -144,15 +144,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
[[package]]
name = "ascii-canvas"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
dependencies = [
"term",
]
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "2.0.11" version = "2.0.11"
@ -200,21 +191,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -223,9 +199,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.1.0" version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
[[package]] [[package]]
name = "bstr" name = "bstr"
@ -700,16 +676,6 @@ dependencies = [
"dirs-sys 0.4.0", "dirs-sys 0.4.0",
] ]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]] [[package]]
name = "dirs-sys" name = "dirs-sys"
version = "0.3.7" version = "0.3.7"
@ -732,17 +698,6 @@ dependencies = [
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]] [[package]]
name = "doc-comment" name = "doc-comment"
version = "0.3.3" version = "0.3.3"
@ -767,15 +722,6 @@ version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "ena"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
dependencies = [
"log",
]
[[package]] [[package]]
name = "encode_unicode" name = "encode_unicode"
version = "0.3.6" version = "0.3.6"
@ -833,12 +779,6 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "flake8-to-ruff" name = "flake8-to-ruff"
version = "0.0.265" version = "0.0.265"
@ -1168,37 +1108,11 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "lalrpop"
version = "0.19.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87"
dependencies = [
"ascii-canvas",
"bit-set",
"diff",
"ena",
"is-terminal",
"itertools",
"lalrpop-util",
"petgraph",
"pico-args",
"regex",
"regex-syntax 0.6.29",
"string_cache",
"term",
"tiny-keccak",
"unicode-xid",
]
[[package]] [[package]]
name = "lalrpop-util" name = "lalrpop-util"
version = "0.19.9" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd" checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
@ -1388,12 +1302,6 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c" checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]] [[package]]
name = "nextest-workspace-hack" name = "nextest-workspace-hack"
version = "0.1.0" version = "0.1.0"
@ -1525,29 +1433,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.2.16",
"smallvec",
"windows-sys 0.45.0",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.12" version = "1.0.12"
@ -1624,23 +1509,13 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "petgraph"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]] [[package]]
name = "phf" name = "phf"
version = "0.11.1" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
dependencies = [ dependencies = [
"phf_shared 0.11.1", "phf_shared",
] ]
[[package]] [[package]]
@ -1650,7 +1525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
dependencies = [ dependencies = [
"phf_generator", "phf_generator",
"phf_shared 0.11.1", "phf_shared",
] ]
[[package]] [[package]]
@ -1659,19 +1534,10 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
dependencies = [ dependencies = [
"phf_shared 0.11.1", "phf_shared",
"rand", "rand",
] ]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher",
]
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.11.1" version = "0.11.1"
@ -1681,12 +1547,6 @@ dependencies = [
"siphasher", "siphasher",
] ]
[[package]]
name = "pico-args"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"
@ -1738,12 +1598,6 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "3.0.3" version = "3.0.3"
@ -1944,7 +1798,7 @@ checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
dependencies = [ dependencies = [
"aho-corasick 1.0.1", "aho-corasick 1.0.1",
"memchr", "memchr",
"regex-syntax 0.7.1", "regex-syntax",
] ]
[[package]] [[package]]
@ -1953,12 +1807,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.7.1" version = "0.7.1"
@ -2008,7 +1856,7 @@ version = "0.0.265"
dependencies = [ dependencies = [
"annotate-snippets 0.9.1", "annotate-snippets 0.9.1",
"anyhow", "anyhow",
"bitflags 2.1.0", "bitflags 2.2.1",
"chrono", "chrono",
"clap 4.2.4", "clap 4.2.4",
"colored", "colored",
@ -2101,7 +1949,7 @@ dependencies = [
"assert_cmd", "assert_cmd",
"atty", "atty",
"bincode", "bincode",
"bitflags 2.1.0", "bitflags 2.2.1",
"cachedir", "cachedir",
"chrono", "chrono",
"clap 4.2.4", "clap 4.2.4",
@ -2200,7 +2048,7 @@ name = "ruff_python_ast"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.1.0", "bitflags 2.2.1",
"is-macro", "is-macro",
"itertools", "itertools",
"log", "log",
@ -2209,10 +2057,9 @@ dependencies = [
"num-traits", "num-traits",
"once_cell", "once_cell",
"regex", "regex",
"ruff_rustpython",
"ruff_text_size", "ruff_text_size",
"rustc-hash", "rustc-hash",
"rustpython-common", "rustpython-literal 0.2.0 (git+https://github.com/RustPython/Parser.git?rev=2af98056629fbe75ccc0d90c4ee05dfeb403d666)",
"rustpython-parser", "rustpython-parser",
"serde", "serde",
"smallvec", "smallvec",
@ -2234,7 +2081,6 @@ dependencies = [
"ruff_testing_macros", "ruff_testing_macros",
"ruff_text_size", "ruff_text_size",
"rustc-hash", "rustc-hash",
"rustpython-common",
"rustpython-parser", "rustpython-parser",
"similar", "similar",
"test-case", "test-case",
@ -2244,7 +2090,7 @@ dependencies = [
name = "ruff_python_semantic" name = "ruff_python_semantic"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 2.1.0", "bitflags 2.2.1",
"is-macro", "is-macro",
"nohash-hasher", "nohash-hasher",
"ruff_python_ast", "ruff_python_ast",
@ -2268,8 +2114,6 @@ name = "ruff_rustpython"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"once_cell",
"rustpython-common",
"rustpython-parser", "rustpython-parser",
] ]
@ -2286,7 +2130,7 @@ dependencies = [
[[package]] [[package]]
name = "ruff_text_size" name = "ruff_text_size"
version = "0.0.0" version = "0.0.0"
source = "git+https://github.com/charliermarsh/RustPython.git?rev=c3147d2c1524ebd0e90cf1c2938d770314fd5a5a#c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" source = "git+https://github.com/RustPython/Parser.git?rev=2af98056629fbe75ccc0d90c4ee05dfeb403d666#2af98056629fbe75ccc0d90c4ee05dfeb403d666"
dependencies = [ dependencies = [
"schemars", "schemars",
"serde", "serde",
@ -2357,75 +2201,92 @@ dependencies = [
[[package]] [[package]]
name = "rustpython-ast" name = "rustpython-ast"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/charliermarsh/RustPython.git?rev=c3147d2c1524ebd0e90cf1c2938d770314fd5a5a#c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" source = "git+https://github.com/RustPython/Parser.git?rev=2af98056629fbe75ccc0d90c4ee05dfeb403d666#2af98056629fbe75ccc0d90c4ee05dfeb403d666"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"ruff_text_size", "rustpython-parser-core",
] ]
[[package]] [[package]]
name = "rustpython-common" name = "rustpython-common"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/charliermarsh/RustPython.git?rev=c3147d2c1524ebd0e90cf1c2938d770314fd5a5a#c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" source = "git+https://github.com/RustPython/RustPython.git?rev=f3e4d3409253660bd4fa7f3d24d3db747e7dca61#f3e4d3409253660bd4fa7f3d24d3db747e7dca61"
dependencies = [ dependencies = [
"ascii", "ascii",
"bitflags 1.3.2", "bitflags 2.2.1",
"bstr 0.2.17", "bstr 0.2.17",
"cfg-if", "cfg-if",
"getrandom",
"hexf-parse",
"itertools", "itertools",
"lexical-parse-float",
"libc", "libc",
"lock_api", "lock_api",
"num-bigint", "num-bigint",
"num-complex",
"num-traits", "num-traits",
"once_cell", "once_cell",
"radium", "radium",
"rand", "rand",
"rustpython-literal 0.2.0 (git+https://github.com/youknowone/RustPython-parser.git?rev=5b2af304a2baa53598e594097824165d4ac7a119)",
"siphasher", "siphasher",
"unic-ucd-category",
"volatile", "volatile",
"widestring", "widestring",
] ]
[[package]] [[package]]
name = "rustpython-compiler-core" name = "rustpython-literal"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/charliermarsh/RustPython.git?rev=c3147d2c1524ebd0e90cf1c2938d770314fd5a5a#c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" source = "git+https://github.com/RustPython/Parser.git?rev=2af98056629fbe75ccc0d90c4ee05dfeb403d666#2af98056629fbe75ccc0d90c4ee05dfeb403d666"
dependencies = [ dependencies = [
"bitflags 1.3.2", "hexf-parse",
"itertools", "lexical-parse-float",
"lz4_flex", "num-traits",
"num-bigint", "unic-ucd-category",
"num-complex", ]
"ruff_text_size",
[[package]]
name = "rustpython-literal"
version = "0.2.0"
source = "git+https://github.com/youknowone/RustPython-parser.git?rev=5b2af304a2baa53598e594097824165d4ac7a119#5b2af304a2baa53598e594097824165d4ac7a119"
dependencies = [
"hexf-parse",
"lexical-parse-float",
"num-traits",
"unic-ucd-category",
] ]
[[package]] [[package]]
name = "rustpython-parser" name = "rustpython-parser"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/charliermarsh/RustPython.git?rev=c3147d2c1524ebd0e90cf1c2938d770314fd5a5a#c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" source = "git+https://github.com/RustPython/Parser.git?rev=2af98056629fbe75ccc0d90c4ee05dfeb403d666#2af98056629fbe75ccc0d90c4ee05dfeb403d666"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools", "itertools",
"lalrpop",
"lalrpop-util", "lalrpop-util",
"log", "log",
"num-bigint", "num-bigint",
"num-traits", "num-traits",
"phf", "phf",
"phf_codegen", "phf_codegen",
"ruff_text_size",
"rustc-hash", "rustc-hash",
"rustpython-ast", "rustpython-ast",
"rustpython-compiler-core", "rustpython-parser-core",
"tiny-keccak", "tiny-keccak",
"unic-emoji-char", "unic-emoji-char",
"unic-ucd-ident", "unic-ucd-ident",
"unicode_names2", "unicode_names2",
] ]
[[package]]
name = "rustpython-parser-core"
version = "0.2.0"
source = "git+https://github.com/RustPython/Parser.git?rev=2af98056629fbe75ccc0d90c4ee05dfeb403d666#2af98056629fbe75ccc0d90c4ee05dfeb403d666"
dependencies = [
"itertools",
"lz4_flex",
"num-bigint",
"num-complex",
"ruff_text_size",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.12" version = "1.0.12"
@ -2613,19 +2474,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
"phf_shared 0.10.0",
"precomputed-hash",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -2698,17 +2546,6 @@ dependencies = [
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.2.0" version = "1.2.0"
@ -3061,12 +2898,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]] [[package]]
name = "unicode_names2" name = "unicode_names2"
version = "0.6.0" version = "0.6.0"

View file

@ -11,7 +11,7 @@ authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
[workspace.dependencies] [workspace.dependencies]
anyhow = { version = "1.0.69" } anyhow = { version = "1.0.69" }
bitflags = { version = "2.1.0" } bitflags = { version = "2.2.1" }
chrono = { version = "0.4.23", default-features = false, features = ["clock"] } chrono = { version = "0.4.23", default-features = false, features = ["clock"] }
clap = { version = "4.1.8", features = ["derive"] } clap = { version = "4.1.8", features = ["derive"] }
colored = { version = "2.0.0" } colored = { version = "2.0.0" }
@ -30,10 +30,11 @@ path-absolutize = { version = "3.0.14" }
proc-macro2 = { version = "1.0.51" } proc-macro2 = { version = "1.0.51" }
quote = { version = "1.0.23" } quote = { version = "1.0.23" }
regex = { version = "1.7.1" } regex = { version = "1.7.1" }
ruff_text_size = { git = "https://github.com/charliermarsh/RustPython.git", rev = "c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" } ruff_text_size = { git = "https://github.com/RustPython/Parser.git", rev = "2af98056629fbe75ccc0d90c4ee05dfeb403d666" }
rustc-hash = { version = "1.1.0" } rustc-hash = { version = "1.1.0" }
rustpython-common = { git = "https://github.com/charliermarsh/RustPython.git", rev = "c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" } rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "f3e4d3409253660bd4fa7f3d24d3db747e7dca61" }
rustpython-parser = { git = "https://github.com/charliermarsh/RustPython.git", rev = "c3147d2c1524ebd0e90cf1c2938d770314fd5a5a" } rustpython-literal = { git = "https://github.com/RustPython/Parser.git", rev = "2af98056629fbe75ccc0d90c4ee05dfeb403d666" }
rustpython-parser = { git = "https://github.com/RustPython/Parser.git", rev = "2af98056629fbe75ccc0d90c4ee05dfeb403d666" , default-features = false}
schemars = { version = "0.8.12" } schemars = { version = "0.8.12" }
serde = { version = "1.0.152", features = ["derive"] } serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.93", features = ["preserve_order"] } serde_json = { version = "1.0.93", features = ["preserve_order"] }

View file

@ -5,7 +5,7 @@ use libcst_native::{
Codegen, CodegenState, ImportNames, ParenthesizableWhitespace, SmallStatement, Statement, Codegen, CodegenState, ImportNames, ParenthesizableWhitespace, SmallStatement, Statement,
}; };
use ruff_text_size::{TextLen, TextRange, TextSize}; use ruff_text_size::{TextLen, TextRange, TextSize};
use rustpython_parser::ast::{ExcepthandlerKind, Expr, Keyword, Stmt, StmtKind}; use rustpython_parser::ast::{self, ExcepthandlerKind, Expr, Keyword, Stmt, StmtKind};
use rustpython_parser::{lexer, Mode, Tok}; use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::Edit; use ruff_diagnostics::Edit;
@ -28,21 +28,21 @@ fn has_single_child(body: &[Stmt], deleted: &[&Stmt]) -> bool {
/// Determine if a child is the only statement in its body. /// Determine if a child is the only statement in its body.
fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool> { fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool> {
match &parent.node { match &parent.node {
StmtKind::FunctionDef { body, .. } StmtKind::FunctionDef(ast::StmtFunctionDef { body, .. })
| StmtKind::AsyncFunctionDef { body, .. } | StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef { body, .. })
| StmtKind::ClassDef { body, .. } | StmtKind::ClassDef(ast::StmtClassDef { body, .. })
| StmtKind::With { body, .. } | StmtKind::With(ast::StmtWith { body, .. })
| StmtKind::AsyncWith { body, .. } => { | StmtKind::AsyncWith(ast::StmtAsyncWith { body, .. }) => {
if body.iter().contains(child) { if body.iter().contains(child) {
Ok(has_single_child(body, deleted)) Ok(has_single_child(body, deleted))
} else { } else {
bail!("Unable to find child in parent body") bail!("Unable to find child in parent body")
} }
} }
StmtKind::For { body, orelse, .. } StmtKind::For(ast::StmtFor { body, orelse, .. })
| StmtKind::AsyncFor { body, orelse, .. } | StmtKind::AsyncFor(ast::StmtAsyncFor { body, orelse, .. })
| StmtKind::While { body, orelse, .. } | StmtKind::While(ast::StmtWhile { body, orelse, .. })
| StmtKind::If { body, orelse, .. } => { | StmtKind::If(ast::StmtIf { body, orelse, .. }) => {
if body.iter().contains(child) { if body.iter().contains(child) {
Ok(has_single_child(body, deleted)) Ok(has_single_child(body, deleted))
} else if orelse.iter().contains(child) { } else if orelse.iter().contains(child) {
@ -51,18 +51,18 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
bail!("Unable to find child in parent body") bail!("Unable to find child in parent body")
} }
} }
StmtKind::Try { StmtKind::Try(ast::StmtTry {
body, body,
handlers, handlers,
orelse, orelse,
finalbody, finalbody,
} })
| StmtKind::TryStar { | StmtKind::TryStar(ast::StmtTryStar {
body, body,
handlers, handlers,
orelse, orelse,
finalbody, finalbody,
} => { }) => {
if body.iter().contains(child) { if body.iter().contains(child) {
Ok(has_single_child(body, deleted)) Ok(has_single_child(body, deleted))
} else if orelse.iter().contains(child) { } else if orelse.iter().contains(child) {
@ -70,7 +70,9 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
} else if finalbody.iter().contains(child) { } else if finalbody.iter().contains(child) {
Ok(has_single_child(finalbody, deleted)) Ok(has_single_child(finalbody, deleted))
} else if let Some(body) = handlers.iter().find_map(|handler| match &handler.node { } else if let Some(body) = handlers.iter().find_map(|handler| match &handler.node {
ExcepthandlerKind::ExceptHandler { body, .. } => { ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler {
body, ..
}) => {
if body.iter().contains(child) { if body.iter().contains(child) {
Some(body) Some(body)
} else { } else {
@ -83,7 +85,7 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
bail!("Unable to find child in parent body") bail!("Unable to find child in parent body")
} }
} }
StmtKind::Match { cases, .. } => { StmtKind::Match(ast::StmtMatch { cases, .. }) => {
if let Some(body) = cases.iter().find_map(|case| { if let Some(body) = cases.iter().find_map(|case| {
if case.body.iter().contains(child) { if case.body.iter().contains(child) {
Some(&case.body) Some(&case.body)
@ -350,7 +352,7 @@ pub fn remove_argument(
if n_arguments == 1 { if n_arguments == 1 {
// Case 1: there is only one argument. // Case 1: there is only one argument.
let mut count: usize = 0; let mut count: usize = 0;
for (tok, range) in lexer::lex_located(contents, Mode::Module, call_at).flatten() { for (tok, range) in lexer::lex_starts_at(contents, Mode::Module, call_at).flatten() {
if matches!(tok, Tok::Lpar) { if matches!(tok, Tok::Lpar) {
if count == 0 { if count == 0 {
fix_start = Some(if remove_parentheses { fix_start = Some(if remove_parentheses {
@ -382,7 +384,7 @@ pub fn remove_argument(
{ {
// Case 2: argument or keyword is _not_ the last node. // Case 2: argument or keyword is _not_ the last node.
let mut seen_comma = false; let mut seen_comma = false;
for (tok, range) in lexer::lex_located(contents, Mode::Module, call_at).flatten() { for (tok, range) in lexer::lex_starts_at(contents, Mode::Module, call_at).flatten() {
if seen_comma { if seen_comma {
if matches!(tok, Tok::NonLogicalNewline) { if matches!(tok, Tok::NonLogicalNewline) {
// Also delete any non-logical newlines after the comma. // Also delete any non-logical newlines after the comma.
@ -405,7 +407,7 @@ pub fn remove_argument(
} else { } else {
// Case 3: argument or keyword is the last node, so we have to find the last // Case 3: argument or keyword is the last node, so we have to find the last
// comma in the stmt. // comma in the stmt.
for (tok, range) in lexer::lex_located(contents, Mode::Module, call_at).flatten() { for (tok, range) in lexer::lex_starts_at(contents, Mode::Module, call_at).flatten() {
if range.start() == expr_range.start() { if range.start() == expr_range.start() {
fix_end = Some(expr_range.end()); fix_end = Some(expr_range.end());
break; break;

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::path::Path; use std::path::Path;
use rustpython_parser::ast::{StmtKind, Suite}; use rustpython_parser::ast::{self, StmtKind, Suite};
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_python_ast::helpers::to_module_path; use ruff_python_ast::helpers::to_module_path;
@ -29,20 +29,21 @@ fn extract_import_map(path: &Path, package: Option<&Path>, blocks: &[&Block]) ->
let mut module_imports = Vec::with_capacity(num_imports); let mut module_imports = Vec::with_capacity(num_imports);
for stmt in blocks.iter().flat_map(|block| &block.imports) { for stmt in blocks.iter().flat_map(|block| &block.imports) {
match &stmt.node { match &stmt.node {
StmtKind::Import { names } => { StmtKind::Import(ast::StmtImport { names }) => {
module_imports.extend( module_imports.extend(
names names
.iter() .iter()
.map(|name| ModuleImport::new(name.node.name.clone(), stmt.range())), .map(|name| ModuleImport::new(name.node.name.to_string(), stmt.range())),
); );
} }
StmtKind::ImportFrom { StmtKind::ImportFrom(ast::StmtImportFrom {
module, module,
names, names,
level, level,
} => { }) => {
let level = level.unwrap_or(0); let level = level.map_or(0, |level| level.to_usize());
let module = if let Some(module) = module { let module = if let Some(module) = module {
let module: &String = module.as_ref();
if level == 0 { if level == 0 {
Cow::Borrowed(module) Cow::Borrowed(module)
} else { } else {

View file

@ -4,7 +4,7 @@
use std::iter::FusedIterator; use std::iter::FusedIterator;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind, Suite}; use rustpython_parser::ast::{self, Constant, ExprKind, Stmt, StmtKind, Suite};
use rustpython_parser::lexer::LexResult; use rustpython_parser::lexer::LexResult;
use rustpython_parser::Tok; use rustpython_parser::Tok;
@ -76,11 +76,11 @@ struct StringLinesVisitor<'a> {
impl StatementVisitor<'_> for StringLinesVisitor<'_> { impl StatementVisitor<'_> for StringLinesVisitor<'_> {
fn visit_stmt(&mut self, stmt: &Stmt) { fn visit_stmt(&mut self, stmt: &Stmt) {
if let StmtKind::Expr { value } = &stmt.node { if let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(..), value: Constant::Str(..),
.. ..
} = &value.node }) = &value.node
{ {
for line in UniversalNewlineIterator::with_offset( for line in UniversalNewlineIterator::with_offset(
self.locator.slice(value.range()), self.locator.slice(value.range()),

View file

@ -1,6 +1,6 @@
//! Extract docstrings from an AST. //! Extract docstrings from an AST.
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt, StmtKind};
use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::analyze::visibility;
@ -10,16 +10,16 @@ use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> { pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
let stmt = suite.first()?; let stmt = suite.first()?;
// Require the docstring to be a standalone expression. // Require the docstring to be a standalone expression.
let StmtKind::Expr { value } = &stmt.node else { let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node else {
return None; return None;
}; };
// Only match strings. // Only match strings.
if !matches!( if !matches!(
&value.node, &value.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(_), value: Constant::Str(_),
.. ..
} })
) { ) {
return None; return None;
} }

View file

@ -3,7 +3,7 @@
use anyhow::Result; use anyhow::Result;
use libcst_native::{Codegen, CodegenState, ImportAlias, Name, NameOrAttribute}; use libcst_native::{Codegen, CodegenState, ImportAlias, Name, NameOrAttribute};
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use rustpython_parser::ast::{Stmt, StmtKind, Suite}; use rustpython_parser::ast::{self, Stmt, StmtKind, Suite};
use rustpython_parser::{lexer, Mode, Tok}; use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::Edit; use ruff_diagnostics::Edit;
@ -79,13 +79,13 @@ impl<'a> Importer<'a> {
if stmt.start() >= at { if stmt.start() >= at {
break; break;
} }
if let StmtKind::ImportFrom { if let StmtKind::ImportFrom(ast::StmtImportFrom {
module: name, module: name,
level, level,
.. ..
} = &stmt.node }) = &stmt.node
{ {
if level.map_or(true, |level| level == 0) if level.map_or(true, |level| level.to_u32() == 0)
&& name.as_ref().map_or(false, |name| name == module) && name.as_ref().map_or(false, |name| name == module)
{ {
import_from = Some(*stmt); import_from = Some(*stmt);
@ -178,7 +178,8 @@ fn match_docstring_end(body: &[Stmt]) -> Option<TextSize> {
/// along with a trailing newline suffix. /// along with a trailing newline suffix.
fn end_of_statement_insertion(stmt: &Stmt, locator: &Locator, stylist: &Stylist) -> Insertion { fn end_of_statement_insertion(stmt: &Stmt, locator: &Locator, stylist: &Stylist) -> Insertion {
let location = stmt.end(); let location = stmt.end();
let mut tokens = lexer::lex_located(locator.after(location), Mode::Module, location).flatten(); let mut tokens =
lexer::lex_starts_at(locator.after(location), Mode::Module, location).flatten();
if let Some((Tok::Semi, range)) = tokens.next() { if let Some((Tok::Semi, range)) = tokens.next() {
// If the first token after the docstring is a semicolon, insert after the semicolon as an // If the first token after the docstring is a semicolon, insert after the semicolon as an
// inline statement; // inline statement;
@ -211,7 +212,7 @@ fn top_of_file_insertion(body: &[Stmt], locator: &Locator, stylist: &Stylist) ->
let mut location = if let Some(location) = match_docstring_end(body) { let mut location = if let Some(location) = match_docstring_end(body) {
// If the first token after the docstring is a semicolon, insert after the semicolon as an // If the first token after the docstring is a semicolon, insert after the semicolon as an
// inline statement; // inline statement;
let first_token = lexer::lex_located(locator.after(location), Mode::Module, location) let first_token = lexer::lex_starts_at(locator.after(location), Mode::Module, location)
.flatten() .flatten()
.next(); .next();
if let Some((Tok::Semi, range)) = first_token { if let Some((Tok::Semi, range)) = first_token {
@ -226,7 +227,7 @@ fn top_of_file_insertion(body: &[Stmt], locator: &Locator, stylist: &Stylist) ->
// Skip over any comments and empty lines. // Skip over any comments and empty lines.
for (tok, range) in for (tok, range) in
lexer::lex_located(locator.after(location), Mode::Module, location).flatten() lexer::lex_starts_at(locator.after(location), Mode::Module, location).flatten()
{ {
if matches!(tok, Tok::Comment(..) | Tok::Newline) { if matches!(tok, Tok::Comment(..) | Tok::Newline) {
location = locator.full_line_end(range.end()); location = locator.full_line_end(range.end());

View file

@ -145,7 +145,7 @@ impl<'a> DisplayParseError<'a> {
impl Display for DisplayParseError<'_> { impl Display for DisplayParseError<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let source_location = self.source_code.source_location(self.error.location); let source_location = self.source_code.source_location(self.error.offset);
write!( write!(
f, f,

View file

@ -1,5 +1,5 @@
use num_bigint::BigInt; use num_bigint::BigInt;
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Located}; use rustpython_parser::ast::{self, Attributed, Cmpop, Constant, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -124,16 +124,15 @@ fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool {
pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) { pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
if is_sys(checker, value, "version") { if is_sys(checker, value, "version") {
match &slice.node { match &slice.node {
ExprKind::Slice { ExprKind::Slice(ast::ExprSlice {
lower: None, lower: None,
upper: Some(upper), upper: Some(upper),
step: None, step: None,
.. }) => {
} => { if let ExprKind::Constant(ast::ExprConstant {
if let ExprKind::Constant {
value: Constant::Int(i), value: Constant::Int(i),
.. ..
} = &upper.node }) = &upper.node
{ {
if *i == BigInt::from(1) if *i == BigInt::from(1)
&& checker.settings.rules.enabled(Rule::SysVersionSlice1) && checker.settings.rules.enabled(Rule::SysVersionSlice1)
@ -151,10 +150,10 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
} }
} }
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(i), value: Constant::Int(i),
.. ..
} => { }) => {
if *i == BigInt::from(2) && checker.settings.rules.enabled(Rule::SysVersion2) { if *i == BigInt::from(2) && checker.settings.rules.enabled(Rule::SysVersion2) {
checker checker
.diagnostics .diagnostics
@ -175,21 +174,23 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
/// YTT103, YTT201, YTT203, YTT204, YTT302 /// YTT103, YTT201, YTT203, YTT204, YTT302
pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &[Expr]) { pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &[Expr]) {
match &left.node { match &left.node {
ExprKind::Subscript { value, slice, .. } if is_sys(checker, value, "version_info") => { ExprKind::Subscript(ast::ExprSubscript { value, slice, .. })
if let ExprKind::Constant { if is_sys(checker, value, "version_info") =>
{
if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(i), value: Constant::Int(i),
.. ..
} = &slice.node }) = &slice.node
{ {
if *i == BigInt::from(0) { if *i == BigInt::from(0) {
if let ( if let (
[Cmpop::Eq | Cmpop::NotEq], [Cmpop::Eq | Cmpop::NotEq],
[Located { [Attributed {
node: node:
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(n), value: Constant::Int(n),
.. ..
}, }),
.. ..
}], }],
) = (ops, comparators) ) = (ops, comparators)
@ -205,12 +206,12 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
} else if *i == BigInt::from(1) { } else if *i == BigInt::from(1) {
if let ( if let (
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE], [Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
[Located { [Attributed {
node: node:
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(_), value: Constant::Int(_),
.. ..
}, }),
.. ..
}], }],
) = (ops, comparators) ) = (ops, comparators)
@ -225,17 +226,17 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
} }
} }
ExprKind::Attribute { value, attr, .. } ExprKind::Attribute(ast::ExprAttribute { value, attr, .. })
if is_sys(checker, value, "version_info") && attr == "minor" => if is_sys(checker, value, "version_info") && attr == "minor" =>
{ {
if let ( if let (
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE], [Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
[Located { [Attributed {
node: node:
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(_), value: Constant::Int(_),
.. ..
}, }),
.. ..
}], }],
) = (ops, comparators) ) = (ops, comparators)
@ -258,12 +259,12 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
if is_sys(checker, left, "version") { if is_sys(checker, left, "version") {
if let ( if let (
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE], [Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
[Located { [Attributed {
node: node:
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(s), value: Constant::Str(s),
.. ..
}, }),
.. ..
}], }],
) = (ops, comparators) ) = (ops, comparators)

View file

@ -13,7 +13,7 @@ pub fn add_return_annotation(locator: &Locator, stmt: &Stmt, annotation: &str) -
let mut seen_lpar = false; let mut seen_lpar = false;
let mut seen_rpar = false; let mut seen_rpar = false;
let mut count: usize = 0; let mut count: usize = 0;
for (tok, range) in lexer::lex_located(contents, Mode::Module, stmt.start()).flatten() { for (tok, range) in lexer::lex_starts_at(contents, Mode::Module, stmt.start()).flatten() {
if seen_lpar && seen_rpar { if seen_lpar && seen_rpar {
if matches!(tok, Tok::Colon) { if matches!(tok, Tok::Colon) {
return Ok(Edit::insertion(format!(" -> {annotation}"), range.start())); return Ok(Edit::insertion(format!(" -> {annotation}"), range.start()));

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Arguments, Expr, Stmt, StmtKind}; use rustpython_parser::ast::{self, Arguments, Expr, Stmt, StmtKind};
use ruff_python_ast::cast; use ruff_python_ast::cast;
use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::analyze::visibility;
@ -8,20 +8,20 @@ use crate::docstrings::definition::{Definition, DefinitionKind};
pub(super) fn match_function_def(stmt: &Stmt) -> (&str, &Arguments, Option<&Expr>, &Vec<Stmt>) { pub(super) fn match_function_def(stmt: &Stmt) -> (&str, &Arguments, Option<&Expr>, &Vec<Stmt>) {
match &stmt.node { match &stmt.node {
StmtKind::FunctionDef { StmtKind::FunctionDef(ast::StmtFunctionDef {
name, name,
args, args,
returns, returns,
body, body,
.. ..
} })
| StmtKind::AsyncFunctionDef { | StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
name, name,
args, args,
returns, returns,
body, body,
.. ..
} => (name, args, returns.as_ref().map(|expr| &**expr), body), }) => (name, args, returns.as_ref().map(|expr| &**expr), body),
_ => panic!("Found non-FunctionDef in match_name"), _ => panic!("Found non-FunctionDef in match_name"),
} }
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -420,10 +420,10 @@ fn is_none_returning(body: &[Stmt]) -> bool {
for expr in visitor.returns.into_iter().flatten() { for expr in visitor.returns.into_iter().flatten() {
if !matches!( if !matches!(
expr.node, expr.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::None, value: Constant::None,
.. ..
} })
) { ) {
return false; return false;
} }

View file

@ -1,6 +1,6 @@
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use rustpython_parser::ast::{Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -10,10 +10,10 @@ static PASSWORD_CANDIDATE_REGEX: Lazy<Regex> = Lazy::new(|| {
pub fn string_literal(expr: &Expr) -> Option<&str> { pub fn string_literal(expr: &Expr) -> Option<&str> {
match &expr.node { match &expr.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(string), value: Constant::Str(string),
.. ..
} => Some(string), }) => Some(string),
_ => None, _ => None,
} }
} }
@ -24,7 +24,7 @@ pub fn matches_password_name(string: &str) -> bool {
pub fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> bool { pub fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> bool {
type_.map_or(true, |type_| { type_.map_or(true, |type_| {
if let ExprKind::Tuple { elts, .. } = &type_.node { if let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &type_.node {
elts.iter().any(|type_| { elts.iter().any(|type_| {
checker checker
.ctx .ctx

View file

@ -1,7 +1,7 @@
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Operator}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword, Operator};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -70,14 +70,14 @@ static PYSTAT_MAPPING: Lazy<FxHashMap<&'static str, u16>> = Lazy::new(|| {
fn get_int_value(expr: &Expr) -> Option<u16> { fn get_int_value(expr: &Expr) -> Option<u16> {
match &expr.node { match &expr.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(value), value: Constant::Int(value),
.. ..
} => value.to_u16(), }) => value.to_u16(),
ExprKind::Attribute { .. } => { ExprKind::Attribute(_) => {
compose_call_path(expr).and_then(|path| PYSTAT_MAPPING.get(path.as_str()).copied()) compose_call_path(expr).and_then(|path| PYSTAT_MAPPING.get(path.as_str()).copied())
} }
ExprKind::BinOp { left, op, right } => { ExprKind::BinOp(ast::ExprBinOp { left, op, right }) => {
if let (Some(left_value), Some(right_value)) = if let (Some(left_value), Some(right_value)) =
(get_int_value(left), get_int_value(right)) (get_int_value(left), get_int_value(right))
{ {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -15,7 +15,7 @@ impl Violation for ExecBuiltin {
/// S102 /// S102
pub fn exec_used(expr: &Expr, func: &Expr) -> Option<Diagnostic> { pub fn exec_used(expr: &Expr, func: &Expr) -> Option<Diagnostic> {
let ExprKind::Name { id, .. } = &func.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &func.node else {
return None; return None;
}; };
if id != "exec" { if id != "exec" {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -24,17 +24,17 @@ impl Violation for HardcodedPasswordString {
fn password_target(target: &Expr) -> Option<&str> { fn password_target(target: &Expr) -> Option<&str> {
let target_name = match &target.node { let target_name = match &target.node {
// variable = "s3cr3t" // variable = "s3cr3t"
ExprKind::Name { id, .. } => id, ExprKind::Name(ast::ExprName { id, .. }) => id.as_str(),
// d["password"] = "s3cr3t" // d["password"] = "s3cr3t"
ExprKind::Subscript { slice, .. } => match &slice.node { ExprKind::Subscript(ast::ExprSubscript { slice, .. }) => match &slice.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(string), value: Constant::Str(string),
.. ..
} => string, }) => string,
_ => return None, _ => return None,
}, },
// obj.password = "s3cr3t" // obj.password = "s3cr3t"
ExprKind::Attribute { attr, .. } => attr, ExprKind::Attribute(ast::ExprAttribute { attr, .. }) => attr,
_ => return None, _ => return None,
}; };

View file

@ -1,6 +1,6 @@
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use rustpython_parser::ast::{Expr, ExprKind, Operator}; use rustpython_parser::ast::{self, Expr, ExprKind, Operator};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -56,10 +56,10 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
match &expr.node { match &expr.node {
// "select * from table where val = " + "str" + ... // "select * from table where val = " + "str" + ...
// "select * from table where val = %s" % ... // "select * from table where val = %s" % ...
ExprKind::BinOp { ExprKind::BinOp(ast::ExprBinOp {
op: Operator::Add | Operator::Mod, op: Operator::Add | Operator::Mod,
.. ..
} => { }) => {
let Some(parent) = checker.ctx.expr_parent() else { let Some(parent) = checker.ctx.expr_parent() else {
if any_over_expr(expr, &has_string_literal) { if any_over_expr(expr, &has_string_literal) {
return Some(unparse_expr(expr, checker.stylist)); return Some(unparse_expr(expr, checker.stylist));
@ -67,7 +67,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
return None; return None;
}; };
// Only evaluate the full BinOp, not the nested components. // Only evaluate the full BinOp, not the nested components.
let ExprKind::BinOp { .. } = &parent.node else { let ExprKind::BinOp(_ )= &parent.node else {
if any_over_expr(expr, &has_string_literal) { if any_over_expr(expr, &has_string_literal) {
return Some(unparse_expr(expr, checker.stylist)); return Some(unparse_expr(expr, checker.stylist));
} }
@ -75,8 +75,8 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
}; };
None None
} }
ExprKind::Call { func, .. } => { ExprKind::Call(ast::ExprCall { func, .. }) => {
let ExprKind::Attribute{ attr, value, .. } = &func.node else { let ExprKind::Attribute(ast::ExprAttribute { attr, value, .. }) = &func.node else {
return None; return None;
}; };
// "select * from table where val = {}".format(...) // "select * from table where val = {}".format(...)
@ -86,7 +86,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
None None
} }
// f"select * from table where val = {val}" // f"select * from table where val = {val}"
ExprKind::JoinedStr { .. } => Some(unparse_expr(expr, checker.stylist)), ExprKind::JoinedStr(_) => Some(unparse_expr(expr, checker.stylist)),
_ => None, _ => None,
} }
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -27,10 +27,10 @@ fn is_used_for_security(call_args: &SimpleCallArgs) -> bool {
match call_args.keyword_argument("usedforsecurity") { match call_args.keyword_argument("usedforsecurity") {
Some(expr) => !matches!( Some(expr) => !matches!(
&expr.node, &expr.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Bool(false), value: Constant::Bool(false),
.. ..
} })
), ),
_ => true, _ => true,
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -47,13 +47,13 @@ pub fn jinja2_autoescape_false(
if let Some(autoescape_arg) = call_args.keyword_argument("autoescape") { if let Some(autoescape_arg) = call_args.keyword_argument("autoescape") {
match &autoescape_arg.node { match &autoescape_arg.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Bool(true), value: Constant::Bool(true),
.. ..
} => (), }) => (),
ExprKind::Call { func, .. } => { ExprKind::Call(ast::ExprCall { func, .. }) => {
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
if id.as_str() != "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(), autoescape_arg.range(),

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -56,10 +56,10 @@ pub fn request_with_no_cert_validation(
}) { }) {
let call_args = SimpleCallArgs::new(args, keywords); let call_args = SimpleCallArgs::new(args, keywords);
if let Some(verify_arg) = call_args.keyword_argument("verify") { if let Some(verify_arg) = call_args.keyword_argument("verify") {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Bool(false), value: Constant::Bool(false),
.. ..
} = &verify_arg.node }) = &verify_arg.node
{ {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
RequestWithNoCertValidation { RequestWithNoCertValidation {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -45,10 +45,10 @@ pub fn request_without_timeout(
let call_args = SimpleCallArgs::new(args, keywords); let call_args = SimpleCallArgs::new(args, keywords);
if let Some(timeout_arg) = call_args.keyword_argument("timeout") { if let Some(timeout_arg) = call_args.keyword_argument("timeout") {
if let Some(timeout) = match &timeout_arg.node { if let Some(timeout) = match &timeout_arg.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: value @ Constant::None, value: value @ Constant::None,
.. ..
} => Some(unparse_constant(value, checker.stylist)), }) => Some(unparse_constant(value, checker.stylist)),
_ => None, _ => None,
} { } {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(

View file

@ -2,7 +2,7 @@
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -159,17 +159,17 @@ fn find_shell_keyword<'a>(ctx: &Context, keywords: &'a [Keyword]) -> Option<Shel
fn shell_call_seems_safe(arg: &Expr) -> bool { fn shell_call_seems_safe(arg: &Expr) -> bool {
matches!( matches!(
arg.node, arg.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(_), value: Constant::Str(_),
.. ..
} })
) )
} }
/// Return the [`Expr`] as a string literal, if it's a string or a list of strings. /// Return the [`Expr`] as a string literal, if it's a string or a list of strings.
fn try_string_literal(expr: &Expr) -> Option<&str> { fn try_string_literal(expr: &Expr) -> Option<&str> {
match &expr.node { match &expr.node {
ExprKind::List { elts, .. } => { ExprKind::List(ast::ExprList { elts, .. }) => {
if elts.is_empty() { if elts.is_empty() {
None None
} else { } else {

View file

@ -1,5 +1,5 @@
use num_traits::{One, Zero}; use num_traits::{One, Zero};
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -33,10 +33,10 @@ pub fn snmp_insecure_version(
{ {
let call_args = SimpleCallArgs::new(args, keywords); let call_args = SimpleCallArgs::new(args, keywords);
if let Some(mp_model_arg) = call_args.keyword_argument("mpModel") { if let Some(mp_model_arg) = call_args.keyword_argument("mpModel") {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(value), value: Constant::Int(value),
.. ..
} = &mp_model_arg.node }) = &mp_model_arg.node
{ {
if value.is_zero() || value.is_one() { if value.is_zero() || value.is_one() {
checker checker

View file

@ -1,7 +1,7 @@
//! Check for calls to suspicious functions, or calls into suspicious modules. //! Check for calls to suspicious functions, or calls into suspicious modules.
//! //!
//! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html> //! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html>
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation}; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -466,7 +466,7 @@ const SUSPICIOUS_MODULES: &[SuspiciousModule] = &[
/// S001 /// S001
pub fn suspicious_function_call(checker: &mut Checker, expr: &Expr) { pub fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
let ExprKind::Call { func, .. } = &expr.node else { let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node else {
return; return;
}; };

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -48,8 +48,8 @@ pub fn unsafe_yaml_load(checker: &mut Checker, func: &Expr, args: &[Expr], keywo
}) })
{ {
let loader = match &loader_arg.node { let loader = match &loader_arg.node {
ExprKind::Attribute { attr, .. } => Some(attr.to_string()), ExprKind::Attribute(ast::ExprAttribute { attr, .. }) => Some(attr.to_string()),
ExprKind::Name { id, .. } => Some(id.to_string()), ExprKind::Name(ast::ExprName { id, .. }) => Some(id.to_string()),
_ => None, _ => None,
}; };
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -30,17 +30,17 @@ pub fn blind_except(
let Some(type_) = type_ else { let Some(type_) = type_ else {
return; return;
}; };
let ExprKind::Name { id, .. } = &type_.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &type_.node else {
return; return;
}; };
for exception in ["BaseException", "Exception"] { for exception in ["BaseException", "Exception"] {
if id == exception && checker.ctx.is_builtin(exception) { if id == exception && checker.ctx.is_builtin(exception) {
// If the exception is re-raised, don't flag an error. // If the exception is re-raised, don't flag an error.
if body.iter().any(|stmt| { if body.iter().any(|stmt| {
if let StmtKind::Raise { exc, .. } = &stmt.node { if let StmtKind::Raise(ast::StmtRaise { exc, .. }) = &stmt.node {
if let Some(exc) = exc { if let Some(exc) = exc {
if let ExprKind::Name { id, .. } = &exc.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &exc.node {
name.map_or(false, |name| name == id) name.map_or(false, |name| id == name)
} else { } else {
false false
} }
@ -56,10 +56,12 @@ pub fn blind_except(
// If the exception is logged, don't flag an error. // If the exception is logged, don't flag an error.
if body.iter().any(|stmt| { if body.iter().any(|stmt| {
if let StmtKind::Expr { value } = &stmt.node { if let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node {
if let ExprKind::Call { func, keywords, .. } = &value.node { if let ExprKind::Call(ast::ExprCall { func, keywords, .. }) = &value.node {
if logging::is_logger_candidate(&checker.ctx, func) { if logging::is_logger_candidate(&checker.ctx, func) {
if let ExprKind::Attribute { attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &func.node
{
let attr = attr.as_str();
if attr == "exception" { if attr == "exception" {
return true; return true;
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Arguments, Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Arguments, Constant, Expr, ExprKind};
use ruff_diagnostics::Violation; use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_diagnostics::{Diagnostic, DiagnosticKind};
@ -67,11 +67,11 @@ const FUNC_DEF_NAME_ALLOWLIST: &[&str] = &["__setitem__"];
/// `true`, the function name must be explicitly allowed, and the argument must /// `true`, the function name must be explicitly allowed, and the argument must
/// be either the first or second argument in the call. /// be either the first or second argument in the call.
fn allow_boolean_trap(func: &Expr) -> bool { fn allow_boolean_trap(func: &Expr) -> bool {
if let ExprKind::Attribute { attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &func.node {
return FUNC_CALL_NAME_ALLOWLIST.contains(&attr.as_ref()); return FUNC_CALL_NAME_ALLOWLIST.contains(&attr.as_ref());
} }
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
return FUNC_CALL_NAME_ALLOWLIST.contains(&id.as_ref()); return FUNC_CALL_NAME_ALLOWLIST.contains(&id.as_ref());
} }
@ -81,10 +81,10 @@ fn allow_boolean_trap(func: &Expr) -> bool {
const fn is_boolean_arg(arg: &Expr) -> bool { const fn is_boolean_arg(arg: &Expr) -> bool {
matches!( matches!(
&arg.node, &arg.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Bool(_), value: Constant::Bool(_),
.. ..
} })
) )
} }
@ -120,11 +120,11 @@ pub fn check_positional_boolean_in_def(
// check for both bool (python class) and 'bool' (string annotation) // check for both bool (python class) and 'bool' (string annotation)
let hint = match &expr.node { let hint = match &expr.node {
ExprKind::Name { id, .. } => id == "bool", ExprKind::Name(ast::ExprName { id, .. }) => id == "bool",
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(value), value: Constant::Str(value),
.. ..
} => value == "bool", }) => value == "bool",
_ => false, _ => false,
}; };
if !hint { if !hint {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -57,8 +57,8 @@ fn is_abc_class(context: &Context, bases: &[Expr], keywords: &[Keyword]) -> bool
fn is_empty_body(body: &[Stmt]) -> bool { fn is_empty_body(body: &[Stmt]) -> bool {
body.iter().all(|stmt| match &stmt.node { body.iter().all(|stmt| match &stmt.node {
StmtKind::Pass => true, StmtKind::Pass => true,
StmtKind::Expr { value } => match &value.node { StmtKind::Expr(ast::StmtExpr { value }) => match &value.node {
ExprKind::Constant { value, .. } => { ExprKind::Constant(ast::ExprConstant { value, .. }) => {
matches!(value, Constant::Str(..) | Constant::Ellipsis) matches!(value, Constant::Str(..) | Constant::Ellipsis)
} }
_ => false, _ => false,
@ -88,23 +88,23 @@ pub fn abstract_base_class(
for stmt in body { for stmt in body {
// https://github.com/PyCQA/flake8-bugbear/issues/293 // https://github.com/PyCQA/flake8-bugbear/issues/293
// Ignore abc's that declares a class attribute that must be set // Ignore abc's that declares a class attribute that must be set
if let StmtKind::AnnAssign { .. } | StmtKind::Assign { .. } = &stmt.node { if let StmtKind::AnnAssign(_) | StmtKind::Assign(_) = &stmt.node {
has_abstract_method = true; has_abstract_method = true;
continue; continue;
} }
let ( let (
StmtKind::FunctionDef { StmtKind::FunctionDef(ast::StmtFunctionDef {
decorator_list, decorator_list,
body, body,
name: method_name, name: method_name,
.. ..
} | StmtKind::AsyncFunctionDef { }) | StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
decorator_list, decorator_list,
body, body,
name: method_name, name: method_name,
.. ..
} })
) = &stmt.node else { ) = &stmt.node else {
continue; continue;
}; };

View file

@ -1,5 +1,5 @@
use ruff_text_size::TextSize; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -24,20 +24,17 @@ impl AlwaysAutofixableViolation for AssertFalse {
fn assertion_error(msg: Option<&Expr>) -> Stmt { fn assertion_error(msg: Option<&Expr>) -> Stmt {
Stmt::new( Stmt::new(
TextSize::default(), TextRange::default(),
TextSize::default(), StmtKind::Raise(ast::StmtRaise {
StmtKind::Raise {
exc: Some(Box::new(Expr::new( exc: Some(Box::new(Expr::new(
TextSize::default(), TextRange::default(),
TextSize::default(), ExprKind::Call(ast::ExprCall {
ExprKind::Call {
func: Box::new(Expr::new( func: Box::new(Expr::new(
TextSize::default(), TextRange::default(),
TextSize::default(), ExprKind::Name(ast::ExprName {
ExprKind::Name { id: "AssertionError".into(),
id: "AssertionError".to_string(),
ctx: ExprContext::Load, ctx: ExprContext::Load,
}, }),
)), )),
args: if let Some(msg) = msg { args: if let Some(msg) = msg {
vec![msg.clone()] vec![msg.clone()]
@ -45,19 +42,19 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
vec![] vec![]
}, },
keywords: vec![], keywords: vec![],
}, }),
))), ))),
cause: None, cause: None,
}, }),
) )
} }
/// B011 /// B011
pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) { pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) {
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Bool(false), value: Constant::Bool(false),
.. ..
} = &test.node else { } )= &test.node else {
return; return;
}; };

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{ExprKind, Stmt, Withitem}; use rustpython_parser::ast::{self, ExprKind, Stmt, Withitem};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -55,7 +55,7 @@ pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[With
return; return;
}; };
let item_context = &item.context_expr; let item_context = &item.context_expr;
let ExprKind::Call { func, args, keywords } = &item_context.node else { let ExprKind::Call(ast::ExprCall { func, args, keywords }) = &item_context.node else {
return; return;
}; };
if args.len() != 1 { if args.len() != 1 {
@ -74,7 +74,8 @@ pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[With
} }
let kind = { let kind = {
if matches!(&func.node, ExprKind::Attribute { attr, .. } if attr == "assertRaises") { if matches!(&func.node, ExprKind::Attribute(ast::ExprAttribute { attr, .. }) if attr == "assertRaises")
{
AssertionKind::AssertRaises AssertionKind::AssertRaises
} else if checker } else if checker
.ctx .ctx

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -20,13 +20,13 @@ pub fn assignment_to_os_environ(checker: &mut Checker, targets: &[Expr]) {
return; return;
} }
let target = &targets[0]; let target = &targets[0];
let ExprKind::Attribute { value, attr, .. } = &target.node else { let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) = &target.node else {
return; return;
}; };
if attr != "environ" { if attr != "environ" {
return; return;
} }
let ExprKind::Name { id, .. } = &value.node else { let ExprKind::Name(ast::ExprName { id, .. } )= &value.node else {
return; return;
}; };
if id != "os" { if id != "os" {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -36,7 +36,7 @@ pub fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
for decorator in decorator_list { for decorator in decorator_list {
// TODO(charlie): This should take into account `classmethod-decorators` and // TODO(charlie): This should take into account `classmethod-decorators` and
// `staticmethod-decorators`. // `staticmethod-decorators`.
if let ExprKind::Name { id, .. } = &decorator.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &decorator.node {
if id == "classmethod" || id == "staticmethod" { if id == "classmethod" || id == "staticmethod" {
return; return;
} }
@ -46,7 +46,7 @@ pub fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
if is_cache_func( if is_cache_func(
checker, checker,
match &decorator.node { match &decorator.node {
ExprKind::Call { func, .. } => func, ExprKind::Call(ast::ExprCall { func, .. }) => func,
_ => decorator, _ => decorator,
}, },
) { ) {

View file

@ -17,7 +17,7 @@ impl Violation for CannotRaiseLiteral {
/// B016 /// B016
pub fn cannot_raise_literal(checker: &mut Checker, expr: &Expr) { pub fn cannot_raise_literal(checker: &mut Checker, expr: &Expr) {
let ExprKind::Constant { .. } = &expr.node else { let ExprKind::Constant ( _) = &expr.node else {
return; return;
}; };
checker checker

View file

@ -1,7 +1,7 @@
use itertools::Itertools; use itertools::Itertools;
use ruff_text_size::TextSize; use ruff_text_size::TextRange;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind}; use rustpython_parser::ast::{self, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_diagnostics::{Diagnostic, Edit, Fix};
@ -50,9 +50,8 @@ impl AlwaysAutofixableViolation for DuplicateHandlerException {
fn type_pattern(elts: Vec<&Expr>) -> Expr { fn type_pattern(elts: Vec<&Expr>) -> Expr {
Expr::new( Expr::new(
TextSize::default(), TextRange::default(),
TextSize::default(), ast::ExprTuple {
ExprKind::Tuple {
elts: elts.into_iter().cloned().collect(), elts: elts.into_iter().cloned().collect(),
ctx: ExprContext::Load, ctx: ExprContext::Load,
}, },
@ -117,11 +116,11 @@ pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
let mut seen: FxHashSet<CallPath> = FxHashSet::default(); let mut seen: FxHashSet<CallPath> = FxHashSet::default();
let mut duplicates: FxHashMap<CallPath, Vec<&Expr>> = FxHashMap::default(); let mut duplicates: FxHashMap<CallPath, Vec<&Expr>> = FxHashMap::default();
for handler in handlers { for handler in handlers {
let ExcepthandlerKind::ExceptHandler { type_: Some(type_), .. } = &handler.node else { let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_: Some(type_), .. }) = &handler.node else {
continue; continue;
}; };
match &type_.node { match &type_.node {
ExprKind::Attribute { .. } | ExprKind::Name { .. } => { ExprKind::Attribute(_) | ExprKind::Name(_) => {
if let Some(call_path) = call_path::collect_call_path(type_) { if let Some(call_path) = call_path::collect_call_path(type_) {
if seen.contains(&call_path) { if seen.contains(&call_path) {
duplicates.entry(call_path).or_default().push(type_); duplicates.entry(call_path).or_default().push(type_);
@ -130,7 +129,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
} }
} }
} }
ExprKind::Tuple { elts, .. } => { ExprKind::Tuple(ast::ExprTuple { elts, .. }) => {
for (name, expr) in duplicate_handler_exceptions(checker, type_, elts) { for (name, expr) in duplicate_handler_exceptions(checker, type_, elts) {
if seen.contains(&name) { if seen.contains(&name) {
duplicates.entry(name).or_default().push(expr); duplicates.entry(name).or_default().push(expr);

View file

@ -1,5 +1,5 @@
use rustpython_parser::ast::Excepthandler; use rustpython_parser::ast::Excepthandler;
use rustpython_parser::ast::{ExcepthandlerKind, ExprKind}; use rustpython_parser::ast::{self, ExcepthandlerKind, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -18,11 +18,12 @@ impl Violation for ExceptWithEmptyTuple {
/// B029 /// B029
pub fn except_with_empty_tuple(checker: &mut Checker, excepthandler: &Excepthandler) { pub fn except_with_empty_tuple(checker: &mut Checker, excepthandler: &Excepthandler) {
let ExcepthandlerKind::ExceptHandler { type_, .. } = &excepthandler.node; let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_, .. }) =
&excepthandler.node;
let Some(type_) = type_ else { let Some(type_) = type_ else {
return; return;
}; };
let ExprKind::Tuple { elts, .. } = &type_.node else { let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &type_.node else {
return; return;
}; };
if elts.is_empty() { if elts.is_empty() {

View file

@ -1,6 +1,6 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind}; use rustpython_parser::ast::{self, Excepthandler, ExcepthandlerKind, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -21,15 +21,16 @@ impl Violation for ExceptWithNonExceptionClasses {
/// This should leave any unstarred iterables alone (subsequently raising a /// This should leave any unstarred iterables alone (subsequently raising a
/// warning for B029). /// warning for B029).
fn flatten_starred_iterables(expr: &Expr) -> Vec<&Expr> { fn flatten_starred_iterables(expr: &Expr) -> Vec<&Expr> {
let ExprKind::Tuple { elts, .. } = &expr.node else { let ExprKind::Tuple(ast::ExprTuple { elts, .. } )= &expr.node else {
return vec![expr]; return vec![expr];
}; };
let mut flattened_exprs: Vec<&Expr> = Vec::with_capacity(elts.len()); let mut flattened_exprs: Vec<&Expr> = Vec::with_capacity(elts.len());
let mut exprs_to_process: VecDeque<&Expr> = elts.iter().collect(); let mut exprs_to_process: VecDeque<&Expr> = elts.iter().collect();
while let Some(expr) = exprs_to_process.pop_front() { while let Some(expr) = exprs_to_process.pop_front() {
match &expr.node { match &expr.node {
ExprKind::Starred { value, .. } => match &value.node { ExprKind::Starred(ast::ExprStarred { value, .. }) => match &value.node {
ExprKind::Tuple { elts, .. } | ExprKind::List { elts, .. } => { ExprKind::Tuple(ast::ExprTuple { elts, .. })
| ExprKind::List(ast::ExprList { elts, .. }) => {
exprs_to_process.append(&mut elts.iter().collect()); exprs_to_process.append(&mut elts.iter().collect());
} }
_ => flattened_exprs.push(value), _ => flattened_exprs.push(value),
@ -42,17 +43,15 @@ fn flatten_starred_iterables(expr: &Expr) -> Vec<&Expr> {
/// B030 /// B030
pub fn except_with_non_exception_classes(checker: &mut Checker, excepthandler: &Excepthandler) { pub fn except_with_non_exception_classes(checker: &mut Checker, excepthandler: &Excepthandler) {
let ExcepthandlerKind::ExceptHandler { type_, .. } = &excepthandler.node; let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_, .. }) =
&excepthandler.node;
let Some(type_) = type_ else { let Some(type_) = type_ else {
return; return;
}; };
for expr in flatten_starred_iterables(type_) { for expr in flatten_starred_iterables(type_) {
if !matches!( if !matches!(
&expr.node, &expr.node,
ExprKind::Subscript { .. } ExprKind::Subscript(_) | ExprKind::Attribute(_) | ExprKind::Name(_) | ExprKind::Call(_),
| ExprKind::Attribute { .. }
| ExprKind::Name { .. }
| ExprKind::Call { .. },
) { ) {
checker checker
.diagnostics .diagnostics

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -23,10 +23,10 @@ pub fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) {
let Some(stmt) = body.first() else { let Some(stmt) = body.first() else {
return; return;
}; };
let StmtKind::Expr { value } = &stmt.node else { let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node else {
return; return;
}; };
let ExprKind::JoinedStr { .. } = value.node else { let ExprKind::JoinedStr ( _) = value.node else {
return; return;
}; };
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(

View file

@ -1,5 +1,5 @@
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Arguments, Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Arguments, Constant, Expr, ExprKind};
use ruff_diagnostics::Violation; use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_diagnostics::{Diagnostic, DiagnosticKind};
@ -84,7 +84,7 @@ where
{ {
fn visit_expr(&mut self, expr: &'b Expr) { fn visit_expr(&mut self, expr: &'b Expr) {
match &expr.node { match &expr.node {
ExprKind::Call { func, args, .. } => { ExprKind::Call(ast::ExprCall { func, args, .. }) => {
if !is_mutable_func(self.checker, func) if !is_mutable_func(self.checker, func)
&& !is_immutable_func(&self.checker.ctx, func, &self.extend_immutable_calls) && !is_immutable_func(&self.checker.ctx, func, &self.extend_immutable_calls)
&& !is_nan_or_infinity(func, args) && !is_nan_or_infinity(func, args)
@ -99,14 +99,14 @@ where
} }
visitor::walk_expr(self, expr); visitor::walk_expr(self, expr);
} }
ExprKind::Lambda { .. } => {} ExprKind::Lambda(_) => {}
_ => visitor::walk_expr(self, expr), _ => visitor::walk_expr(self, expr),
} }
} }
} }
fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool { fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
let ExprKind::Name { id, .. } = &expr.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node else {
return false; return false;
}; };
if id != "float" { if id != "float" {
@ -115,10 +115,10 @@ fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
let Some(arg) = args.first() else { let Some(arg) = args.first() else {
return false; return false;
}; };
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(value), value: Constant::Str(value),
.. ..
} = &arg.node else { } )= &arg.node else {
return false; return false;
}; };
let lowercased = value.to_lowercase(); let lowercased = value.to_lowercase();

View file

@ -1,6 +1,6 @@
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustpython_parser::ast::{Comprehension, Expr, ExprContext, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Comprehension, Expr, ExprContext, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -36,7 +36,7 @@ struct LoadedNamesVisitor<'a> {
impl<'a> Visitor<'a> for LoadedNamesVisitor<'a> { impl<'a> Visitor<'a> for LoadedNamesVisitor<'a> {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match &expr.node { match &expr.node {
ExprKind::Name { id, ctx } => match ctx { ExprKind::Name(ast::ExprName { id, ctx }) => match ctx {
ExprContext::Load => self.loaded.push((id, expr, expr.range())), ExprContext::Load => self.loaded.push((id, expr, expr.range())),
ExprContext::Store => self.stored.push((id, expr, expr.range())), ExprContext::Store => self.stored.push((id, expr, expr.range())),
ExprContext::Del => {} ExprContext::Del => {}
@ -57,8 +57,8 @@ struct SuspiciousVariablesVisitor<'a> {
impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> { impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
fn visit_stmt(&mut self, stmt: &'a Stmt) { fn visit_stmt(&mut self, stmt: &'a Stmt) {
match &stmt.node { match &stmt.node {
StmtKind::FunctionDef { args, body, .. } StmtKind::FunctionDef(ast::StmtFunctionDef { args, body, .. })
| StmtKind::AsyncFunctionDef { args, body, .. } => { | StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef { args, body, .. }) => {
// Collect all loaded variable names. // Collect all loaded variable names.
let mut visitor = LoadedNamesVisitor::default(); let mut visitor = LoadedNamesVisitor::default();
visitor.visit_body(body); visitor.visit_body(body);
@ -76,9 +76,9 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
); );
return; return;
} }
StmtKind::Return { value: Some(value) } => { StmtKind::Return(ast::StmtReturn { value: Some(value) }) => {
// Mark `return lambda: x` as safe. // Mark `return lambda: x` as safe.
if matches!(value.node, ExprKind::Lambda { .. }) { if matches!(value.node, ExprKind::Lambda(_)) {
self.safe_functions.push(value); self.safe_functions.push(value);
} }
} }
@ -89,26 +89,27 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match &expr.node { match &expr.node {
ExprKind::Call { ExprKind::Call(ast::ExprCall {
func, func,
args, args,
keywords, keywords,
} => { }) => {
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
let id = id.as_str();
if id == "filter" || id == "reduce" || id == "map" { if id == "filter" || id == "reduce" || id == "map" {
for arg in args { for arg in args {
if matches!(arg.node, ExprKind::Lambda { .. }) { if matches!(arg.node, ExprKind::Lambda(_)) {
self.safe_functions.push(arg); self.safe_functions.push(arg);
} }
} }
} }
} }
if let ExprKind::Attribute { value, attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) = &func.node {
if attr == "reduce" { if attr == "reduce" {
if let ExprKind::Name { id, .. } = &value.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &value.node {
if id == "functools" { if id == "functools" {
for arg in args { for arg in args {
if matches!(arg.node, ExprKind::Lambda { .. }) { if matches!(arg.node, ExprKind::Lambda(_)) {
self.safe_functions.push(arg); self.safe_functions.push(arg);
} }
} }
@ -118,13 +119,13 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
} }
for keyword in keywords { for keyword in keywords {
if keyword.node.arg.as_ref().map_or(false, |arg| arg == "key") if keyword.node.arg.as_ref().map_or(false, |arg| arg == "key")
&& matches!(keyword.node.value.node, ExprKind::Lambda { .. }) && matches!(keyword.node.value.node, ExprKind::Lambda(_))
{ {
self.safe_functions.push(&keyword.node.value); self.safe_functions.push(&keyword.node.value);
} }
} }
} }
ExprKind::Lambda { args, body } => { ExprKind::Lambda(ast::ExprLambda { args, body }) => {
if !self.safe_functions.contains(&expr) { if !self.safe_functions.contains(&expr) {
// Collect all loaded variable names. // Collect all loaded variable names.
let mut visitor = LoadedNamesVisitor::default(); let mut visitor = LoadedNamesVisitor::default();
@ -160,13 +161,14 @@ struct NamesFromAssignmentsVisitor<'a> {
impl<'a> Visitor<'a> for NamesFromAssignmentsVisitor<'a> { impl<'a> Visitor<'a> for NamesFromAssignmentsVisitor<'a> {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match &expr.node { match &expr.node {
ExprKind::Name { id, .. } => { ExprKind::Name(ast::ExprName { id, .. }) => {
self.names.insert(id.as_str()); self.names.insert(id.as_str());
} }
ExprKind::Starred { value, .. } => { ExprKind::Starred(ast::ExprStarred { value, .. }) => {
self.visit_expr(value); self.visit_expr(value);
} }
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => { ExprKind::List(ast::ExprList { elts, .. })
| ExprKind::Tuple(ast::ExprTuple { elts, .. }) => {
for expr in elts { for expr in elts {
self.visit_expr(expr); self.visit_expr(expr);
} }
@ -186,24 +188,24 @@ impl<'a> Visitor<'a> for AssignedNamesVisitor<'a> {
fn visit_stmt(&mut self, stmt: &'a Stmt) { fn visit_stmt(&mut self, stmt: &'a Stmt) {
if matches!( if matches!(
&stmt.node, &stmt.node,
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } StmtKind::FunctionDef(_) | StmtKind::AsyncFunctionDef(_)
) { ) {
// Don't recurse. // Don't recurse.
return; return;
} }
match &stmt.node { match &stmt.node {
StmtKind::Assign { targets, .. } => { StmtKind::Assign(ast::StmtAssign { targets, .. }) => {
let mut visitor = NamesFromAssignmentsVisitor::default(); let mut visitor = NamesFromAssignmentsVisitor::default();
for expr in targets { for expr in targets {
visitor.visit_expr(expr); visitor.visit_expr(expr);
} }
self.names.extend(visitor.names); self.names.extend(visitor.names);
} }
StmtKind::AugAssign { target, .. } StmtKind::AugAssign(ast::StmtAugAssign { target, .. })
| StmtKind::AnnAssign { target, .. } | StmtKind::AnnAssign(ast::StmtAnnAssign { target, .. })
| StmtKind::For { target, .. } | StmtKind::For(ast::StmtFor { target, .. })
| StmtKind::AsyncFor { target, .. } => { | StmtKind::AsyncFor(ast::StmtAsyncFor { target, .. }) => {
let mut visitor = NamesFromAssignmentsVisitor::default(); let mut visitor = NamesFromAssignmentsVisitor::default();
visitor.visit_expr(target); visitor.visit_expr(target);
self.names.extend(visitor.names); self.names.extend(visitor.names);
@ -215,7 +217,7 @@ impl<'a> Visitor<'a> for AssignedNamesVisitor<'a> {
} }
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
if matches!(&expr.node, ExprKind::Lambda { .. }) { if matches!(&expr.node, ExprKind::Lambda(_)) {
// Don't recurse. // Don't recurse.
return; return;
} }

View file

@ -1,5 +1,5 @@
use ruff_text_size::TextSize; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Constant, Expr, ExprContext, ExprKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -27,11 +27,10 @@ impl AlwaysAutofixableViolation for GetAttrWithConstant {
} }
fn attribute(value: &Expr, attr: &str) -> Expr { fn attribute(value: &Expr, attr: &str) -> Expr {
Expr::new( Expr::new(
TextSize::default(), TextRange::default(),
TextSize::default(), ast::ExprAttribute {
ExprKind::Attribute {
value: Box::new(value.clone()), value: Box::new(value.clone()),
attr: attr.to_string(), attr: attr.into(),
ctx: ExprContext::Load, ctx: ExprContext::Load,
}, },
) )
@ -39,7 +38,7 @@ fn attribute(value: &Expr, attr: &str) -> Expr {
/// B009 /// B009
pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) { pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
let ExprKind::Name { id, .. } = &func.node else { let ExprKind::Name(ast::ExprName { id, .. } )= &func.node else {
return; return;
}; };
if id != "getattr" { if id != "getattr" {
@ -48,10 +47,10 @@ pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
let [obj, arg] = args else { let [obj, arg] = args else {
return; return;
}; };
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(value), value: Constant::Str(value),
.. ..
} = &arg.node else { } )= &arg.node else {
return; return;
}; };
if !is_identifier(value) { if !is_identifier(value) {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Stmt, StmtKind}; use rustpython_parser::ast::{self, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -24,33 +24,34 @@ fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
JumpStatementInFinally { JumpStatementInFinally {
name: match &stmt.node { name: match &stmt.node {
StmtKind::Break { .. } => "break".to_string(), StmtKind::Break => "break",
StmtKind::Continue { .. } => "continue".to_string(), StmtKind::Continue => "continue",
StmtKind::Return { .. } => "return".to_string(), StmtKind::Return(_) => "return",
_ => unreachable!( _ => unreachable!(
"Expected StmtKind::Break | StmtKind::Continue | StmtKind::Return" "Expected StmtKind::Break | StmtKind::Continue | StmtKind::Return"
), ),
}, }
.to_owned(),
}, },
stmt.range(), stmt.range(),
)); ));
} }
match &stmt.node { match &stmt.node {
StmtKind::While { body, .. } StmtKind::While(ast::StmtWhile { body, .. })
| StmtKind::For { body, .. } | StmtKind::For(ast::StmtFor { body, .. })
| StmtKind::AsyncFor { body, .. } => { | StmtKind::AsyncFor(ast::StmtAsyncFor { body, .. }) => {
walk_stmt(checker, body, |stmt| { walk_stmt(checker, body, |stmt| {
matches!(stmt.node, StmtKind::Return { .. }) matches!(stmt.node, StmtKind::Return(_))
}); });
} }
StmtKind::If { body, .. } StmtKind::If(ast::StmtIf { body, .. })
| StmtKind::Try { body, .. } | StmtKind::Try(ast::StmtTry { body, .. })
| StmtKind::TryStar { body, .. } | StmtKind::TryStar(ast::StmtTryStar { body, .. })
| StmtKind::With { body, .. } | StmtKind::With(ast::StmtWith { body, .. })
| StmtKind::AsyncWith { body, .. } => { | StmtKind::AsyncWith(ast::StmtAsyncWith { body, .. }) => {
walk_stmt(checker, body, f); walk_stmt(checker, body, f);
} }
StmtKind::Match { cases, .. } => { StmtKind::Match(ast::StmtMatch { cases, .. }) => {
for case in cases { for case in cases {
walk_stmt(checker, &case.body, f); walk_stmt(checker, &case.body, f);
} }
@ -65,7 +66,7 @@ pub fn jump_statement_in_finally(checker: &mut Checker, finalbody: &[Stmt]) {
walk_stmt(checker, finalbody, |stmt| { walk_stmt(checker, finalbody, |stmt| {
matches!( matches!(
stmt.node, stmt.node,
StmtKind::Break | StmtKind::Continue | StmtKind::Return { .. } StmtKind::Break | StmtKind::Continue | StmtKind::Return(_)
) )
}); });
} }

View file

@ -1,5 +1,5 @@
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -32,18 +32,18 @@ where
{ {
fn visit_expr(&mut self, expr: &'b Expr) { fn visit_expr(&mut self, expr: &'b Expr) {
match &expr.node { match &expr.node {
ExprKind::Name { id, .. } => { ExprKind::Name(ast::ExprName { id, .. }) => {
self.names.insert(id, expr); self.names.insert(id, expr);
} }
ExprKind::ListComp { generators, .. } ExprKind::ListComp(ast::ExprListComp { generators, .. })
| ExprKind::DictComp { generators, .. } | ExprKind::DictComp(ast::ExprDictComp { generators, .. })
| ExprKind::SetComp { generators, .. } | ExprKind::SetComp(ast::ExprSetComp { generators, .. })
| ExprKind::GeneratorExp { generators, .. } => { | ExprKind::GeneratorExp(ast::ExprGeneratorExp { generators, .. }) => {
for comp in generators { for comp in generators {
self.visit_expr(&comp.iter); self.visit_expr(&comp.iter);
} }
} }
ExprKind::Lambda { args, body } => { ExprKind::Lambda(ast::ExprLambda { args, body }) => {
visitor::walk_expr(self, body); visitor::walk_expr(self, body);
for arg in &args.args { for arg in &args.args {
self.names.remove(arg.node.arg.as_str()); self.names.remove(arg.node.arg.as_str());

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Arguments, Expr, ExprKind}; use rustpython_parser::ast::{self, Arguments, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -38,13 +38,13 @@ pub fn is_mutable_func(checker: &Checker, func: &Expr) -> bool {
fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool { fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool {
match &expr.node { match &expr.node {
ExprKind::List { .. } ExprKind::List(_)
| ExprKind::Dict { .. } | ExprKind::Dict(_)
| ExprKind::Set { .. } | ExprKind::Set(_)
| ExprKind::ListComp { .. } | ExprKind::ListComp(_)
| ExprKind::DictComp { .. } | ExprKind::DictComp(_)
| ExprKind::SetComp { .. } => true, | ExprKind::SetComp(_) => true,
ExprKind::Call { func, .. } => is_mutable_func(checker, func), ExprKind::Call(ast::ExprCall { func, .. }) => is_mutable_func(checker, func),
_ => false, _ => false,
} }
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{ExprKind, Stmt}; use rustpython_parser::ast::{self, ExprKind, Stmt};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -33,7 +33,7 @@ pub fn raise_without_from_inside_except(checker: &mut Checker, body: &[Stmt]) {
if cause.is_none() { if cause.is_none() {
if let Some(exc) = exc { if let Some(exc) = exc {
match &exc.node { match &exc.node {
ExprKind::Name { id, .. } if is_lower(id) => {} ExprKind::Name(ast::ExprName { id, .. }) if is_lower(id) => {}
_ => { _ => {
checker checker
.diagnostics .diagnostics

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, ExprKind}; use rustpython_parser::ast::{self, Excepthandler, ExcepthandlerKind, ExprKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -31,10 +31,10 @@ impl AlwaysAutofixableViolation for RedundantTupleInExceptionHandler {
/// B013 /// B013
pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[Excepthandler]) { pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[Excepthandler]) {
for handler in handlers { for handler in handlers {
let ExcepthandlerKind::ExceptHandler { type_: Some(type_), .. } = &handler.node else { let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_: Some(type_), .. }) = &handler.node else {
continue; continue;
}; };
let ExprKind::Tuple { elts, .. } = &type_.node else { let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &type_.node else {
continue; continue;
}; };
let [elt] = &elts[..] else { let [elt] = &elts[..] else {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Comprehension, Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Comprehension, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -84,7 +84,7 @@ impl<'a> GroupNameFinder<'a> {
} }
fn name_matches(&self, expr: &Expr) -> bool { fn name_matches(&self, expr: &Expr) -> bool {
if let ExprKind::Name { id, .. } = &expr.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node {
id == self.group_name id == self.group_name
} else { } else {
false false
@ -113,9 +113,9 @@ where
return; return;
} }
match &stmt.node { match &stmt.node {
StmtKind::For { StmtKind::For(ast::StmtFor {
target, iter, body, .. target, iter, body, ..
} => { }) => {
if self.name_matches(target) { if self.name_matches(target) {
self.overridden = true; self.overridden = true;
} else { } else {
@ -138,15 +138,15 @@ where
self.nested = false; self.nested = false;
} }
} }
StmtKind::While { body, .. } => { StmtKind::While(ast::StmtWhile { body, .. }) => {
self.nested = true; self.nested = true;
visitor::walk_body(self, body); visitor::walk_body(self, body);
self.nested = false; self.nested = false;
} }
StmtKind::If { test, body, orelse } => { StmtKind::If(ast::StmtIf { test, body, orelse }) => {
// Determine whether we're on an `if` arm (as opposed to an `elif`). // Determine whether we're on an `if` arm (as opposed to an `elif`).
let is_if_arm = !self.parent_ifs.iter().any(|parent| { let is_if_arm = !self.parent_ifs.iter().any(|parent| {
if let StmtKind::If { orelse, .. } = &parent.node { if let StmtKind::If(ast::StmtIf { orelse, .. }) = &parent.node {
orelse.len() == 1 && &orelse[0] == stmt orelse.len() == 1 && &orelse[0] == stmt
} else { } else {
false false
@ -166,7 +166,7 @@ where
let has_else = orelse let has_else = orelse
.first() .first()
.map_or(false, |expr| !matches!(expr.node, StmtKind::If { .. })); .map_or(false, |expr| !matches!(expr.node, StmtKind::If(_)));
self.parent_ifs.push(stmt); self.parent_ifs.push(stmt);
if has_else { if has_else {
@ -193,7 +193,7 @@ where
} }
} }
} }
StmtKind::Match { subject, cases } => { StmtKind::Match(ast::StmtMatch { subject, cases }) => {
self.counter_stack.push(Vec::with_capacity(cases.len())); self.counter_stack.push(Vec::with_capacity(cases.len()));
self.visit_expr(subject); self.visit_expr(subject);
for match_case in cases { for match_case in cases {
@ -207,14 +207,14 @@ where
self.increment_usage_count(max_count); self.increment_usage_count(max_count);
} }
} }
StmtKind::Assign { targets, value, .. } => { StmtKind::Assign(ast::StmtAssign { targets, value, .. }) => {
if targets.iter().any(|target| self.name_matches(target)) { if targets.iter().any(|target| self.name_matches(target)) {
self.overridden = true; self.overridden = true;
} else { } else {
self.visit_expr(value); self.visit_expr(value);
} }
} }
StmtKind::AnnAssign { target, value, .. } => { StmtKind::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => {
if self.name_matches(target) { if self.name_matches(target) {
self.overridden = true; self.overridden = true;
} else if let Some(expr) = value { } else if let Some(expr) = value {
@ -241,7 +241,7 @@ where
} }
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
if let ExprKind::NamedExpr { target, .. } = &expr.node { if let ExprKind::NamedExpr(ast::ExprNamedExpr { target, .. }) = &expr.node {
if self.name_matches(target) { if self.name_matches(target) {
self.overridden = true; self.overridden = true;
} }
@ -251,7 +251,8 @@ where
} }
match &expr.node { match &expr.node {
ExprKind::ListComp { elt, generators } | ExprKind::SetComp { elt, generators } => { ExprKind::ListComp(ast::ExprListComp { elt, generators })
| ExprKind::SetComp(ast::ExprSetComp { elt, generators }) => {
for comprehension in generators { for comprehension in generators {
self.visit_comprehension(comprehension); self.visit_comprehension(comprehension);
} }
@ -261,11 +262,11 @@ where
self.nested = false; self.nested = false;
} }
} }
ExprKind::DictComp { ExprKind::DictComp(ast::ExprDictComp {
key, key,
value, value,
generators, generators,
} => { }) => {
for comprehension in generators { for comprehension in generators {
self.visit_comprehension(comprehension); self.visit_comprehension(comprehension);
} }
@ -307,10 +308,10 @@ pub fn reuse_of_groupby_generator(
body: &[Stmt], body: &[Stmt],
iter: &Expr, iter: &Expr,
) { ) {
let ExprKind::Call { func, .. } = &iter.node else { let ExprKind::Call(ast::ExprCall { func, .. }) = &iter.node else {
return; return;
}; };
let ExprKind::Tuple { elts, .. } = &target.node else { let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &target.node else {
// Ignore any `groupby()` invocation that isn't unpacked // Ignore any `groupby()` invocation that isn't unpacked
return; return;
}; };
@ -318,7 +319,7 @@ pub fn reuse_of_groupby_generator(
return; return;
} }
// We have an invocation of groupby which is a simple unpacking // We have an invocation of groupby which is a simple unpacking
let ExprKind::Name { id: group_name, .. } = &elts[1].node else { let ExprKind::Name(ast::ExprName { id: group_name, .. }) = &elts[1].node else {
return; return;
}; };
// Check if the function call is `itertools.groupby` // Check if the function call is `itertools.groupby`

View file

@ -1,5 +1,5 @@
use ruff_text_size::TextSize; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -29,28 +29,26 @@ impl AlwaysAutofixableViolation for SetAttrWithConstant {
fn assignment(obj: &Expr, name: &str, value: &Expr, stylist: &Stylist) -> String { fn assignment(obj: &Expr, name: &str, value: &Expr, stylist: &Stylist) -> String {
let stmt = Stmt::new( let stmt = Stmt::new(
TextSize::default(), TextRange::default(),
TextSize::default(), StmtKind::Assign(ast::StmtAssign {
StmtKind::Assign {
targets: vec![Expr::new( targets: vec![Expr::new(
TextSize::default(), TextRange::default(),
TextSize::default(), ExprKind::Attribute(ast::ExprAttribute {
ExprKind::Attribute {
value: Box::new(obj.clone()), value: Box::new(obj.clone()),
attr: name.to_string(), attr: name.into(),
ctx: ExprContext::Store, ctx: ExprContext::Store,
}, }),
)], )],
value: Box::new(value.clone()), value: Box::new(value.clone()),
type_comment: None, type_comment: None,
}, }),
); );
unparse_stmt(&stmt, stylist) unparse_stmt(&stmt, stylist)
} }
/// B010 /// B010
pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) { pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
let ExprKind::Name { id, .. } = &func.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &func.node else {
return; return;
}; };
if id != "setattr" { if id != "setattr" {
@ -59,10 +57,10 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
let [obj, name, value] = args else { let [obj, name, value] = args else {
return; return;
}; };
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(name), value: Constant::Str(name),
.. ..
} = &name.node else { } )= &name.node else {
return; return;
}; };
if !is_identifier(name) { if !is_identifier(name) {
@ -74,7 +72,7 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
// We can only replace a `setattr` call (which is an `Expr`) with an assignment // We can only replace a `setattr` call (which is an `Expr`) with an assignment
// (which is a `Stmt`) if the `Expr` is already being used as a `Stmt` // (which is a `Stmt`) if the `Expr` is already being used as a `Stmt`
// (i.e., it's directly within an `StmtKind::Expr`). // (i.e., it's directly within an `StmtKind::Expr`).
if let StmtKind::Expr { value: child } = &checker.ctx.stmt().node { if let StmtKind::Expr(ast::StmtExpr { value: child }) = &checker.ctx.stmt().node {
if expr == child.as_ref() { if expr == child.as_ref() {
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range()); let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());

View file

@ -34,7 +34,7 @@ pub fn star_arg_unpacking_after_keyword_arg(
return; return;
}; };
for arg in args { for arg in args {
let ExprKind::Starred { .. } = arg.node else { let ExprKind::Starred (_) = arg.node else {
continue; continue;
}; };
if arg.start() <= keyword.start() { if arg.start() <= keyword.start() {

View file

@ -1,5 +1,5 @@
use itertools::Itertools; use itertools::Itertools;
use rustpython_parser::ast::{Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -18,7 +18,7 @@ impl Violation for StripWithMultiCharacters {
/// B005 /// B005
pub fn strip_with_multi_characters(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) { pub fn strip_with_multi_characters(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
let ExprKind::Attribute { attr, .. } = &func.node else { let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &func.node else {
return; return;
}; };
if !matches!(attr.as_str(), "strip" | "lstrip" | "rstrip") { if !matches!(attr.as_str(), "strip" | "lstrip" | "rstrip") {
@ -28,10 +28,10 @@ pub fn strip_with_multi_characters(checker: &mut Checker, expr: &Expr, func: &Ex
return; return;
} }
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(value), value: Constant::Str(value),
.. ..
} = &args[0].node else { } )= &args[0].node else {
return; return;
}; };

View file

@ -17,7 +17,7 @@
//! n += 1 //! n += 1
//! ``` //! ```
use rustpython_parser::ast::{Expr, ExprKind, Unaryop}; use rustpython_parser::ast::{self, Expr, ExprKind, Unaryop};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -39,7 +39,7 @@ pub fn unary_prefix_increment(checker: &mut Checker, expr: &Expr, op: &Unaryop,
if !matches!(op, Unaryop::UAdd) { if !matches!(op, Unaryop::UAdd) {
return; return;
} }
let ExprKind::UnaryOp { op, .. } = &operand.node else { let ExprKind::UnaryOp(ast::ExprUnaryOp { op, .. })= &operand.node else {
return; return;
}; };
if !matches!(op, Unaryop::UAdd) { if !matches!(op, Unaryop::UAdd) {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Stmt}; use rustpython_parser::ast::{self, Expr, ExprKind, Stmt};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -44,15 +44,15 @@ pub fn unintentional_type_annotation(
return; return;
} }
match &target.node { match &target.node {
ExprKind::Subscript { value, .. } => { ExprKind::Subscript(ast::ExprSubscript { value, .. }) => {
if matches!(&value.node, ExprKind::Name { .. }) { if matches!(&value.node, ExprKind::Name(_)) {
checker checker
.diagnostics .diagnostics
.push(Diagnostic::new(UnintentionalTypeAnnotation, stmt.range())); .push(Diagnostic::new(UnintentionalTypeAnnotation, stmt.range()));
} }
} }
ExprKind::Attribute { value, .. } => { ExprKind::Attribute(ast::ExprAttribute { value, .. }) => {
if let ExprKind::Name { id, .. } = &value.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &value.node {
if id != "self" { if id != "self" {
checker checker
.diagnostics .diagnostics

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -20,7 +20,7 @@ impl Violation for UnreliableCallableCheck {
/// B004 /// B004
pub fn unreliable_callable_check(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) { pub fn unreliable_callable_check(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
let ExprKind::Name { id, .. } = &func.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &func.node else {
return; return;
}; };
if id != "getattr" && id != "hasattr" { if id != "getattr" && id != "hasattr" {
@ -29,10 +29,10 @@ pub fn unreliable_callable_check(checker: &mut Checker, expr: &Expr, func: &Expr
if args.len() < 2 { if args.len() < 2 {
return; return;
}; };
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(s), value: Constant::Str(s),
.. ..
} = &args[1].node else }) = &args[1].node else
{ {
return; return;
}; };

View file

@ -19,7 +19,7 @@
//! ``` //! ```
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use rustpython_parser::ast::{Expr, ExprKind, Stmt}; use rustpython_parser::ast::{self, Expr, ExprKind, Stmt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
@ -93,7 +93,7 @@ where
'b: 'a, 'b: 'a,
{ {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
if let ExprKind::Name { id, .. } = &expr.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node {
self.names.insert(id, expr); self.names.insert(id, expr);
} }
visitor::walk_expr(self, expr); visitor::walk_expr(self, expr);

View file

@ -20,7 +20,7 @@ impl Violation for UselessComparison {
/// B015 /// B015
pub fn useless_comparison(checker: &mut Checker, expr: &Expr) { pub fn useless_comparison(checker: &mut Checker, expr: &Expr) {
if matches!(expr.node, ExprKind::Compare { .. }) { if matches!(expr.node, ExprKind::Compare(_)) {
checker checker
.diagnostics .diagnostics
.push(Diagnostic::new(UselessComparison, expr.range())); .push(Diagnostic::new(UselessComparison, expr.range()));

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -36,18 +36,18 @@ impl Violation for UselessExpression {
/// B018 /// B018
pub fn useless_expression(checker: &mut Checker, value: &Expr) { pub fn useless_expression(checker: &mut Checker, value: &Expr) {
// Ignore comparisons, as they're handled by `useless_comparison`. // Ignore comparisons, as they're handled by `useless_comparison`.
if matches!(value.node, ExprKind::Compare { .. }) { if matches!(value.node, ExprKind::Compare(_)) {
return; return;
} }
// Ignore strings, to avoid false positives with docstrings. // Ignore strings, to avoid false positives with docstrings.
if matches!( if matches!(
value.node, value.node,
ExprKind::JoinedStr { .. } ExprKind::JoinedStr(_)
| ExprKind::Constant { | ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(..) | Constant::Ellipsis, value: Constant::Str(..) | Constant::Ellipsis,
.. ..
} })
) { ) {
return; return;
} }
@ -56,7 +56,7 @@ pub fn useless_expression(checker: &mut Checker, value: &Expr) {
if contains_effect(value, |id| checker.ctx.is_builtin(id)) { if contains_effect(value, |id| checker.ctx.is_builtin(id)) {
// Flag attributes as useless expressions, even if they're attached to calls or other // Flag attributes as useless expressions, even if they're attached to calls or other
// expressions. // expressions.
if matches!(value.node, ExprKind::Attribute { .. }) { if matches!(value.node, ExprKind::Attribute(_)) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
UselessExpression { UselessExpression {
kind: Kind::Attribute, kind: Kind::Attribute,

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
@ -21,7 +21,7 @@ pub fn zip_without_explicit_strict(
func: &Expr, func: &Expr,
kwargs: &[Keyword], kwargs: &[Keyword],
) { ) {
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
if id == "zip" if id == "zip"
&& checker.ctx.is_builtin("zip") && checker.ctx.is_builtin("zip")
&& !kwargs.iter().any(|keyword| { && !kwargs.iter().any(|keyword| {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::Located; use rustpython_parser::ast::Attributed;
use ruff_diagnostics::Violation; use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_diagnostics::{Diagnostic, DiagnosticKind};
@ -170,7 +170,7 @@ impl Violation for BuiltinAttributeShadowing {
/// Check builtin name shadowing. /// Check builtin name shadowing.
pub fn builtin_shadowing<T>( pub fn builtin_shadowing<T>(
name: &str, name: &str,
located: &Located<T>, located: &Attributed<T>,
node_type: ShadowingType, node_type: ShadowingType,
ignorelist: &[String], ignorelist: &[String],
) -> Option<Diagnostic> { ) -> Option<Diagnostic> {

View file

@ -116,7 +116,7 @@ pub fn fix_unnecessary_generator_set(
// If the expression is embedded in an f-string, surround it with spaces to avoid // If the expression is embedded in an f-string, surround it with spaces to avoid
// syntax errors. // syntax errors.
if let Some(parent_element) = parent { if let Some(parent_element) = parent {
if let &rustpython_parser::ast::ExprKind::FormattedValue { .. } = &parent_element.node { if let &rustpython_parser::ast::ExprKind::FormattedValue(_) = &parent_element.node {
content = format!(" {content} "); content = format!(" {content} ");
} }
} }
@ -186,7 +186,7 @@ pub fn fix_unnecessary_generator_dict(
// If the expression is embedded in an f-string, surround it with spaces to avoid // If the expression is embedded in an f-string, surround it with spaces to avoid
// syntax errors. // syntax errors.
if let Some(parent_element) = parent { if let Some(parent_element) = parent {
if let &rustpython_parser::ast::ExprKind::FormattedValue { .. } = &parent_element.node { if let &rustpython_parser::ast::ExprKind::FormattedValue(_) = &parent_element.node {
content = format!(" {content} "); content = format!(" {content} ");
} }
} }
@ -1101,9 +1101,7 @@ pub fn fix_unnecessary_map(
// syntax errors. // syntax errors.
if kind == "set" || kind == "dict" { if kind == "set" || kind == "dict" {
if let Some(parent_element) = parent { if let Some(parent_element) = parent {
if let &rustpython_parser::ast::ExprKind::FormattedValue { .. } = if let &rustpython_parser::ast::ExprKind::FormattedValue(_) = &parent_element.node {
&parent_element.node
{
content = format!(" {content} "); content = format!(" {content} ");
} }
} }

View file

@ -1,7 +1,7 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
pub fn expr_name(func: &Expr) -> Option<&str> { pub fn expr_name(func: &Expr) -> Option<&str> {
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
Some(id) Some(id)
} else { } else {
None None

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::registry::AsRule; use crate::registry::AsRule;
@ -65,7 +65,7 @@ pub fn unnecessary_call_around_sorted(
let Some(arg) = args.first() else { let Some(arg) = args.first() else {
return; return;
}; };
let ExprKind::Call { func, .. } = &arg.node else { let ExprKind::Call(ast::ExprCall { func, .. }) = &arg.node else {
return; return;
}; };
let Some(inner) = helpers::expr_name(func) else { let Some(inner) = helpers::expr_name(func) else {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Comprehension, Expr, ExprKind}; use rustpython_parser::ast::{self, Comprehension, Expr, ExprKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -51,9 +51,9 @@ impl AlwaysAutofixableViolation for UnnecessaryComprehension {
/// Add diagnostic for C416 based on the expression node id. /// Add diagnostic for C416 based on the expression node id.
fn add_diagnostic(checker: &mut Checker, expr: &Expr) { fn add_diagnostic(checker: &mut Checker, expr: &Expr) {
let id = match &expr.node { let id = match &expr.node {
ExprKind::ListComp { .. } => "list", ExprKind::ListComp(_) => "list",
ExprKind::SetComp { .. } => "set", ExprKind::SetComp(_) => "set",
ExprKind::DictComp { .. } => "dict", ExprKind::DictComp(_) => "dict",
_ => return, _ => return,
}; };
if !checker.ctx.is_builtin(id) { if !checker.ctx.is_builtin(id) {
@ -86,7 +86,7 @@ pub fn unnecessary_dict_comprehension(
return; return;
} }
let generator = &generators[0]; let generator = &generators[0];
if !(generator.ifs.is_empty() && generator.is_async == 0) { if !generator.ifs.is_empty() || generator.is_async {
return; return;
} }
let Some(key_id) = helpers::expr_name(key) else { let Some(key_id) = helpers::expr_name(key) else {
@ -95,7 +95,7 @@ pub fn unnecessary_dict_comprehension(
let Some(value_id) = helpers::expr_name(value) else { let Some(value_id) = helpers::expr_name(value) else {
return; return;
}; };
let ExprKind::Tuple { elts, .. } = &generator.target.node else { let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &generator.target.node else {
return; return;
}; };
if elts.len() != 2 { if elts.len() != 2 {
@ -127,7 +127,7 @@ pub fn unnecessary_list_set_comprehension(
return; return;
} }
let generator = &generators[0]; let generator = &generators[0];
if !(generator.ifs.is_empty() && generator.is_async == 0) { if !generator.ifs.is_empty() || generator.is_async {
return; return;
} }
let Some(elt_id) = helpers::expr_name(elt) else { let Some(elt_id) = helpers::expr_name(elt) else {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use ruff_diagnostics::Violation; use ruff_diagnostics::Violation;
use ruff_diagnostics::{AutofixKind, Diagnostic}; use ruff_diagnostics::{AutofixKind, Diagnostic};
@ -66,11 +66,11 @@ pub fn unnecessary_comprehension_any_all(
if !keywords.is_empty() { if !keywords.is_empty() {
return; return;
} }
let ExprKind::Name { id, .. } = &func.node else { let ExprKind::Name(ast::ExprName { id, .. } )= &func.node else {
return; return;
}; };
if (matches!(id.as_str(), "all" | "any")) && args.len() == 1 { if (matches!(id.as_str(), "all" | "any")) && args.len() == 1 {
let (ExprKind::ListComp { elt, .. } | ExprKind::SetComp { elt, .. }) = &args[0].node else { let (ExprKind::ListComp(ast::ExprListComp { elt, .. } )| ExprKind::SetComp(ast::ExprSetComp { elt, .. })) = &args[0].node else {
return; return;
}; };
if is_async_generator(elt) { if is_async_generator(elt) {
@ -92,5 +92,5 @@ pub fn unnecessary_comprehension_any_all(
/// Return `true` if the `Expr` contains an `await` expression. /// Return `true` if the `Expr` contains an `await` expression.
fn is_async_generator(expr: &Expr) -> bool { fn is_async_generator(expr: &Expr) -> bool {
any_over_expr(expr, &|expr| matches!(expr.node, ExprKind::Await { .. })) any_over_expr(expr, &|expr| matches!(expr.node, ExprKind::Await(_)))
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -84,7 +84,7 @@ pub fn unnecessary_double_cast_or_process(
let Some(arg) = args.first() else { let Some(arg) = args.first() else {
return; return;
}; };
let ExprKind::Call { func, ..} = &arg.node else { let ExprKind::Call(ast::ExprCall { func, ..} )= &arg.node else {
return; return;
}; };
let Some(inner) = helpers::expr_name(func) else { let Some(inner) = helpers::expr_name(func) else {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -53,9 +53,9 @@ pub fn unnecessary_generator_dict(
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else { let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
return; return;
}; };
if let ExprKind::GeneratorExp { elt, .. } = argument { if let ExprKind::GeneratorExp(ast::ExprGeneratorExp { elt, .. }) = argument {
match &elt.node { match &elt.node {
ExprKind::Tuple { elts, .. } if elts.len() == 2 => { ExprKind::Tuple(ast::ExprTuple { elts, .. }) if elts.len() == 2 => {
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range()); let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)] #[allow(deprecated)]

View file

@ -55,7 +55,7 @@ pub fn unnecessary_generator_list(
if !checker.ctx.is_builtin("list") { if !checker.ctx.is_builtin("list") {
return; return;
} }
if let ExprKind::GeneratorExp { .. } = argument { if let ExprKind::GeneratorExp(_) = argument {
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, expr.range()); let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)] #[allow(deprecated)]

View file

@ -56,7 +56,7 @@ pub fn unnecessary_generator_set(
if !checker.ctx.is_builtin("set") { if !checker.ctx.is_builtin("set") {
return; return;
} }
if let ExprKind::GeneratorExp { .. } = argument { if let ExprKind::GeneratorExp(_) = argument {
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range()); let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)] #[allow(deprecated)]

View file

@ -45,7 +45,7 @@ pub fn unnecessary_list_call(checker: &mut Checker, expr: &Expr, func: &Expr, ar
if !checker.ctx.is_builtin("list") { if !checker.ctx.is_builtin("list") {
return; return;
} }
if !matches!(argument, ExprKind::ListComp { .. }) { if !matches!(argument, ExprKind::ListComp(_)) {
return; return;
} }
let mut diagnostic = Diagnostic::new(UnnecessaryListCall, expr.range()); let mut diagnostic = Diagnostic::new(UnnecessaryListCall, expr.range());

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::registry::AsRule; use crate::registry::AsRule;
@ -52,10 +52,10 @@ pub fn unnecessary_list_comprehension_dict(
if !checker.ctx.is_builtin("dict") { if !checker.ctx.is_builtin("dict") {
return; return;
} }
let ExprKind::ListComp { elt, .. } = &argument else { let ExprKind::ListComp(ast::ExprListComp { elt, .. }) = &argument else {
return; return;
}; };
let ExprKind::Tuple { elts, .. } = &elt.node else { let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &elt.node else {
return; return;
}; };
if elts.len() != 2 { if elts.len() != 2 {

View file

@ -53,7 +53,7 @@ pub fn unnecessary_list_comprehension_set(
if !checker.ctx.is_builtin("set") { if !checker.ctx.is_builtin("set") {
return; return;
} }
if let ExprKind::ListComp { .. } = &argument { if let ExprKind::ListComp(_) = &argument {
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, expr.range()); let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)] #[allow(deprecated)]

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::registry::AsRule; use crate::registry::AsRule;
@ -60,15 +60,14 @@ pub fn unnecessary_literal_dict(
return; return;
} }
let (kind, elts) = match argument { let (kind, elts) = match argument {
ExprKind::Tuple { elts, .. } => ("tuple", elts), ExprKind::Tuple(ast::ExprTuple { elts, .. }) => ("tuple", elts),
ExprKind::List { elts, .. } => ("list", elts), ExprKind::List(ast::ExprList { elts, .. }) => ("list", elts),
_ => return, _ => return,
}; };
// Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`. // Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`.
if !elts if !elts.iter().all(
.iter() |elt| matches!(&elt.node, ExprKind::Tuple(ast::ExprTuple { elts, .. } )if elts.len() == 2),
.all(|elt| matches!(&elt.node, ExprKind::Tuple { elts, .. } if elts.len() == 2)) ) {
{
return; return;
} }
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(

View file

@ -61,8 +61,8 @@ pub fn unnecessary_literal_set(
return; return;
} }
let kind = match argument { let kind = match argument {
ExprKind::List { .. } => "list", ExprKind::List(_) => "list",
ExprKind::Tuple { .. } => "tuple", ExprKind::Tuple(_) => "tuple",
_ => return, _ => return,
}; };
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(

View file

@ -79,8 +79,8 @@ pub fn unnecessary_literal_within_dict_call(
return; return;
} }
let argument_kind = match argument { let argument_kind = match argument {
ExprKind::DictComp { .. } => DictKind::Comprehension, ExprKind::DictComp(_) => DictKind::Comprehension,
ExprKind::Dict { .. } => DictKind::Literal, ExprKind::Dict(_) => DictKind::Literal,
_ => return, _ => return,
}; };
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(

View file

@ -82,8 +82,8 @@ pub fn unnecessary_literal_within_list_call(
return; return;
} }
let argument_kind = match argument { let argument_kind = match argument {
ExprKind::Tuple { .. } => "tuple", ExprKind::Tuple(_) => "tuple",
ExprKind::List { .. } => "list", ExprKind::List(_) => "list",
_ => return, _ => return,
}; };
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(

View file

@ -83,8 +83,8 @@ pub fn unnecessary_literal_within_tuple_call(
return; return;
} }
let argument_kind = match argument { let argument_kind = match argument {
ExprKind::Tuple { .. } => "tuple", ExprKind::Tuple(_) => "tuple",
ExprKind::List { .. } => "list", ExprKind::List(_) => "list",
_ => return, _ => return,
}; };
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(

View file

@ -1,5 +1,5 @@
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::{AutofixKind, Violation}; use ruff_diagnostics::{AutofixKind, Violation};
@ -94,7 +94,7 @@ pub fn unnecessary_map(
// Exclude the parent if already matched by other arms // Exclude the parent if already matched by other arms
if let Some(parent) = parent { if let Some(parent) = parent {
if let ExprKind::Call { func: f, .. } = &parent.node { if let ExprKind::Call(ast::ExprCall { func: f, .. }) = &parent.node {
if let Some(id_parent) = helpers::expr_name(f) { if let Some(id_parent) = helpers::expr_name(f) {
if id_parent == "dict" || id_parent == "set" || id_parent == "list" { if id_parent == "dict" || id_parent == "set" || id_parent == "list" {
return; return;
@ -103,7 +103,7 @@ pub fn unnecessary_map(
}; };
}; };
if args.len() == 2 && matches!(&args[0].node, ExprKind::Lambda { .. }) { if args.len() == 2 && matches!(&args[0].node, ExprKind::Lambda(_)) {
let mut diagnostic = create_diagnostic("generator", expr.range()); let mut diagnostic = create_diagnostic("generator", expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)] #[allow(deprecated)]
@ -126,14 +126,14 @@ pub fn unnecessary_map(
} }
if let Some(arg) = args.first() { if let Some(arg) = args.first() {
if let ExprKind::Call { func, args, .. } = &arg.node { if let ExprKind::Call(ast::ExprCall { func, args, .. }) = &arg.node {
if args.len() != 2 { if args.len() != 2 {
return; return;
} }
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else { let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else {
return; return;
}; };
if let ExprKind::Lambda { .. } = argument { if let ExprKind::Lambda(_) = argument {
let mut diagnostic = create_diagnostic(id, expr.range()); let mut diagnostic = create_diagnostic(id, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)] #[allow(deprecated)]
@ -158,12 +158,12 @@ pub fn unnecessary_map(
} }
if args.len() == 1 { if args.len() == 1 {
if let ExprKind::Call { func, args, .. } = &args[0].node { if let ExprKind::Call(ast::ExprCall { func, args, .. }) = &args[0].node {
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else { let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else {
return; return;
}; };
if let ExprKind::Lambda { body, .. } = &argument { if let ExprKind::Lambda(ast::ExprLambda { body, .. }) = &argument {
if matches!(&body.node, ExprKind::Tuple { elts, .. } | ExprKind::List { elts, .. } if elts.len() == 2) if matches!(&body.node, ExprKind::Tuple(ast::ExprTuple { elts, .. }) | ExprKind::List(ast::ExprList { elts, .. } )if elts.len() == 2)
{ {
let mut diagnostic = create_diagnostic(id, expr.range()); let mut diagnostic = create_diagnostic(id, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {

View file

@ -1,5 +1,5 @@
use num_bigint::BigInt; use num_bigint::BigInt;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Unaryop}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Unaryop};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
@ -60,10 +60,10 @@ pub fn unnecessary_subscript_reversal(
if !checker.ctx.is_builtin(id) { if !checker.ctx.is_builtin(id) {
return; return;
} }
let ExprKind::Subscript { slice, .. } = &first_arg.node else { let ExprKind::Subscript(ast::ExprSubscript { slice, .. }) = &first_arg.node else {
return; return;
}; };
let ExprKind::Slice { lower, upper, step } = &slice.node else { let ExprKind::Slice(ast::ExprSlice { lower, upper, step }) = &slice.node else {
return; return;
}; };
if lower.is_some() || upper.is_some() { if lower.is_some() || upper.is_some() {
@ -72,16 +72,16 @@ pub fn unnecessary_subscript_reversal(
let Some(step) = step.as_ref() else { let Some(step) = step.as_ref() else {
return; return;
}; };
let ExprKind::UnaryOp { let ExprKind::UnaryOp(ast::ExprUnaryOp {
op: Unaryop::USub, op: Unaryop::USub,
operand, operand,
} = &step.node else { }) = &step.node else {
return; return;
}; };
let ExprKind::Constant { let ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(val), value: Constant::Int(val),
.. ..
} = &operand.node else { }) = &operand.node else {
return; return;
}; };
if *val != BigInt::from(1) { if *val != BigInt::from(1) {

View file

@ -1,5 +1,5 @@
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -317,10 +317,10 @@ pub fn call_datetime_strptime_without_zone(
} }
// Does the `strptime` call contain a format string with a timezone specifier? // Does the `strptime` call contain a format string with a timezone specifier?
if let Some(ExprKind::Constant { if let Some(ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(format), value: Constant::Str(format),
kind: None, kind: None,
}) = args.get(1).as_ref().map(|arg| &arg.node) })) = args.get(1).as_ref().map(|arg| &arg.node)
{ {
if format.contains("%z") { if format.contains("%z") {
return; return;
@ -335,8 +335,9 @@ pub fn call_datetime_strptime_without_zone(
return; return;
}; };
if let ExprKind::Call { keywords, .. } = &grandparent.node { if let ExprKind::Call(ast::ExprCall { keywords, .. }) = &grandparent.node {
if let ExprKind::Attribute { attr, .. } = &parent.node { if let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &parent.node {
let attr = attr.as_str();
// Ex) `datetime.strptime(...).astimezone()` // Ex) `datetime.strptime(...).astimezone()`
if attr == "astimezone" { if attr == "astimezone" {
return; return;

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -52,24 +52,24 @@ pub fn all_with_model_form(checker: &Checker, bases: &[Expr], body: &[Stmt]) ->
return None; return None;
} }
for element in body.iter() { for element in body.iter() {
let StmtKind::ClassDef { name, body, .. } = &element.node else { let StmtKind::ClassDef(ast::StmtClassDef { name, body, .. }) = &element.node else {
continue; continue;
}; };
if name != "Meta" { if name != "Meta" {
continue; continue;
} }
for element in body.iter() { for element in body.iter() {
let StmtKind::Assign { targets, value, .. } = &element.node else { let StmtKind::Assign(ast::StmtAssign { targets, value, .. }) = &element.node else {
continue; continue;
}; };
for target in targets.iter() { for target in targets.iter() {
let ExprKind::Name { id, .. } = &target.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &target.node else {
continue; continue;
}; };
if id != "fields" { if id != "fields" {
continue; continue;
} }
let ExprKind::Constant { value, .. } = &value.node else { let ExprKind::Constant(ast::ExprConstant { value, .. }) = &value.node else {
continue; continue;
}; };
match &value { match &value {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -54,18 +54,18 @@ pub fn exclude_with_model_form(
return None; return None;
} }
for element in body.iter() { for element in body.iter() {
let StmtKind::ClassDef { name, body, .. } = &element.node else { let StmtKind::ClassDef(ast::StmtClassDef { name, body, .. }) = &element.node else {
continue; continue;
}; };
if name != "Meta" { if name != "Meta" {
continue; continue;
} }
for element in body.iter() { for element in body.iter() {
let StmtKind::Assign { targets, .. } = &element.node else { let StmtKind::Assign(ast::StmtAssign { targets, .. }) = &element.node else {
continue; continue;
}; };
for target in targets.iter() { for target in targets.iter() {
let ExprKind::Name { id, .. } = &target.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &target.node else {
continue; continue;
}; };
if id == "exclude" { if id == "exclude" {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -86,7 +86,7 @@ pub fn locals_in_render_function(
} }
fn is_locals_call(checker: &Checker, expr: &Expr) -> bool { fn is_locals_call(checker: &Checker, expr: &Expr) -> bool {
let ExprKind::Call { func, .. } = &expr.node else { let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node else {
return false return false
}; };
checker checker

View file

@ -1,5 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt, StmtKind};
use rustpython_parser::ast::{ExprKind, Stmt};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -70,7 +69,7 @@ pub fn model_without_dunder_str(
fn has_dunder_method(body: &[Stmt]) -> bool { fn has_dunder_method(body: &[Stmt]) -> bool {
body.iter().any(|val| match &val.node { body.iter().any(|val| match &val.node {
StmtKind::FunctionDef { name, .. } => { StmtKind::FunctionDef(ast::StmtFunctionDef { name, .. }) => {
if name == "__str__" { if name == "__str__" {
return true; return true;
} }
@ -95,24 +94,24 @@ fn checker_applies(checker: &Checker, bases: &[Expr], body: &[Stmt]) -> bool {
/// Check if class is abstract, in terms of Django model inheritance. /// Check if class is abstract, in terms of Django model inheritance.
fn is_model_abstract(body: &[Stmt]) -> bool { fn is_model_abstract(body: &[Stmt]) -> bool {
for element in body.iter() { for element in body.iter() {
let StmtKind::ClassDef {name, body, ..} = &element.node else { let StmtKind::ClassDef(ast::StmtClassDef {name, body, ..}) = &element.node else {
continue continue
}; };
if name != "Meta" { if name != "Meta" {
continue; continue;
} }
for element in body.iter() { for element in body.iter() {
let StmtKind::Assign {targets, value, ..} = &element.node else { let StmtKind::Assign(ast::StmtAssign {targets, value, ..}) = &element.node else {
continue; continue;
}; };
for target in targets.iter() { for target in targets.iter() {
let ExprKind::Name {id , ..} = &target.node else { let ExprKind::Name(ast::ExprName {id , ..}) = &target.node else {
continue; continue;
}; };
if id != "abstract" { if id != "abstract" {
continue; continue;
} }
let ExprKind::Constant{value: Constant::Bool(true), ..} = &value.node else { let ExprKind::Constant(ast::ExprConstant{value: Constant::Bool(true), ..}) = &value.node else {
continue; continue;
}; };
return true; return true;

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -59,9 +59,10 @@ where
let mut seen_receiver = false; let mut seen_receiver = false;
for (i, decorator) in decorator_list.iter().enumerate() { for (i, decorator) in decorator_list.iter().enumerate() {
let is_receiver = match &decorator.node { let is_receiver = match &decorator.node {
ExprKind::Call { func, .. } => resolve_call_path(func).map_or(false, |call_path| { ExprKind::Call(ast::ExprCall { func, .. }) => resolve_call_path(func)
call_path.as_slice() == ["django", "dispatch", "receiver"] .map_or(false, |call_path| {
}), call_path.as_slice() == ["django", "dispatch", "receiver"]
}),
_ => false, _ => false,
}; };
if i > 0 && is_receiver && !seen_receiver { if i > 0 && is_receiver && !seen_receiver {

View file

@ -1,5 +1,5 @@
use rustpython_parser::ast::Constant::Bool; use rustpython_parser::ast::Constant::Bool;
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -64,7 +64,7 @@ const NOT_NULL_TRUE_FIELDS: [&str; 6] = [
pub fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> Vec<Diagnostic> { pub fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> Vec<Diagnostic> {
let mut errors = Vec::new(); let mut errors = Vec::new();
for statement in body.iter() { for statement in body.iter() {
let StmtKind::Assign {value, ..} = &statement.node else { let StmtKind::Assign(ast::StmtAssign {value, ..}) = &statement.node else {
continue continue
}; };
if let Some(field_name) = is_nullable_field(checker, value) { if let Some(field_name) = is_nullable_field(checker, value) {
@ -80,7 +80,7 @@ pub fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> Vec<Diag
} }
fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> { fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
let ExprKind::Call {func, keywords, ..} = &value.node else { let ExprKind::Call(ast::ExprCall {func, keywords, ..}) = &value.node else {
return None; return None;
}; };
@ -96,7 +96,7 @@ fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a st
let mut blank_key = false; let mut blank_key = false;
let mut unique_key = false; let mut unique_key = false;
for keyword in keywords.iter() { for keyword in keywords.iter() {
let ExprKind::Constant {value: Bool(true), ..} = &keyword.node.value.node else { let ExprKind::Constant(ast::ExprConstant {value: Bool(true), ..}) = &keyword.node.value.node else {
continue continue
}; };
let Some(argument) = &keyword.node.arg else { let Some(argument) = &keyword.node.arg else {

View file

@ -1,6 +1,6 @@
use std::fmt; use std::fmt;
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -101,8 +101,8 @@ impl fmt::Display for ContentType {
fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType> { fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType> {
match element { match element {
StmtKind::Assign { targets, value, .. } => { StmtKind::Assign(ast::StmtAssign { targets, value, .. }) => {
if let ExprKind::Call { func, .. } = &value.node { if let ExprKind::Call(ast::ExprCall { func, .. }) = &value.node {
if helpers::is_model_field(&checker.ctx, func) { if helpers::is_model_field(&checker.ctx, func) {
return Some(ContentType::FieldDeclaration); return Some(ContentType::FieldDeclaration);
} }
@ -110,7 +110,7 @@ fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType
let Some(expr) = targets.first() else { let Some(expr) = targets.first() else {
return None; return None;
}; };
let ExprKind::Name { id, .. } = &expr.node else { let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node else {
return None; return None;
}; };
if id == "objects" { if id == "objects" {
@ -119,14 +119,14 @@ fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType
None None
} }
} }
StmtKind::ClassDef { name, .. } => { StmtKind::ClassDef(ast::StmtClassDef { name, .. }) => {
if name == "Meta" { if name == "Meta" {
Some(ContentType::MetaClass) Some(ContentType::MetaClass)
} else { } else {
None None
} }
} }
StmtKind::FunctionDef { name, .. } => match name.as_str() { StmtKind::FunctionDef(ast::StmtFunctionDef { name, .. }) => match name.as_str() {
"__str__" => Some(ContentType::StrMethod), "__str__" => Some(ContentType::StrMethod),
"save" => Some(ContentType::SaveMethod), "save" => Some(ContentType::SaveMethod),
"get_absolute_url" => Some(ContentType::GetAbsoluteUrlMethod), "get_absolute_url" => Some(ContentType::GetAbsoluteUrlMethod),

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -184,14 +184,14 @@ impl Violation for DotFormatInException {
/// 2. Replace the exception argument with the variable name. /// 2. Replace the exception argument with the variable name.
fn generate_fix(stylist: &Stylist, stmt: &Stmt, exc_arg: &Expr, indentation: &str) -> Fix { fn generate_fix(stylist: &Stylist, stmt: &Stmt, exc_arg: &Expr, indentation: &str) -> Fix {
let assignment = unparse_stmt( let assignment = unparse_stmt(
&create_stmt(StmtKind::Assign { &create_stmt(StmtKind::Assign(ast::StmtAssign {
targets: vec![create_expr(ExprKind::Name { targets: vec![create_expr(ExprKind::Name(ast::ExprName {
id: String::from("msg"), id: "msg".into(),
ctx: ExprContext::Store, ctx: ExprContext::Store,
})], }))],
value: Box::new(exc_arg.clone()), value: Box::new(exc_arg.clone()),
type_comment: None, type_comment: None,
}), })),
stylist, stylist,
); );
#[allow(deprecated)] #[allow(deprecated)]
@ -214,14 +214,14 @@ fn generate_fix(stylist: &Stylist, stmt: &Stmt, exc_arg: &Expr, indentation: &st
/// EM101, EM102, EM103 /// EM101, EM102, EM103
pub fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) { pub fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
if let ExprKind::Call { args, .. } = &exc.node { if let ExprKind::Call(ast::ExprCall { args, .. }) = &exc.node {
if let Some(first) = args.first() { if let Some(first) = args.first() {
match &first.node { match &first.node {
// Check for string literals // Check for string literals
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(string), value: Constant::Str(string),
.. ..
} => { }) => {
if checker.settings.rules.enabled(Rule::RawStringInException) { if checker.settings.rules.enabled(Rule::RawStringInException) {
if string.len() > checker.settings.flake8_errmsg.max_string_length { if string.len() > checker.settings.flake8_errmsg.max_string_length {
let indentation = whitespace::indentation(checker.locator, stmt) let indentation = whitespace::indentation(checker.locator, stmt)
@ -249,7 +249,7 @@ pub fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
} }
} }
// Check for f-strings // Check for f-strings
ExprKind::JoinedStr { .. } => { ExprKind::JoinedStr(_) => {
if checker.settings.rules.enabled(Rule::FStringInException) { if checker.settings.rules.enabled(Rule::FStringInException) {
let indentation = whitespace::indentation(checker.locator, stmt).and_then( let indentation = whitespace::indentation(checker.locator, stmt).and_then(
|indentation| { |indentation| {
@ -275,10 +275,12 @@ pub fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
} }
} }
// Check for .format() calls // Check for .format() calls
ExprKind::Call { func, .. } => { ExprKind::Call(ast::ExprCall { func, .. }) => {
if checker.settings.rules.enabled(Rule::DotFormatInException) { if checker.settings.rules.enabled(Rule::DotFormatInException) {
if let ExprKind::Attribute { value, attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) =
if attr == "format" && matches!(value.node, ExprKind::Constant { .. }) { &func.node
{
if attr == "format" && matches!(value.node, ExprKind::Constant(_)) {
let indentation = whitespace::indentation(checker.locator, stmt) let indentation = whitespace::indentation(checker.locator, stmt)
.and_then(|indentation| { .and_then(|indentation| {
if checker.ctx.find_binding("msg").is_none() { if checker.ctx.find_binding("msg").is_none() {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Operator}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Operator};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -34,8 +34,8 @@ impl Violation for PrintfInGetTextFuncCall {
/// Returns true if the [`Expr`] is an internationalization function call. /// Returns true if the [`Expr`] is an internationalization function call.
pub fn is_gettext_func_call(func: &Expr, functions_names: &[String]) -> bool { pub fn is_gettext_func_call(func: &Expr, functions_names: &[String]) -> bool {
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
functions_names.contains(id) functions_names.contains(id.as_ref())
} else { } else {
false false
} }
@ -44,7 +44,7 @@ pub fn is_gettext_func_call(func: &Expr, functions_names: &[String]) -> bool {
/// INT001 /// INT001
pub fn f_string_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> { pub fn f_string_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
if let Some(first) = args.first() { if let Some(first) = args.first() {
if matches!(first.node, ExprKind::JoinedStr { .. }) { if matches!(first.node, ExprKind::JoinedStr(_)) {
return Some(Diagnostic::new(FStringInGetTextFuncCall {}, first.range())); return Some(Diagnostic::new(FStringInGetTextFuncCall {}, first.range()));
} }
} }
@ -54,8 +54,8 @@ pub fn f_string_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
/// INT002 /// INT002
pub fn format_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> { pub fn format_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
if let Some(first) = args.first() { if let Some(first) = args.first() {
if let ExprKind::Call { func, .. } = &first.node { if let ExprKind::Call(ast::ExprCall { func, .. }) = &first.node {
if let ExprKind::Attribute { attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &func.node {
if attr == "format" { if attr == "format" {
return Some(Diagnostic::new(FormatInGetTextFuncCall {}, first.range())); return Some(Diagnostic::new(FormatInGetTextFuncCall {}, first.range()));
} }
@ -68,16 +68,16 @@ pub fn format_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
/// INT003 /// INT003
pub fn printf_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> { pub fn printf_in_gettext_func_call(args: &[Expr]) -> Option<Diagnostic> {
if let Some(first) = args.first() { if let Some(first) = args.first() {
if let ExprKind::BinOp { if let ExprKind::BinOp(ast::ExprBinOp {
op: Operator::Mod { .. }, op: Operator::Mod { .. },
left, left,
.. ..
} = &first.node }) = &first.node
{ {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(_), value: Constant::Str(_),
.. ..
} = left.node }) = left.node
{ {
return Some(Diagnostic::new(PrintfInGetTextFuncCall {}, first.range())); return Some(Diagnostic::new(PrintfInGetTextFuncCall {}, first.range()));
} }

View file

@ -1,6 +1,6 @@
use itertools::Itertools; use itertools::Itertools;
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Operator}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Operator};
use rustpython_parser::lexer::LexResult; use rustpython_parser::lexer::LexResult;
use rustpython_parser::Tok; use rustpython_parser::Tok;
@ -149,22 +149,22 @@ pub fn implicit(tokens: &[LexResult], settings: &Settings, locator: &Locator) ->
/// ISC003 /// ISC003
pub fn explicit(expr: &Expr) -> Option<Diagnostic> { pub fn explicit(expr: &Expr) -> Option<Diagnostic> {
if let ExprKind::BinOp { left, op, right } = &expr.node { if let ExprKind::BinOp(ast::ExprBinOp { left, op, right }) = &expr.node {
if matches!(op, Operator::Add) { if matches!(op, Operator::Add) {
if matches!( if matches!(
left.node, left.node,
ExprKind::JoinedStr { .. } ExprKind::JoinedStr(_)
| ExprKind::Constant { | ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(..) | Constant::Bytes(..), value: Constant::Str(..) | Constant::Bytes(..),
.. ..
} })
) && matches!( ) && matches!(
right.node, right.node,
ExprKind::JoinedStr { .. } ExprKind::JoinedStr(_)
| ExprKind::Constant { | ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(..) | Constant::Bytes(..), value: Constant::Str(..) | Constant::Bytes(..),
.. ..
} })
) { ) {
return Some(Diagnostic::new(ExplicitStringConcatenation, expr.range())); return Some(Diagnostic::new(ExplicitStringConcatenation, expr.range()));
} }

View file

@ -1,6 +1,5 @@
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Operator}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword, Operator};
use std::ops::Add;
use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_ast::helpers::{find_keyword, SimpleCallArgs}; use ruff_python_ast::helpers::{find_keyword, SimpleCallArgs};
@ -43,7 +42,7 @@ const RESERVED_ATTRS: &[&str; 22] = &[
fn check_msg(checker: &mut Checker, msg: &Expr) { fn check_msg(checker: &mut Checker, msg: &Expr) {
match &msg.node { match &msg.node {
// Check for string concatenation and percent format. // Check for string concatenation and percent format.
ExprKind::BinOp { op, .. } => match op { ExprKind::BinOp(ast::ExprBinOp { op, .. }) => match op {
Operator::Add => { Operator::Add => {
if checker.settings.rules.enabled(Rule::LoggingStringConcat) { if checker.settings.rules.enabled(Rule::LoggingStringConcat) {
checker checker
@ -61,7 +60,7 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
_ => {} _ => {}
}, },
// Check for f-strings. // Check for f-strings.
ExprKind::JoinedStr { .. } => { ExprKind::JoinedStr(_) => {
if checker.settings.rules.enabled(Rule::LoggingFString) { if checker.settings.rules.enabled(Rule::LoggingFString) {
checker checker
.diagnostics .diagnostics
@ -69,10 +68,10 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
} }
} }
// Check for .format() calls. // Check for .format() calls.
ExprKind::Call { func, .. } => { ExprKind::Call(ast::ExprCall { func, .. }) => {
if checker.settings.rules.enabled(Rule::LoggingStringFormat) { if checker.settings.rules.enabled(Rule::LoggingStringFormat) {
if let ExprKind::Attribute { value, attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) = &func.node {
if attr == "format" && matches!(value.node, ExprKind::Constant { .. }) { if attr == "format" && matches!(value.node, ExprKind::Constant(_)) {
checker checker
.diagnostics .diagnostics
.push(Diagnostic::new(LoggingStringFormat, msg.range())); .push(Diagnostic::new(LoggingStringFormat, msg.range()));
@ -87,13 +86,13 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
/// Check contents of the `extra` argument to logging calls. /// Check contents of the `extra` argument to logging calls.
fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) { fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
match &extra.node.value.node { match &extra.node.value.node {
ExprKind::Dict { keys, .. } => { ExprKind::Dict(ast::ExprDict { keys, .. }) => {
for key in keys { for key in keys {
if let Some(key) = &key { if let Some(key) = &key {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(string), value: Constant::Str(string),
.. ..
} = &key.node }) = &key.node
{ {
if RESERVED_ATTRS.contains(&string.as_str()) { if RESERVED_ATTRS.contains(&string.as_str()) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
@ -105,7 +104,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
} }
} }
} }
ExprKind::Call { func, keywords, .. } => { ExprKind::Call(ast::ExprCall { func, keywords, .. }) => {
if checker if checker
.ctx .ctx
.resolve_call_path(func) .resolve_call_path(func)
@ -151,10 +150,10 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
return; return;
} }
if let ExprKind::Attribute { value, attr, .. } = &func.node { if let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) = &func.node {
if let Some(logging_call_type) = LoggingCallType::from_attribute(attr.as_str()) { if let Some(logging_call_type) = LoggingCallType::from_attribute(attr.as_str()) {
let call_args = SimpleCallArgs::new(args, keywords); let call_args = SimpleCallArgs::new(args, keywords);
let level_call_range = TextRange::new(value.end().add(TextSize::from(1)), func.end()); let level_call_range = TextRange::new(value.end() + TextSize::from(1), func.end());
// G001 - G004 // G001 - G004
let msg_pos = usize::from(matches!(logging_call_type, LoggingCallType::LogCall)); let msg_pos = usize::from(matches!(logging_call_type, LoggingCallType::LogCall));
@ -202,11 +201,13 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
// return. // return.
if !(matches!( if !(matches!(
exc_info.node.value.node, exc_info.node.value.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Bool(true), value: Constant::Bool(true),
.. ..
} })
) || if let ExprKind::Call { func, .. } = &exc_info.node.value.node { ) || if let ExprKind::Call(ast::ExprCall { func, .. }) =
&exc_info.node.value.node
{
checker checker
.ctx .ctx
.resolve_call_path(func) .resolve_call_path(func)

View file

@ -5,7 +5,7 @@ use itertools::Either::{Left, Right};
use log::error; use log::error;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustpython_parser::ast::{ use rustpython_parser::ast::{
Boolop, Constant, Expr, ExprContext, ExprKind, Keyword, Stmt, StmtKind, self, Boolop, Constant, Expr, ExprContext, ExprKind, Keyword, Stmt, StmtKind,
}; };
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
@ -301,15 +301,15 @@ pub fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
// redundant. Consider removing all `pass` statements instead. // redundant. Consider removing all `pass` statements instead.
let docstring_stmt = &body[0]; let docstring_stmt = &body[0];
let pass_stmt = &body[1]; let pass_stmt = &body[1];
let StmtKind::Expr { value } = &docstring_stmt.node else { let StmtKind::Expr(ast::StmtExpr { value } )= &docstring_stmt.node else {
return; return;
}; };
if matches!( if matches!(
value.node, value.node,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(..), value: Constant::Str(..),
.. ..
} })
) { ) {
if matches!(pass_stmt.node, StmtKind::Pass) { if matches!(pass_stmt.node, StmtKind::Pass) {
let mut diagnostic = Diagnostic::new(UnnecessaryPass, pass_stmt.range()); let mut diagnostic = Diagnostic::new(UnnecessaryPass, pass_stmt.range());
@ -351,18 +351,18 @@ pub fn duplicate_class_field_definition<'a, 'b>(
for stmt in body { for stmt in body {
// Extract the property name from the assignment statement. // Extract the property name from the assignment statement.
let target = match &stmt.node { let target = match &stmt.node {
StmtKind::Assign { targets, .. } => { StmtKind::Assign(ast::StmtAssign { targets, .. }) => {
if targets.len() != 1 { if targets.len() != 1 {
continue; continue;
} }
if let ExprKind::Name { id, .. } = &targets[0].node { if let ExprKind::Name(ast::ExprName { id, .. }) = &targets[0].node {
id id
} else { } else {
continue; continue;
} }
} }
StmtKind::AnnAssign { target, .. } => { StmtKind::AnnAssign(ast::StmtAnnAssign { target, .. }) => {
if let ExprKind::Name { id, .. } = &target.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &target.node {
id id
} else { } else {
continue; continue;
@ -407,7 +407,7 @@ pub fn non_unique_enums<'a, 'b>(checker: &mut Checker<'a>, parent: &'b Stmt, bod
where where
'b: 'a, 'b: 'a,
{ {
let StmtKind::ClassDef { bases, .. } = &parent.node else { let StmtKind::ClassDef(ast::StmtClassDef { bases, .. }) = &parent.node else {
return; return;
}; };
@ -422,11 +422,11 @@ where
let mut seen_targets: FxHashSet<ComparableExpr> = FxHashSet::default(); let mut seen_targets: FxHashSet<ComparableExpr> = FxHashSet::default();
for stmt in body { for stmt in body {
let StmtKind::Assign { value, .. } = &stmt.node else { let StmtKind::Assign(ast::StmtAssign { value, .. }) = &stmt.node else {
continue; continue;
}; };
if let ExprKind::Call { func, .. } = &value.node { if let ExprKind::Call(ast::ExprCall { func, .. }) = &value.node {
if checker if checker
.ctx .ctx
.resolve_call_path(func) .resolve_call_path(func)
@ -454,7 +454,7 @@ pub fn unnecessary_spread(checker: &mut Checker, keys: &[Option<Expr>], values:
if let (None, value) = item { if let (None, value) = item {
// We only care about when the key is None which indicates a spread `**` // We only care about when the key is None which indicates a spread `**`
// inside a dict. // inside a dict.
if let ExprKind::Dict { .. } = value.node { if let ExprKind::Dict(_) = value.node {
let diagnostic = Diagnostic::new(UnnecessarySpread, value.range()); let diagnostic = Diagnostic::new(UnnecessarySpread, value.range());
checker.diagnostics.push(diagnostic); checker.diagnostics.push(diagnostic);
} }
@ -464,10 +464,10 @@ pub fn unnecessary_spread(checker: &mut Checker, keys: &[Option<Expr>], values:
/// Return `true` if a key is a valid keyword argument name. /// Return `true` if a key is a valid keyword argument name.
fn is_valid_kwarg_name(key: &Expr) -> bool { fn is_valid_kwarg_name(key: &Expr) -> bool {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(value), value: Constant::Str(value),
.. ..
} = &key.node }) = &key.node
{ {
is_identifier(value) is_identifier(value)
} else { } else {
@ -480,7 +480,7 @@ pub fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs: &[Key
for kw in kwargs { for kw in kwargs {
// keyword is a spread operator (indicated by None) // keyword is a spread operator (indicated by None)
if kw.node.arg.is_none() { if kw.node.arg.is_none() {
if let ExprKind::Dict { keys, .. } = &kw.node.value.node { if let ExprKind::Dict(ast::ExprDict { keys, .. }) = &kw.node.value.node {
// ensure foo(**{"bar-bar": 1}) doesn't error // ensure foo(**{"bar-bar": 1}) doesn't error
if keys.iter().all(|expr| expr.as_ref().map_or(false, is_valid_kwarg_name)) || if keys.iter().all(|expr| expr.as_ref().map_or(false, is_valid_kwarg_name)) ||
// handle case of foo(**{**bar}) // handle case of foo(**{**bar})
@ -496,18 +496,17 @@ pub fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs: &[Key
/// PIE810 /// PIE810
pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) { pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
let ExprKind::BoolOp { op: Boolop::Or, values } = &expr.node else { let ExprKind::BoolOp(ast::ExprBoolOp { op: Boolop::Or, values }) = &expr.node else {
return; return;
}; };
let mut duplicates = BTreeMap::new(); let mut duplicates = BTreeMap::new();
for (index, call) in values.iter().enumerate() { for (index, call) in values.iter().enumerate() {
let ExprKind::Call { let ExprKind::Call(ast::ExprCall {
func, func,
args, args,
keywords, keywords,
.. }) = &call.node else {
} = &call.node else {
continue continue
}; };
@ -515,15 +514,14 @@ pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
continue; continue;
} }
let ExprKind::Attribute { value, attr, .. } = &func.node else { let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. } )= &func.node else {
continue continue
}; };
if attr != "startswith" && attr != "endswith" { if attr != "startswith" && attr != "endswith" {
continue; continue;
} }
let ExprKind::Name { id: arg_name, .. } = &value.node else { let ExprKind::Name(ast::ExprName { id: arg_name, .. } )= &value.node else {
continue continue
}; };
@ -547,7 +545,7 @@ pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
.iter() .iter()
.map(|index| &values[*index]) .map(|index| &values[*index])
.map(|expr| { .map(|expr| {
let ExprKind::Call { func: _, args, keywords: _} = &expr.node else { let ExprKind::Call(ast::ExprCall { func: _, args, keywords: _}) = &expr.node else {
unreachable!("{}", format!("Indices should only contain `{attr_name}` calls")) unreachable!("{}", format!("Indices should only contain `{attr_name}` calls"))
}; };
args.get(0) args.get(0)
@ -555,20 +553,20 @@ pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
}) })
.collect(); .collect();
let call = create_expr(ExprKind::Call { let call = create_expr(ExprKind::Call(ast::ExprCall {
func: Box::new(create_expr(ExprKind::Attribute { func: Box::new(create_expr(ExprKind::Attribute(ast::ExprAttribute {
value: Box::new(create_expr(ExprKind::Name { value: Box::new(create_expr(ExprKind::Name(ast::ExprName {
id: arg_name.to_string(), id: arg_name.into(),
ctx: ExprContext::Load, ctx: ExprContext::Load,
})), }))),
attr: attr_name.to_string(), attr: attr_name.into(),
ctx: ExprContext::Load, ctx: ExprContext::Load,
})), }))),
args: vec![create_expr(ExprKind::Tuple { args: vec![create_expr(ExprKind::Tuple(ast::ExprTuple {
elts: words elts: words
.iter() .iter()
.flat_map(|value| { .flat_map(|value| {
if let ExprKind::Tuple { elts, .. } = &value.node { if let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &value.node {
Left(elts.iter()) Left(elts.iter())
} else { } else {
Right(iter::once(*value)) Right(iter::once(*value))
@ -577,13 +575,13 @@ pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
.map(Clone::clone) .map(Clone::clone)
.collect(), .collect(),
ctx: ExprContext::Load, ctx: ExprContext::Load,
})], }))],
keywords: vec![], keywords: vec![],
}); }));
// Generate the combined `BoolOp`. // Generate the combined `BoolOp`.
let mut call = Some(call); let mut call = Some(call);
let bool_op = create_expr(ExprKind::BoolOp { let bool_op = create_expr(ExprKind::BoolOp(ast::ExprBoolOp {
op: Boolop::Or, op: Boolop::Or,
values: values values: values
.iter() .iter()
@ -596,7 +594,7 @@ pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
} }
}) })
.collect(), .collect(),
}); }));
#[allow(deprecated)] #[allow(deprecated)]
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
unparse_expr(&bool_op, checker.stylist), unparse_expr(&bool_op, checker.stylist),
@ -610,7 +608,7 @@ pub fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
/// PIE807 /// PIE807
pub fn reimplemented_list_builtin(checker: &mut Checker, expr: &Expr) { pub fn reimplemented_list_builtin(checker: &mut Checker, expr: &Expr) {
let ExprKind::Lambda { args, body } = &expr.node else { let ExprKind::Lambda(ast::ExprLambda { args, body }) = &expr.node else {
panic!("Expected ExprKind::Lambda"); panic!("Expected ExprKind::Lambda");
}; };
if args.args.is_empty() if args.args.is_empty()
@ -619,7 +617,7 @@ pub fn reimplemented_list_builtin(checker: &mut Checker, expr: &Expr) {
&& args.vararg.is_none() && args.vararg.is_none()
&& args.kwarg.is_none() && args.kwarg.is_none()
{ {
if let ExprKind::List { elts, .. } = &body.node { if let ExprKind::List(ast::ExprList { elts, .. }) = &body.node {
if elts.is_empty() { if elts.is_empty() {
let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range()); let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range());
if checker.patch(diagnostic.kind.rule()) { if checker.patch(diagnostic.kind.rule()) {

View file

@ -1,5 +1,5 @@
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustpython_parser::ast::{Expr, ExprKind, Operator}; use rustpython_parser::ast::{self, Expr, ExprKind, Operator};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -45,11 +45,11 @@ fn traverse_union<'a>(
// //
// So we have to traverse both branches in order (left, then right), to report duplicates // So we have to traverse both branches in order (left, then right), to report duplicates
// in the order they appear in the source code. // in the order they appear in the source code.
if let ExprKind::BinOp { if let ExprKind::BinOp(ast::ExprBinOp {
op: Operator::BitOr, op: Operator::BitOr,
left, left,
right, right,
} = &expr.node }) = &expr.node
{ {
// Traverse left subtree, then the right subtree, propagating the previous node. // Traverse left subtree, then the right subtree, propagating the previous node.
traverse_union(seen_nodes, checker, left, Some(expr)); traverse_union(seen_nodes, checker, left, Some(expr));
@ -72,7 +72,7 @@ fn traverse_union<'a>(
let parent = parent.expect("Parent node must exist"); let parent = parent.expect("Parent node must exist");
// SAFETY: Parent node must have been a `BinOp` in order for us to have traversed it. // SAFETY: Parent node must have been a `BinOp` in order for us to have traversed it.
let ExprKind::BinOp { left, right, .. } = &parent.node else { let ExprKind::BinOp(ast::ExprBinOp { left, right, .. }) = &parent.node else {
panic!("Parent node must be a BinOp"); panic!("Parent node must be a BinOp");
}; };

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind}; use rustpython_parser::ast::{self, Constant, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -20,8 +20,8 @@ pub fn non_empty_stub_body(checker: &mut Checker, body: &[Stmt]) {
if body.len() != 1 { if body.len() != 1 {
return; return;
} }
if let StmtKind::Expr { value } = &body[0].node { if let StmtKind::Expr(ast::StmtExpr { value }) = &body[0].node {
if let ExprKind::Constant { value, .. } = &value.node { if let ExprKind::Constant(ast::ExprConstant { value, .. }) = &value.node {
if matches!(value, Constant::Ellipsis | Constant::Str(_)) { if matches!(value, Constant::Ellipsis | Constant::Str(_)) {
return; return;
} }

View file

@ -1,6 +1,6 @@
use std::fmt; use std::fmt;
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -63,13 +63,13 @@ pub fn prefix_type_params(checker: &mut Checker, value: &Expr, targets: &[Expr])
if targets.len() != 1 { if targets.len() != 1 {
return; return;
} }
if let ExprKind::Name { id, .. } = &targets[0].node { if let ExprKind::Name(ast::ExprName { id, .. }) = &targets[0].node {
if id.starts_with('_') { if id.starts_with('_') {
return; return;
} }
}; };
if let ExprKind::Call { func, .. } = &value.node { if let ExprKind::Call(ast::ExprCall { func, .. }) = &value.node {
let Some(kind) = checker.ctx.resolve_call_path(func).and_then(|call_path| { let Some(kind) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
if checker.ctx.match_typing_call_path(&call_path, "ParamSpec") { if checker.ctx.match_typing_call_path(&call_path, "ParamSpec") {
Some(VarKind::ParamSpec) Some(VarKind::ParamSpec)

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Arguments, Constant, Expr, ExprKind, Operator, Unaryop}; use rustpython_parser::ast::{self, Arguments, Constant, Expr, ExprKind, Operator, Unaryop};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -80,14 +80,16 @@ fn is_valid_default_value_with_annotation(
allow_container: bool, allow_container: bool,
) -> bool { ) -> bool {
match &default.node { match &default.node {
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } | ExprKind::Set { elts, .. } => { ExprKind::List(ast::ExprList { elts, .. })
| ExprKind::Tuple(ast::ExprTuple { elts, .. })
| ExprKind::Set(ast::ExprSet { elts }) => {
return allow_container return allow_container
&& elts.len() <= 10 && elts.len() <= 10
&& elts && elts
.iter() .iter()
.all(|e| is_valid_default_value_with_annotation(e, checker, false)); .all(|e| is_valid_default_value_with_annotation(e, checker, false));
} }
ExprKind::Dict { keys, values, .. } => { ExprKind::Dict(ast::ExprDict { keys, values }) => {
return allow_container return allow_container
&& keys.len() <= 10 && keys.len() <= 10
&& keys.iter().zip(values).all(|(k, v)| { && keys.iter().zip(values).all(|(k, v)| {
@ -96,60 +98,60 @@ fn is_valid_default_value_with_annotation(
}) && is_valid_default_value_with_annotation(v, checker, false) }) && is_valid_default_value_with_annotation(v, checker, false)
}); });
} }
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Ellipsis | Constant::None, value: Constant::Ellipsis | Constant::None,
.. ..
} => { }) => {
return true; return true;
} }
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(..), value: Constant::Str(..),
.. ..
} => return checker.locator.slice(default.range()).len() <= 50, }) => return checker.locator.slice(default.range()).len() <= 50,
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Bytes(..), value: Constant::Bytes(..),
.. ..
} => return checker.locator.slice(default.range()).len() <= 50, }) => return checker.locator.slice(default.range()).len() <= 50,
// Ex) `123`, `True`, `False`, `3.14` // Ex) `123`, `True`, `False`, `3.14`
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(..) | Constant::Bool(..) | Constant::Float(..), value: Constant::Int(..) | Constant::Bool(..) | Constant::Float(..),
.. ..
} => { }) => {
return checker.locator.slice(default.range()).len() <= 10; return checker.locator.slice(default.range()).len() <= 10;
} }
// Ex) `2j` // Ex) `2j`
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Complex { real, .. }, value: Constant::Complex { real, .. },
.. ..
} => { }) => {
if *real == 0.0 { if *real == 0.0 {
return checker.locator.slice(default.range()).len() <= 10; return checker.locator.slice(default.range()).len() <= 10;
} }
} }
ExprKind::UnaryOp { ExprKind::UnaryOp(ast::ExprUnaryOp {
op: Unaryop::USub, op: Unaryop::USub,
operand, operand,
} => { }) => {
// Ex) `-1`, `-3.14` // Ex) `-1`, `-3.14`
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(..) | Constant::Float(..), value: Constant::Int(..) | Constant::Float(..),
.. ..
} = &operand.node }) = &operand.node
{ {
return checker.locator.slice(operand.range()).len() <= 10; return checker.locator.slice(operand.range()).len() <= 10;
} }
// Ex) `-2j` // Ex) `-2j`
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Complex { real, .. }, value: Constant::Complex { real, .. },
.. ..
} = &operand.node }) = &operand.node
{ {
if *real == 0.0 { if *real == 0.0 {
return checker.locator.slice(operand.range()).len() <= 10; return checker.locator.slice(operand.range()).len() <= 10;
} }
} }
// Ex) `-math.inf`, `-math.pi`, etc. // Ex) `-math.inf`, `-math.pi`, etc.
if let ExprKind::Attribute { .. } = &operand.node { if let ExprKind::Attribute(_) = &operand.node {
if checker if checker
.ctx .ctx
.resolve_call_path(operand) .resolve_call_path(operand)
@ -164,34 +166,34 @@ fn is_valid_default_value_with_annotation(
} }
} }
} }
ExprKind::BinOp { ExprKind::BinOp(ast::ExprBinOp {
left, left,
op: Operator::Add | Operator::Sub, op: Operator::Add | Operator::Sub,
right, right,
} => { }) => {
// Ex) `1 + 2j`, `1 - 2j`, `-1 - 2j`, `-1 + 2j` // Ex) `1 + 2j`, `1 - 2j`, `-1 - 2j`, `-1 + 2j`
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Complex { .. }, value: Constant::Complex { .. },
.. ..
} = right.node }) = right.node
{ {
// Ex) `1 + 2j`, `1 - 2j` // Ex) `1 + 2j`, `1 - 2j`
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(..) | Constant::Float(..), value: Constant::Int(..) | Constant::Float(..),
.. ..
} = &left.node }) = &left.node
{ {
return checker.locator.slice(left.range()).len() <= 10; return checker.locator.slice(left.range()).len() <= 10;
} else if let ExprKind::UnaryOp { } else if let ExprKind::UnaryOp(ast::ExprUnaryOp {
op: Unaryop::USub, op: Unaryop::USub,
operand, operand,
} = &left.node }) = &left.node
{ {
// Ex) `-1 + 2j`, `-1 - 2j` // Ex) `-1 + 2j`, `-1 - 2j`
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Int(..) | Constant::Float(..), value: Constant::Int(..) | Constant::Float(..),
.. ..
} = &operand.node }) = &operand.node
{ {
return checker.locator.slice(operand.range()).len() <= 10; return checker.locator.slice(operand.range()).len() <= 10;
} }
@ -199,7 +201,7 @@ fn is_valid_default_value_with_annotation(
} }
} }
// Ex) `math.inf`, `sys.stdin`, etc. // Ex) `math.inf`, `sys.stdin`, etc.
ExprKind::Attribute { .. } => { ExprKind::Attribute(_) => {
if checker if checker
.ctx .ctx
.resolve_call_path(default) .resolve_call_path(default)
@ -221,18 +223,18 @@ fn is_valid_default_value_with_annotation(
/// Returns `true` if an [`Expr`] appears to be a valid PEP 604 union. (e.g. `int | None`) /// Returns `true` if an [`Expr`] appears to be a valid PEP 604 union. (e.g. `int | None`)
fn is_valid_pep_604_union(annotation: &Expr) -> bool { fn is_valid_pep_604_union(annotation: &Expr) -> bool {
match &annotation.node { match &annotation.node {
ExprKind::BinOp { ExprKind::BinOp(ast::ExprBinOp {
left, left,
op: Operator::BitOr, op: Operator::BitOr,
right, right,
} => is_valid_pep_604_union(left) && is_valid_pep_604_union(right), }) => is_valid_pep_604_union(left) && is_valid_pep_604_union(right),
ExprKind::Name { .. } ExprKind::Name(_)
| ExprKind::Subscript { .. } | ExprKind::Subscript(_)
| ExprKind::Attribute { .. } | ExprKind::Attribute(_)
| ExprKind::Constant { | ExprKind::Constant(ast::ExprConstant {
value: Constant::None, value: Constant::None,
.. ..
} => true, }) => true,
_ => false, _ => false,
} }
} }
@ -241,21 +243,21 @@ fn is_valid_pep_604_union(annotation: &Expr) -> bool {
fn is_valid_default_value_without_annotation(default: &Expr) -> bool { fn is_valid_default_value_without_annotation(default: &Expr) -> bool {
matches!( matches!(
&default.node, &default.node,
ExprKind::Call { .. } ExprKind::Call(_)
| ExprKind::Name { .. } | ExprKind::Name(_)
| ExprKind::Attribute { .. } | ExprKind::Attribute(_)
| ExprKind::Subscript { .. } | ExprKind::Subscript(_)
| ExprKind::Constant { | ExprKind::Constant(ast::ExprConstant {
value: Constant::Ellipsis | Constant::None, value: Constant::Ellipsis | Constant::None,
.. ..
} })
) || is_valid_pep_604_union(default) ) || is_valid_pep_604_union(default)
} }
/// Returns `true` if an [`Expr`] appears to be `TypeVar`, `TypeVarTuple`, `NewType`, or `ParamSpec` /// Returns `true` if an [`Expr`] appears to be `TypeVar`, `TypeVarTuple`, `NewType`, or `ParamSpec`
/// call. /// call.
fn is_type_var_like_call(context: &Context, expr: &Expr) -> bool { fn is_type_var_like_call(context: &Context, expr: &Expr) -> bool {
let ExprKind::Call { func, .. } = &expr.node else { let ExprKind::Call(ast::ExprCall { func, .. } )= &expr.node else {
return false; return false;
}; };
context.resolve_call_path(func).map_or(false, |call_path| { context.resolve_call_path(func).map_or(false, |call_path| {
@ -272,7 +274,7 @@ fn is_type_var_like_call(context: &Context, expr: &Expr) -> bool {
/// Returns `true` if this is a "special" assignment which must have a value (e.g., an assignment to /// Returns `true` if this is a "special" assignment which must have a value (e.g., an assignment to
/// `__all__`). /// `__all__`).
fn is_special_assignment(context: &Context, target: &Expr) -> bool { fn is_special_assignment(context: &Context, target: &Expr) -> bool {
if let ExprKind::Name { id, .. } = &target.node { if let ExprKind::Name(ast::ExprName { id, .. }) = &target.node {
match id.as_str() { match id.as_str() {
"__all__" => context.scope().kind.is_module(), "__all__" => context.scope().kind.is_module(),
"__match_args__" | "__slots__" => context.scope().kind.is_class(), "__match_args__" | "__slots__" => context.scope().kind.is_class(),

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Expr, ExprKind}; use rustpython_parser::ast::{self, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -60,7 +60,7 @@ fn is_t_suffixed_type_alias(name: &str) -> bool {
/// PYI042 /// PYI042
pub fn snake_case_type_alias(checker: &mut Checker, target: &Expr) { pub fn snake_case_type_alias(checker: &mut Checker, target: &Expr) {
if let ExprKind::Name { id, .. } = target.node() { if let ExprKind::Name(ast::ExprName { id, .. }) = target.node() {
if !is_snake_case_type_alias(id) { if !is_snake_case_type_alias(id) {
return; return;
} }
@ -76,7 +76,7 @@ pub fn snake_case_type_alias(checker: &mut Checker, target: &Expr) {
/// PYI043 /// PYI043
pub fn t_suffixed_type_alias(checker: &mut Checker, target: &Expr) { pub fn t_suffixed_type_alias(checker: &mut Checker, target: &Expr) {
if let ExprKind::Name { id, .. } = target.node() { if let ExprKind::Name(ast::ExprName { id, .. }) = target.node() {
if !is_t_suffixed_type_alias(id) { if !is_t_suffixed_type_alias(id) {
return; return;
} }

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind}; use rustpython_parser::ast::{self, Cmpop, Constant, Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -126,10 +126,10 @@ pub fn unrecognized_platform(
} }
match &right.node { match &right.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(value), value: Constant::Str(value),
.. ..
} => { }) => {
// Other values are possible but we don't need them right now. // Other values are possible but we don't need them right now.
// This protects against typos. // This protects against typos.
if !["linux", "win32", "cygwin", "darwin"].contains(&value.as_str()) if !["linux", "win32", "cygwin", "darwin"].contains(&value.as_str())

View file

@ -6,7 +6,8 @@ use libcst_native::{
SmallStatement, Statement, Suite, TrailingWhitespace, UnaryOp, UnaryOperation, SmallStatement, Statement, Suite, TrailingWhitespace, UnaryOp, UnaryOperation,
}; };
use rustpython_parser::ast::{ use rustpython_parser::ast::{
Boolop, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, Stmt, StmtKind, Unaryop, self, Boolop, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, Stmt, StmtKind,
Unaryop,
}; };
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
@ -135,7 +136,7 @@ where
{ {
fn visit_stmt(&mut self, stmt: &'a Stmt) { fn visit_stmt(&mut self, stmt: &'a Stmt) {
match &stmt.node { match &stmt.node {
StmtKind::Assert { .. } => { StmtKind::Assert(_) => {
self.current_assert = Some(stmt); self.current_assert = Some(stmt);
visitor::walk_stmt(self, stmt); visitor::walk_stmt(self, stmt);
self.current_assert = None; self.current_assert = None;
@ -146,9 +147,9 @@ where
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match &expr.node { match &expr.node {
ExprKind::Name { id, .. } => { ExprKind::Name(ast::ExprName { id, .. }) => {
if let Some(current_assert) = self.current_assert { if let Some(current_assert) = self.current_assert {
if id.as_str() == self.exception_name { if id == self.exception_name {
self.errors.push(Diagnostic::new( self.errors.push(Diagnostic::new(
PytestAssertInExcept { PytestAssertInExcept {
name: id.to_string(), name: id.to_string(),
@ -181,11 +182,11 @@ pub fn unittest_assertion(
keywords: &[Keyword], keywords: &[Keyword],
) -> Option<Diagnostic> { ) -> Option<Diagnostic> {
match &func.node { match &func.node {
ExprKind::Attribute { attr, .. } => { ExprKind::Attribute(ast::ExprAttribute { attr, .. }) => {
if let Ok(unittest_assert) = UnittestAssert::try_from(attr.as_str()) { if let Ok(unittest_assert) = UnittestAssert::try_from(attr.as_str()) {
// We're converting an expression to a statement, so avoid applying the fix if // We're converting an expression to a statement, so avoid applying the fix if
// the assertion is part of a larger expression. // the assertion is part of a larger expression.
let fixable = matches!(checker.ctx.stmt().node, StmtKind::Expr { .. }) let fixable = matches!(checker.ctx.stmt().node, StmtKind::Expr(_))
&& checker.ctx.expr_parent().is_none() && checker.ctx.expr_parent().is_none()
&& !checker.ctx.scope().kind.is_lambda() && !checker.ctx.scope().kind.is_lambda()
&& !has_comments_in(expr.range(), checker.locator); && !has_comments_in(expr.range(), checker.locator);
@ -227,7 +228,11 @@ pub fn assert_in_exception_handler(handlers: &[Excepthandler]) -> Vec<Diagnostic
handlers handlers
.iter() .iter()
.flat_map(|handler| match &handler.node { .flat_map(|handler| match &handler.node {
ExcepthandlerKind::ExceptHandler { name, body, .. } => { ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler {
name,
body,
..
}) => {
if let Some(name) = name { if let Some(name) = name {
check_assert_in_except(name, body) check_assert_in_except(name, body)
} else { } else {
@ -255,28 +260,28 @@ enum CompositionKind {
/// `not a and not b` by De Morgan's laws. /// `not a and not b` by De Morgan's laws.
fn is_composite_condition(test: &Expr) -> CompositionKind { fn is_composite_condition(test: &Expr) -> CompositionKind {
match &test.node { match &test.node {
ExprKind::BoolOp { ExprKind::BoolOp(ast::ExprBoolOp {
op: Boolop::And, .. op: Boolop::And, ..
} => { }) => {
return CompositionKind::Simple; return CompositionKind::Simple;
} }
ExprKind::UnaryOp { ExprKind::UnaryOp(ast::ExprUnaryOp {
op: Unaryop::Not, op: Unaryop::Not,
operand, operand,
} => { }) => {
if let ExprKind::BoolOp { if let ExprKind::BoolOp(ast::ExprBoolOp {
op: Boolop::Or, op: Boolop::Or,
values, values,
} = &operand.node }) = &operand.node
{ {
// Only split cases without mixed `and` and `or`. // Only split cases without mixed `and` and `or`.
return if values.iter().all(|expr| { return if values.iter().all(|expr| {
!matches!( !matches!(
expr.node, expr.node,
ExprKind::BoolOp { ExprKind::BoolOp(ast::ExprBoolOp {
op: Boolop::And, op: Boolop::And,
.. ..
} })
) )
}) { }) {
CompositionKind::Simple CompositionKind::Simple

View file

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use ruff_text_size::{TextLen, TextRange, TextSize}; use ruff_text_size::{TextLen, TextRange, TextSize};
use rustpython_parser::ast::{Arguments, Expr, ExprKind, Keyword, Stmt, StmtKind}; use rustpython_parser::ast::{self, Arguments, Expr, ExprKind, Keyword, Stmt, StmtKind};
use std::fmt; use std::fmt;
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
@ -208,28 +208,28 @@ where
{ {
fn visit_stmt(&mut self, stmt: &'b Stmt) { fn visit_stmt(&mut self, stmt: &'b Stmt) {
match &stmt.node { match &stmt.node {
StmtKind::Return { value, .. } => { StmtKind::Return(ast::StmtReturn { value }) => {
if value.is_some() { if value.is_some() {
self.has_return_with_value = true; self.has_return_with_value = true;
} }
} }
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {} StmtKind::FunctionDef(_) | StmtKind::AsyncFunctionDef(_) => {}
_ => visitor::walk_stmt(self, stmt), _ => visitor::walk_stmt(self, stmt),
} }
} }
fn visit_expr(&mut self, expr: &'b Expr) { fn visit_expr(&mut self, expr: &'b Expr) {
match &expr.node { match &expr.node {
ExprKind::YieldFrom { .. } => { ExprKind::YieldFrom(_) => {
self.has_yield_from = true; self.has_yield_from = true;
} }
ExprKind::Yield { value, .. } => { ExprKind::Yield(ast::ExprYield { value }) => {
self.yield_statements.push(expr); self.yield_statements.push(expr);
if value.is_some() { if value.is_some() {
self.has_return_with_value = true; self.has_return_with_value = true;
} }
} }
ExprKind::Call { func, .. } => { ExprKind::Call(ast::ExprCall { func, .. }) => {
if collect_call_path(func).map_or(false, |call_path| { if collect_call_path(func).map_or(false, |call_path| {
call_path.as_slice() == ["request", "addfinalizer"] call_path.as_slice() == ["request", "addfinalizer"]
}) { }) {
@ -278,12 +278,11 @@ pub fn fix_extraneous_scope_function(
/// PT001, PT002, PT003 /// PT001, PT002, PT003
fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &Expr) { fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &Expr) {
match &decorator.node { match &decorator.node {
ExprKind::Call { ExprKind::Call(ast::ExprCall {
func, func,
args, args,
keywords, keywords,
.. }) => {
} => {
if checker if checker
.settings .settings
.rules .rules
@ -415,8 +414,8 @@ fn check_fixture_returns(checker: &mut Checker, stmt: &Stmt, name: &str, body: &
.enabled(Rule::PytestUselessYieldFixture) .enabled(Rule::PytestUselessYieldFixture)
{ {
if let Some(stmt) = body.last() { if let Some(stmt) = body.last() {
if let StmtKind::Expr { value, .. } = &stmt.node { if let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node {
if let ExprKind::Yield { .. } = value.node { if let ExprKind::Yield(_) = value.node {
if visitor.yield_statements.len() == 1 { if visitor.yield_statements.len() == 1 {
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
PytestUselessYieldFixture { PytestUselessYieldFixture {

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
use ruff_python_ast::call_path::{collect_call_path, CallPath}; use ruff_python_ast::call_path::{collect_call_path, CallPath};
use ruff_python_ast::helpers::map_callable; use ruff_python_ast::helpers::map_callable;
@ -48,10 +48,10 @@ pub(super) fn is_pytest_parametrize(context: &Context, decorator: &Expr) -> bool
} }
pub(super) fn keyword_is_literal(kw: &Keyword, literal: &str) -> bool { pub(super) fn keyword_is_literal(kw: &Keyword, literal: &str) -> bool {
if let ExprKind::Constant { if let ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(string), value: Constant::Str(string),
.. ..
} = &kw.node.value.node }) = &kw.node.value.node
{ {
string == literal string == literal
} else { } else {
@ -61,15 +61,17 @@ pub(super) fn keyword_is_literal(kw: &Keyword, literal: &str) -> bool {
pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool {
match &expr.node { match &expr.node {
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::Str(string), value: Constant::Str(string),
.. ..
} => string.is_empty(), }) => string.is_empty(),
ExprKind::Constant { ExprKind::Constant(ast::ExprConstant {
value: Constant::None, value: Constant::None,
.. ..
} => true, }) => true,
ExprKind::JoinedStr { values } => values.iter().all(is_empty_or_null_string), ExprKind::JoinedStr(ast::ExprJoinedStr { values }) => {
values.iter().all(is_empty_or_null_string)
}
_ => false, _ => false,
} }
} }

View file

@ -36,7 +36,7 @@ pub fn import(import_from: &Stmt, name: &str, asname: Option<&str>) -> Option<Di
pub fn import_from( pub fn import_from(
import_from: &Stmt, import_from: &Stmt,
module: Option<&str>, module: Option<&str>,
level: Option<usize>, level: Option<u32>,
) -> Option<Diagnostic> { ) -> Option<Diagnostic> {
// If level is not zero or module is none, return // If level is not zero or module is none, return
if let Some(level) = level { if let Some(level) = level {

Some files were not shown because too many files have changed in this diff Show more