MCPcopy Create free account
hub / github.com/astral-sh/ruff / node_range

Method node_range

crates/ruff_python_parser/src/parser/mod.rs:311–368  ·  view source on GitHub ↗
(&self, start: TextSize)

Source from the content-addressed store, hash-verified

309 }
310
311 fn node_range(&self, start: TextSize) -> TextRange {
312 // It's possible during error recovery that the parsing didn't consume any tokens. In that
313 // case, `last_token_end` still points to the end of the previous token but `start` is the
314 // start of the current token. Calling `TextRange::new(start, self.last_token_end)` would
315 // panic in that case because `start > end`. This path "detects" this case and creates an
316 // empty range instead.
317 //
318 // The reason it's `<=` instead of just `==` is because there could be whitespaces between
319 // the two tokens. For example:
320 //
321 // ```python
322 // # last token end
323 // # | current token (newline) start
324 // # v v
325 // def foo \n
326 // # ^
327 // # assume there's trailing whitespace here
328 // ```
329 //
330 // Or, there could tokens that are considered "trivia" and thus aren't emitted by the token
331 // source. These are comments and non-logical newlines. For example:
332 //
333 // ```python
334 // # last token end
335 // # v
336 // def foo # comment\n
337 // # ^ current token (newline) start
338 // ```
339 //
340 // In either of the above cases, there's a "gap" between the end of the last token and start
341 // of the current token.
342 if self.prev_token_end <= start {
343 // We need to create an empty range at the last token end instead of the start because
344 // otherwise this node range will fall outside the range of it's parent node. Taking
345 // the above example:
346 //
347 // ```python
348 // if True:
349 // # function start
350 // # | function end
351 // # v v
352 // def foo # comment
353 // # ^ current token start
354 // ```
355 //
356 // Here, the current token start is the start of parameter range but the function ends
357 // at `foo`. Even if there's a function body, the range of parameters would still be
358 // before the comment.
359
360 // test_err node_range_with_gaps
361 // def foo # comment
362 // def bar(): ...
363 // def baz
364 TextRange::empty(self.prev_token_end)
365 } else {
366 TextRange::new(start, self.prev_token_end)
367 }
368 }

Calls 1

emptyFunction · 0.50

Tested by

no test coverage detected