forked from python/mypy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindirection.py
More file actions
118 lines (88 loc) · 4.29 KB
/
indirection.py
File metadata and controls
118 lines (88 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from typing import Dict, Iterable, List, Optional, Set, Union
from mypy.types import SyntheticTypeVisitor
import mypy.types as types
from mypy.util import split_module_names
def extract_module_names(type_name: Optional[str]) -> List[str]:
"""Returns the module names of a fully qualified type name."""
if type_name is not None:
# Discard the first one, which is just the qualified name of the type
possible_module_names = split_module_names(type_name)
return possible_module_names[1:]
else:
return []
class TypeIndirectionVisitor(SyntheticTypeVisitor[Set[str]]):
"""Returns all module references within a particular type."""
def __init__(self) -> None:
self.cache = {} # type: Dict[types.Type, Set[str]]
def find_modules(self, typs: Iterable[types.Type]) -> Set[str]:
return self._visit(typs)
def _visit(self, typ_or_typs: Union[types.Type, Iterable[types.Type]]) -> Set[str]:
typs = [typ_or_typs] if isinstance(typ_or_typs, types.Type) else typ_or_typs
output = set() # type: Set[str]
for typ in typs:
if typ in self.cache:
modules = self.cache[typ]
else:
modules = typ.accept(self)
self.cache[typ] = set(modules)
output.update(modules)
return output
def visit_unbound_type(self, t: types.UnboundType) -> Set[str]:
return self._visit(t.args)
def visit_type_list(self, t: types.TypeList) -> Set[str]:
return self._visit(t.items)
def visit_callable_argument(self, t: types.CallableArgument) -> Set[str]:
return self._visit(t.typ)
def visit_any(self, t: types.AnyType) -> Set[str]:
return set()
def visit_none_type(self, t: types.NoneType) -> Set[str]:
return set()
def visit_uninhabited_type(self, t: types.UninhabitedType) -> Set[str]:
return set()
def visit_erased_type(self, t: types.ErasedType) -> Set[str]:
return set()
def visit_deleted_type(self, t: types.DeletedType) -> Set[str]:
return set()
def visit_type_var(self, t: types.TypeVarType) -> Set[str]:
return self._visit(t.values) | self._visit(t.upper_bound)
def visit_instance(self, t: types.Instance) -> Set[str]:
out = self._visit(t.args)
if t.type:
# Uses of a class depend on everything in the MRO,
# as changes to classes in the MRO can add types to methods,
# change property types, change the MRO itself, etc.
for s in t.type.mro:
out.update(split_module_names(s.module_name))
if t.type.metaclass_type is not None:
out.update(split_module_names(t.type.metaclass_type.type.module_name))
return out
def visit_callable_type(self, t: types.CallableType) -> Set[str]:
out = self._visit(t.arg_types) | self._visit(t.ret_type)
if t.definition is not None:
out.update(extract_module_names(t.definition.fullname()))
return out
def visit_overloaded(self, t: types.Overloaded) -> Set[str]:
return self._visit(t.items()) | self._visit(t.fallback)
def visit_tuple_type(self, t: types.TupleType) -> Set[str]:
return self._visit(t.items) | self._visit(t.partial_fallback)
def visit_typeddict_type(self, t: types.TypedDictType) -> Set[str]:
return self._visit(t.items.values()) | self._visit(t.fallback)
def visit_raw_expression_type(self, t: types.RawExpressionType) -> Set[str]:
assert False, "Unexpected RawExpressionType after semantic analysis phase"
def visit_literal_type(self, t: types.LiteralType) -> Set[str]:
return self._visit(t.fallback)
def visit_star_type(self, t: types.StarType) -> Set[str]:
return set()
def visit_union_type(self, t: types.UnionType) -> Set[str]:
return self._visit(t.items)
def visit_partial_type(self, t: types.PartialType) -> Set[str]:
return set()
def visit_ellipsis_type(self, t: types.EllipsisType) -> Set[str]:
return set()
def visit_type_type(self, t: types.TypeType) -> Set[str]:
return self._visit(t.item)
def visit_forwardref_type(self, t: types.ForwardRef) -> Set[str]:
if t.resolved:
return self._visit(t.resolved)
else:
return set()