Skip to content

Commit

Permalink
Determine end line and column of function itself
Browse files Browse the repository at this point in the history
  • Loading branch information
mschoettle committed May 6, 2024
1 parent 8b7802c commit 6dee499
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 8 deletions.
21 changes: 21 additions & 0 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -983,10 +983,31 @@ def do_func_def(
end_line = getattr(n, "end_lineno", None)
end_column = getattr(n, "end_col_offset", None)

# Determine end of the function definition itself
# Fall back to the end of the function definition including its body
def_end_line: int | None = n.lineno
def_end_column: int | None = n.col_offset

returns = n.returns
# use the return type hint if defined
if returns is not None:
def_end_line = returns.end_lineno
def_end_column = returns.end_col_offset
# otherwise use the last argument in the function definition
elif len(args) > 0:
last_arg = args[-1]
initializer = last_arg.initializer

def_end_line = initializer.end_line if initializer else last_arg.end_line
def_end_column = initializer.end_column if initializer else last_arg.end_column

self.class_and_function_stack.pop()
self.class_and_function_stack.append("F")
body = self.as_required_block(n.body, can_strip=True, is_coroutine=is_coroutine)
func_def = FuncDef(n.name, args, body, func_type)
func_def.def_end_line = def_end_line
func_def.def_end_column = def_end_column

if isinstance(func_def.type, CallableType):
# semanal.py does some in-place modifications we want to avoid
func_def.unanalyzed_type = func_def.type.copy_modified()
Expand Down
7 changes: 3 additions & 4 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,21 +256,20 @@ def span_from_context(ctx: Context) -> Iterable[int]:
assert origin_span is not None
origin_span = itertools.chain(origin_span, span_from_context(secondary_context))

column = context.column if context else -1
end_line = context.end_line if context else -1
end_column = context.end_column if context else -1

# set end line and column to same as start of context for function definitions
# this avoids errors being reported in IDEs for the whole function
# TODO: figure out if it's possible to find the end of the function definition line
if isinstance(context, FuncDef):
end_line = context.line
end_line = context.def_end_line
# column is 1-based, see also format_messages in errors.py
end_column = column + 1
end_column = context.def_end_column + 1 if context.def_end_column else end_column

self.errors.report(
context.line if context else -1,
column,
context.column if context else -1,
msg,
severity=severity,
file=file,
Expand Down
13 changes: 9 additions & 4 deletions test-data/unit/check-columns.test
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,20 @@ if int():

[case testColumnEndFunctionMissingTypeAnnotation]
# flags: --disallow-untyped-defs --show-error-end
from typing import Any, Optional
if int():
def f(x: int):
def f(x: int, foo: Optional[str]):
pass

def g(x):
def g(x: int, foo: Optional[str] = None):
pass

def h(x, foo = None):
pass
[out]
main:3:5:3:5: error: Function is missing a return type annotation
main:6:5:6:5: error: Function is missing a type annotation
main:4:5:4:37: error: Function is missing a return type annotation
main:7:5:7:44: error: Function is missing a return type annotation
main:10:5:10:24: error: Function is missing a type annotation

[case testColumnNameIsNotDefined]
((x)) # E:3: Name "x" is not defined
Expand Down

0 comments on commit 6dee499

Please sign in to comment.