-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Detect and record implicit dependencies in incremental mode (#2041)
For full details see #2041
- Loading branch information
1 parent
7c76609
commit 5e822a8
Showing
12 changed files
with
920 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
from typing import Dict, Iterable, List, Optional, Set | ||
from abc import abstractmethod | ||
|
||
from mypy.visitor import NodeVisitor | ||
from mypy.types import TypeVisitor | ||
from mypy.nodes import MODULE_REF | ||
import mypy.nodes as nodes | ||
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(TypeVisitor[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, *typs: types.Type) -> Set[str]: | ||
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_error_type(self, t: types.ErrorType) -> Set[str]: | ||
return set() | ||
|
||
def visit_any(self, t: types.AnyType) -> Set[str]: | ||
return set() | ||
|
||
def visit_void(self, t: types.Void) -> Set[str]: | ||
return set() | ||
|
||
def visit_none_type(self, t: types.NoneTyp) -> 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 is not None: | ||
out.update(split_module_names(t.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.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) |
Oops, something went wrong.