lookup.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. """
  2. This is a module for various lookup functions:
  3. functions that will find a semantic node by its name.
  4. """
  5. from __future__ import annotations
  6. from mypy.nodes import MypyFile, SymbolTableNode, TypeInfo
  7. # TODO: gradually move existing lookup functions to this module.
  8. def lookup_fully_qualified(
  9. name: str, modules: dict[str, MypyFile], *, raise_on_missing: bool = False
  10. ) -> SymbolTableNode | None:
  11. """Find a symbol using it fully qualified name.
  12. The algorithm has two steps: first we try splitting the name on '.' to find
  13. the module, then iteratively look for each next chunk after a '.' (e.g. for
  14. nested classes).
  15. This function should *not* be used to find a module. Those should be looked
  16. in the modules dictionary.
  17. """
  18. head = name
  19. rest = []
  20. # 1. Find a module tree in modules dictionary.
  21. while True:
  22. if "." not in head:
  23. if raise_on_missing:
  24. assert "." in head, f"Cannot find module for {name}"
  25. return None
  26. head, tail = head.rsplit(".", maxsplit=1)
  27. rest.append(tail)
  28. mod = modules.get(head)
  29. if mod is not None:
  30. break
  31. names = mod.names
  32. # 2. Find the symbol in the module tree.
  33. if not rest:
  34. # Looks like a module, don't use this to avoid confusions.
  35. if raise_on_missing:
  36. assert rest, f"Cannot find {name}, got a module symbol"
  37. return None
  38. while True:
  39. key = rest.pop()
  40. if key not in names:
  41. if raise_on_missing:
  42. assert key in names, f"Cannot find component {key!r} for {name!r}"
  43. return None
  44. stnode = names[key]
  45. if not rest:
  46. return stnode
  47. node = stnode.node
  48. # In fine-grained mode, could be a cross-reference to a deleted module
  49. # or a Var made up for a missing module.
  50. if not isinstance(node, TypeInfo):
  51. if raise_on_missing:
  52. assert node, f"Cannot find {name}"
  53. return None
  54. names = node.names