perf(formatter): Improve is_expression_parenthesized performance (#5825)

This commit is contained in:
Micha Reiser 2023-07-18 15:48:49 +02:00 committed by GitHub
parent 1aa851796e
commit 3b32e3a8fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 9 deletions

View file

@ -1,6 +1,6 @@
use crate::context::NodeLevel; use crate::context::NodeLevel;
use crate::prelude::*; use crate::prelude::*;
use crate::trivia::{first_non_trivia_token, first_non_trivia_token_rev, Token, TokenKind}; use crate::trivia::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind};
use ruff_formatter::prelude::tag::Condition; use ruff_formatter::prelude::tag::Condition;
use ruff_formatter::{format_args, write, Argument, Arguments}; use ruff_formatter::{format_args, write, Argument, Arguments};
use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::node::AnyNodeRef;
@ -72,19 +72,27 @@ pub enum Parentheses {
} }
pub(crate) fn is_expression_parenthesized(expr: AnyNodeRef, contents: &str) -> bool { pub(crate) fn is_expression_parenthesized(expr: AnyNodeRef, contents: &str) -> bool {
matches!( // First test if there's a closing parentheses because it tends to be cheaper.
if matches!(
first_non_trivia_token(expr.end(), contents), first_non_trivia_token(expr.end(), contents),
Some(Token { Some(Token {
kind: TokenKind::RParen, kind: TokenKind::RParen,
.. ..
}) })
) && matches!( ) {
first_non_trivia_token_rev(expr.start(), contents), let mut tokenizer =
Some(Token { SimpleTokenizer::up_to_without_back_comment(expr.start(), contents).skip_trivia();
kind: TokenKind::LParen,
.. matches!(
}) tokenizer.next_back(),
) Some(Token {
kind: TokenKind::LParen,
..
})
)
} else {
false
}
} }
/// Formats `content` enclosed by the `left` and `right` parentheses. The implementation also ensures /// Formats `content` enclosed by the `left` and `right` parentheses. The implementation also ensures

View file

@ -274,10 +274,20 @@ impl<'a> SimpleTokenizer<'a> {
Self::new(source, range) Self::new(source, range)
} }
/// Creates a tokenizer that lexes tokens from the start of `source` up to `offset`.
pub(crate) fn up_to(offset: TextSize, source: &'a str) -> Self { pub(crate) fn up_to(offset: TextSize, source: &'a str) -> Self {
Self::new(source, TextRange::up_to(offset)) Self::new(source, TextRange::up_to(offset))
} }
/// Creates a tokenizer that lexes tokens from the start of `source` up to `offset`, and informs
/// the lexer that the line at `offset` contains no comments. This can significantly speed up backwards lexing
/// because the lexer doesn't need to scan for comments.
pub(crate) fn up_to_without_back_comment(offset: TextSize, source: &'a str) -> Self {
let mut tokenizer = Self::up_to(offset, source);
tokenizer.back_line_has_no_comment = true;
tokenizer
}
fn to_keyword_or_other(&self, range: TextRange) -> TokenKind { fn to_keyword_or_other(&self, range: TextRange) -> TokenKind {
let source = &self.source[range]; let source = &self.source[range];
match source { match source {