mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +00:00

## Summary This PR splits the `Constant` enum as individual literal nodes. It introduces the following new nodes for each variant: * `ExprStringLiteral` * `ExprBytesLiteral` * `ExprNumberLiteral` * `ExprBooleanLiteral` * `ExprNoneLiteral` * `ExprEllipsisLiteral` The main motivation behind this refactor is to introduce the new AST node for implicit string concatenation in the coming PR. The elements of that node will be either a string literal, bytes literal or a f-string which can be implemented using an enum. This means that a string or bytes literal cannot be represented by `Constant::Str` / `Constant::Bytes` which creates an inconsistency. This PR avoids that inconsistency by splitting the constant nodes into it's own literal nodes, literal being the more appropriate naming convention from a static analysis tool perspective. This also makes working with literals in the linter and formatter much more ergonomic like, for example, if one would want to check if this is a string literal, it can be done easily using `Expr::is_string_literal_expr` or matching against `Expr::StringLiteral` as oppose to matching against the `ExprConstant` and enum `Constant`. A few AST helper methods can be simplified as well which will be done in a follow-up PR. This introduces a new `Expr::is_literal_expr` method which is the same as `Expr::is_constant_expr`. There are also intermediary changes related to implicit string concatenation which are quiet less. This is done so as to avoid having a huge PR which this already is. ## Test Plan 1. Verify and update all of the existing snapshots (parser, visitor) 2. Verify that the ecosystem check output remains **unchanged** for both the linter and formatter ### Formatter ecosystem check #### `main` | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75803 | 1799 | 1647 | | django | 0.99983 | 2772 | 34 | | home-assistant | 0.99953 | 10596 | 186 | | poetry | 0.99891 | 317 | 17 | | transformers | 0.99966 | 2657 | 330 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99978 | 3669 | 20 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 22 | #### `dhruv/constant-to-literal` | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75803 | 1799 | 1647 | | django | 0.99983 | 2772 | 34 | | home-assistant | 0.99953 | 10596 | 186 | | poetry | 0.99891 | 317 | 17 | | transformers | 0.99966 | 2657 | 330 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99978 | 3669 | 20 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 22 |
79 lines
2 KiB
Rust
79 lines
2 KiB
Rust
use std::fmt::{Debug, Formatter};
|
|
use std::ops::Deref;
|
|
|
|
use ruff_python_ast::ExprStringLiteral;
|
|
use ruff_python_semantic::Definition;
|
|
use ruff_text_size::{Ranged, TextRange};
|
|
|
|
pub(crate) mod extraction;
|
|
pub(crate) mod google;
|
|
pub(crate) mod numpy;
|
|
pub(crate) mod sections;
|
|
pub(crate) mod styles;
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) struct Docstring<'a> {
|
|
pub(crate) definition: &'a Definition<'a>,
|
|
/// The literal AST node representing the docstring.
|
|
pub(crate) expr: &'a ExprStringLiteral,
|
|
/// The content of the docstring, including the leading and trailing quotes.
|
|
pub(crate) contents: &'a str,
|
|
/// The range of the docstring body (without the quotes). The range is relative to [`Self::contents`].
|
|
pub(crate) body_range: TextRange,
|
|
pub(crate) indentation: &'a str,
|
|
}
|
|
|
|
impl<'a> Docstring<'a> {
|
|
pub(crate) fn body(&self) -> DocstringBody {
|
|
DocstringBody { docstring: self }
|
|
}
|
|
|
|
pub(crate) fn leading_quote(&self) -> &'a str {
|
|
&self.contents[TextRange::up_to(self.body_range.start())]
|
|
}
|
|
|
|
pub(crate) fn triple_quoted(&self) -> bool {
|
|
let leading_quote = self.leading_quote();
|
|
leading_quote.ends_with("\"\"\"") || leading_quote.ends_with("'''")
|
|
}
|
|
}
|
|
|
|
impl Ranged for Docstring<'_> {
|
|
fn range(&self) -> TextRange {
|
|
self.expr.range()
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub(crate) struct DocstringBody<'a> {
|
|
docstring: &'a Docstring<'a>,
|
|
}
|
|
|
|
impl<'a> DocstringBody<'a> {
|
|
pub(crate) fn as_str(self) -> &'a str {
|
|
&self.docstring.contents[self.docstring.body_range]
|
|
}
|
|
}
|
|
|
|
impl Ranged for DocstringBody<'_> {
|
|
fn range(&self) -> TextRange {
|
|
self.docstring.body_range + self.docstring.start()
|
|
}
|
|
}
|
|
|
|
impl Deref for DocstringBody<'_> {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.as_str()
|
|
}
|
|
}
|
|
|
|
impl Debug for DocstringBody<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("DocstringBody")
|
|
.field("text", &self.as_str())
|
|
.field("range", &self.range())
|
|
.finish()
|
|
}
|
|
}
|