Fix stub name resolution

This commit is contained in:
Dave Halter
2018-08-08 13:02:32 +02:00
parent 5466f930be
commit 1ade520ac0

View File

@@ -145,8 +145,8 @@ class TypeshedPlugin(BasePlugin):
pass pass
else: else:
# TODO use code_lines # TODO use code_lines
stub_module_context = ModuleContext( stub_module_context = StubOnlyModuleContext(
evaluator, stub_module_node, path, code_lines=[] context_set, evaluator, stub_module_node, path, code_lines=[]
) )
return ContextSet.from_iterable( return ContextSet.from_iterable(
_merge_modules(context_set, stub_module_context) _merge_modules(context_set, stub_module_context)
@@ -186,7 +186,7 @@ class StubName(TreeNameDefinition):
for stub_context in stub_contexts: for stub_context in stub_contexts:
if isinstance(stub_context, FunctionContext) \ if isinstance(stub_context, FunctionContext) \
and isinstance(actual_context, FunctionContext): and isinstance(actual_context, FunctionContext):
yield FunctionStubContext( yield StubFunctionContext(
actual_context.evaluator, actual_context.evaluator,
stub_context, stub_context,
actual_context.parent_context, actual_context.parent_context,
@@ -210,26 +210,33 @@ class StubName(TreeNameDefinition):
class StubParserTreeFilter(ParserTreeFilter): class StubParserTreeFilter(ParserTreeFilter):
name_class = StubName name_class = StubName
def __init__(self, non_stub_filter, *args, **kwargs): def __init__(self, non_stub_filters, *args, **kwargs):
self._search_global = kwargs.pop('search_global') # Python 2 :/ self._search_global = kwargs.pop('search_global') # Python 2 :/
super(StubParserTreeFilter, self).__init__(*args, **kwargs) super(StubParserTreeFilter, self).__init__(*args, **kwargs)
self._non_stub_filter = non_stub_filter self._non_stub_filters = non_stub_filters
def _check_flows(self, names): def _check_flows(self, names):
return names return names
def _get_non_stub_names(self, string_name):
return [
name
for non_stub_filter in self._non_stub_filters
for name in non_stub_filter.get(string_name)
]
@to_list @to_list
def _convert_names(self, names): def _convert_names(self, names):
for name in names: for name in names:
found_actual_names = self._non_stub_filter.get(name.value) non_stub_names = self._get_non_stub_names(name.value)
# Try to match the names of stubs with non-stubs. If there's no # Try to match the names of stubs with non-stubs. If there's no
# match, just use the stub name. The user will be directed there # match, just use the stub name. The user will be directed there
# for all API accesses. Otherwise the user will be directed to the # for all API accesses. Otherwise the user will be directed to the
# non-stub positions (see StubName). # non-stub positions (see StubName).
if not len(found_actual_names): if not len(non_stub_names):
yield TreeNameDefinition(self.context, name) yield TreeNameDefinition(self.context, name)
else: else:
for non_stub_name in found_actual_names: for non_stub_name in non_stub_names:
assert isinstance(non_stub_name, AbstractTreeName), non_stub_name assert isinstance(non_stub_name, AbstractTreeName), non_stub_name
yield self.name_class( yield self.name_class(
non_stub_name.parent_context, non_stub_name.parent_context,
@@ -270,7 +277,7 @@ class _StubContextFilterMixin(_MixedStubContextMixin):
yield StubParserTreeFilter( yield StubParserTreeFilter(
# Take the first filter, which is here to filter module contents # Take the first filter, which is here to filter module contents
# and wrap it. # and wrap it.
next(filters), [next(filters)],
self.evaluator, self.evaluator,
context=self.stub_context, context=self.stub_context,
until_position=until_position, until_position=until_position,
@@ -289,6 +296,37 @@ class StubClassContext(_StubContextFilterMixin, ClassContext):
pass pass
class FunctionStubContext(_MixedStubContextMixin, FunctionContext): class StubFunctionContext(_MixedStubContextMixin, FunctionContext):
def get_function_execution(self, arguments): def get_function_execution(self, arguments):
return self.stub_context.get_function_execution(arguments) return self.stub_context.get_function_execution(arguments)
return super().get_function_execution(arguments, tree_node=self.stub_context.tree_node)
class StubOnlyModuleContext(ModuleContext):
def __init__(self, non_stub_context_set, *args, **kwargs):
super(StubOnlyModuleContext, self).__init__(*args, **kwargs)
self._non_stub_context_set = non_stub_context_set
def _get_first_non_stub_filters(self):
for context in self._non_stub_context_set:
yield next(context.get_filters(search_global=False))
def get_filters(self, search_global, until_position=None,
origin_scope=None, **kwargs):
filters = super(StubOnlyModuleContext, self).get_filters(
search_global, until_position, origin_scope, **kwargs
)
next(filters) # Ignore the first filter and replace it with our own
# Here we remap the names from stubs to the actual module. This is
# important if type inferences is needed in that module.
yield StubParserTreeFilter(
list(self._get_first_non_stub_filters()),
self.evaluator,
context=self,
until_position=until_position,
origin_scope=origin_scope,
search_global=search_global,
)
for f in filters:
yield f