wildcards.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. from rope.base import ast, evaluate, builtins, pyobjects
  2. from rope.refactor import patchedast, occurrences
  3. class Wildcard(object):
  4. def get_name(self):
  5. """Return the name of this wildcard"""
  6. def matches(self, suspect, arg):
  7. """Return `True` if `suspect` matches this wildcard"""
  8. class Suspect(object):
  9. def __init__(self, pymodule, node, name):
  10. self.name = name
  11. self.pymodule = pymodule
  12. self.node = node
  13. class DefaultWildcard(object):
  14. """The default restructuring wildcard
  15. The argument passed to this wildcard is in the
  16. ``key1=value1,key2=value2,...`` format. Possible keys are:
  17. * name - for checking the reference
  18. * type - for checking the type
  19. * object - for checking the object
  20. * instance - for checking types but similar to builtin isinstance
  21. * exact - matching only occurrences with the same name as the wildcard
  22. * unsure - matching unsure occurrences
  23. """
  24. def __init__(self, project):
  25. self.project = project
  26. def get_name(self):
  27. return 'default'
  28. def matches(self, suspect, arg=''):
  29. args = parse_arg(arg)
  30. if not self._check_exact(args, suspect):
  31. return False
  32. if not self._check_object(args, suspect):
  33. return False
  34. return True
  35. def _check_object(self, args, suspect):
  36. kind = None
  37. expected = None
  38. unsure = args.get('unsure', False)
  39. for check in ['name', 'object', 'type', 'instance']:
  40. if check in args:
  41. kind = check
  42. expected = args[check]
  43. if expected is not None:
  44. checker = _CheckObject(self.project, expected,
  45. kind, unsure=unsure)
  46. return checker(suspect.pymodule, suspect.node)
  47. return True
  48. def _check_exact(self, args, suspect):
  49. node = suspect.node
  50. if args.get('exact'):
  51. if not isinstance(node, ast.Name) or not node.id == suspect.name:
  52. return False
  53. else:
  54. if not isinstance(node, ast.expr):
  55. return False
  56. return True
  57. def parse_arg(arg):
  58. if isinstance(arg, dict):
  59. return arg
  60. result = {}
  61. tokens = arg.split(',')
  62. for token in tokens:
  63. if '=' in token:
  64. parts = token.split('=', 1)
  65. result[parts[0].strip()] = parts[1].strip()
  66. else:
  67. result[token.strip()] = True
  68. return result
  69. class _CheckObject(object):
  70. def __init__(self, project, expected, kind='object', unsure=False):
  71. self.project = project
  72. self.kind = kind
  73. self.unsure = unsure
  74. self.expected = self._evaluate(expected)
  75. def __call__(self, pymodule, node):
  76. pyname = self._evaluate_node(pymodule, node)
  77. if pyname is None or self.expected is None:
  78. return self.unsure
  79. if self._unsure_pyname(pyname, unbound=self.kind=='name'):
  80. return True
  81. if self.kind == 'name':
  82. return self._same_pyname(self.expected, pyname)
  83. else:
  84. pyobject = pyname.get_object()
  85. if self.kind == 'object':
  86. objects = [pyobject]
  87. if self.kind == 'type':
  88. objects = [pyobject.get_type()]
  89. if self.kind == 'instance':
  90. objects = [pyobject]
  91. objects.extend(self._get_super_classes(pyobject))
  92. objects.extend(self._get_super_classes(pyobject.get_type()))
  93. for pyobject in objects:
  94. if self._same_pyobject(self.expected.get_object(), pyobject):
  95. return True
  96. return False
  97. def _get_super_classes(self, pyobject):
  98. result = []
  99. if isinstance(pyobject, pyobjects.AbstractClass):
  100. for superclass in pyobject.get_superclasses():
  101. result.append(superclass)
  102. result.extend(self._get_super_classes(superclass))
  103. return result
  104. def _same_pyobject(self, expected, pyobject):
  105. return expected == pyobject
  106. def _same_pyname(self, expected, pyname):
  107. return occurrences.same_pyname(expected, pyname)
  108. def _unsure_pyname(self, pyname, unbound=True):
  109. return self.unsure and occurrences.unsure_pyname(pyname, unbound)
  110. def _split_name(self, name):
  111. parts = name.split('.')
  112. expression, kind = parts[0], parts[-1]
  113. if len(parts) == 1:
  114. kind = 'name'
  115. return expression, kind
  116. def _evaluate_node(self, pymodule, node):
  117. scope = pymodule.get_scope().get_inner_scope_for_line(node.lineno)
  118. expression = node
  119. if isinstance(expression, ast.Name) and \
  120. isinstance(expression.ctx, ast.Store):
  121. start, end = patchedast.node_region(expression)
  122. text = pymodule.source_code[start:end]
  123. return evaluate.eval_str(scope, text)
  124. else:
  125. return evaluate.eval_node(scope, expression)
  126. def _evaluate(self, code):
  127. attributes = code.split('.')
  128. pyname = None
  129. if attributes[0] in ('__builtin__', '__builtins__'):
  130. class _BuiltinsStub(object):
  131. def get_attribute(self, name):
  132. return builtins.builtins[name]
  133. def __getitem__(self, name):
  134. return builtins.builtins[name]
  135. def __contains__(self, name):
  136. return name in builtins.builtins
  137. pyobject = _BuiltinsStub()
  138. else:
  139. pyobject = self.project.pycore.get_module(attributes[0])
  140. for attribute in attributes[1:]:
  141. pyname = pyobject[attribute]
  142. if pyname is None:
  143. return None
  144. pyobject = pyname.get_object()
  145. return pyname