From fa909c19ce47794500b713dd624c3cb8bc4d8f67 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 21 Jun 2017 17:09:38 +0100 Subject: [PATCH] Don't pass None as the full name to a plugin We would sometimes pass `None` as the full name of a function to a plugin, which could cause a crash within a plugin that doesn't expect it. --- mypy/checkexpr.py | 8 +++++--- test-data/unit/check-custom-plugin.test | 11 +++++++++++ test-data/unit/plugins/fnplugin.py | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 15539f3a79d2..0101f8eec107 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -375,7 +375,7 @@ def apply_function_plugin(self, formal_to_actual: List[List[int]], args: List[Expression], num_formals: int, - fullname: Optional[str], + fullname: str, object_type: Optional[Type], context: Context) -> Type: """Use special case logic to infer the return type of a specific named function/method. @@ -529,8 +529,10 @@ def check_call(self, callee: Type, args: List[Expression], # Store the inferred callable type. self.chk.store_type(callable_node, callee) - if ((object_type is None and self.plugin.get_function_hook(callable_name)) - or (object_type is not None and self.plugin.get_method_hook(callable_name))): + if (callable_name + and ((object_type is None and self.plugin.get_function_hook(callable_name)) + or (object_type is not None + and self.plugin.get_method_hook(callable_name)))): ret_type = self.apply_function_plugin( arg_types, callee.ret_type, arg_kinds, formal_to_actual, args, len(callee.arg_types), callable_name, object_type, context) diff --git a/test-data/unit/check-custom-plugin.test b/test-data/unit/check-custom-plugin.test index d1fdd9fbcfa9..b8e13464ab65 100644 --- a/test-data/unit/check-custom-plugin.test +++ b/test-data/unit/check-custom-plugin.test @@ -11,6 +11,17 @@ reveal_type(f()) # E: Revealed type is 'builtins.int' [[mypy] plugins=/test-data/unit/plugins/fnplugin.py +[case testFunctionPluginFullnameIsNotNone] +# flags: --config-file tmp/mypy.ini +from typing import Callable, TypeVar +f: Callable[[], None] +T = TypeVar('T') +def g(x: T) -> T: return x # This strips out the name of a callable +g(f)() +[file mypy.ini] +[[mypy] +plugins=/test-data/unit/plugins/fnplugin.py + [case testTwoPlugins] # flags: --config-file tmp/mypy.ini def f(): ... diff --git a/test-data/unit/plugins/fnplugin.py b/test-data/unit/plugins/fnplugin.py index 513279213b7d..684d6343458e 100644 --- a/test-data/unit/plugins/fnplugin.py +++ b/test-data/unit/plugins/fnplugin.py @@ -4,6 +4,7 @@ class MyPlugin(Plugin): def get_function_hook(self, fullname): if fullname == '__main__.f': return my_hook + assert fullname is not None return None def my_hook(ctx):