mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 12:05:57 +00:00 
			
		
		
		
	 ef85c682bd
			
		
	
	
		ef85c682bd
		
			
		
	
	
	
	
		
			
			The AST generator creates a reference enum for each syntax group — an enum where each variant contains a reference to the relevant syntax node. Previously you could customize the name of the reference enum for a group — primarily because there was an existing `ExpressionRef` type that wouldn't have lined up with the auto-derived name `ExprRef`. This follow-up PR is a simple search/replace to switch over to the auto-derived name, so that we can remove this customization point.
		
			
				
	
	
		
			67 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			67 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use ruff_python_trivia::{BackwardsTokenizer, CommentRanges, SimpleTokenKind, SimpleTokenizer};
 | |
| use ruff_text_size::{Ranged, TextLen, TextRange};
 | |
| 
 | |
| use crate::AnyNodeRef;
 | |
| use crate::ExprRef;
 | |
| 
 | |
| /// Returns an iterator over the ranges of the optional parentheses surrounding an expression.
 | |
| ///
 | |
| /// E.g. for `((f()))` with `f()` as expression, the iterator returns the ranges (1, 6) and (0, 7).
 | |
| ///
 | |
| /// Note that without a parent the range can be inaccurate, e.g. `f(a)` we falsely return a set of
 | |
| /// parentheses around `a` even if the parentheses actually belong to `f`. That is why you should
 | |
| /// generally prefer [`parenthesized_range`].
 | |
| pub fn parentheses_iterator<'a>(
 | |
|     expr: ExprRef<'a>,
 | |
|     parent: Option<AnyNodeRef>,
 | |
|     comment_ranges: &'a CommentRanges,
 | |
|     source: &'a str,
 | |
| ) -> impl Iterator<Item = TextRange> + 'a {
 | |
|     let right_tokenizer = if let Some(parent) = parent {
 | |
|         // If the parent is a node that brings its own parentheses, exclude the closing parenthesis
 | |
|         // from our search range. Otherwise, we risk matching on calls, like `func(x)`, for which
 | |
|         // the open and close parentheses are part of the `Arguments` node.
 | |
|         //
 | |
|         // There are a few other nodes that may have their own parentheses, but are fine to exclude:
 | |
|         // - `Parameters`: The parameters to a function definition. Any expressions would represent
 | |
|         //   default arguments, and so must be preceded by _at least_ the parameter name. As such,
 | |
|         //   we won't mistake any parentheses for the opening and closing parentheses on the
 | |
|         //   `Parameters` node itself.
 | |
|         // - `Tuple`: The elements of a tuple. The only risk is a single-element tuple (e.g., `(x,)`),
 | |
|         //    which must have a trailing comma anyway.
 | |
|         let exclusive_parent_end = if parent.is_arguments() {
 | |
|             parent.end() - ")".text_len()
 | |
|         } else {
 | |
|             parent.end()
 | |
|         };
 | |
|         SimpleTokenizer::new(source, TextRange::new(expr.end(), exclusive_parent_end))
 | |
|     } else {
 | |
|         SimpleTokenizer::starts_at(expr.end(), source)
 | |
|     };
 | |
| 
 | |
|     let right_tokenizer = right_tokenizer
 | |
|         .skip_trivia()
 | |
|         .take_while(|token| token.kind == SimpleTokenKind::RParen);
 | |
| 
 | |
|     let left_tokenizer = BackwardsTokenizer::up_to(expr.start(), source, comment_ranges)
 | |
|         .skip_trivia()
 | |
|         .take_while(|token| token.kind == SimpleTokenKind::LParen);
 | |
| 
 | |
|     // Zip closing parenthesis with opening parenthesis. The order is intentional, as testing for
 | |
|     // closing parentheses is cheaper, and `zip` will avoid progressing the `left_tokenizer` if
 | |
|     // the `right_tokenizer` is exhausted.
 | |
|     right_tokenizer
 | |
|         .zip(left_tokenizer)
 | |
|         .map(|(right, left)| TextRange::new(left.start(), right.end()))
 | |
| }
 | |
| 
 | |
| /// Returns the [`TextRange`] of a given expression including parentheses, if the expression is
 | |
| /// parenthesized; or `None`, if the expression is not parenthesized.
 | |
| pub fn parenthesized_range(
 | |
|     expr: ExprRef,
 | |
|     parent: AnyNodeRef,
 | |
|     comment_ranges: &CommentRanges,
 | |
|     source: &str,
 | |
| ) -> Option<TextRange> {
 | |
|     parentheses_iterator(expr, Some(parent), comment_ranges, source).last()
 | |
| }
 |