Index: tools/telemetry/third_party/rope/rope/refactor/encapsulate_field.py |
diff --git a/tools/telemetry/third_party/rope/rope/refactor/encapsulate_field.py b/tools/telemetry/third_party/rope/rope/refactor/encapsulate_field.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..32cb7a957b5f3a61de6dbaeda52c49fb143f78b3 |
--- /dev/null |
+++ b/tools/telemetry/third_party/rope/rope/refactor/encapsulate_field.py |
@@ -0,0 +1,209 @@ |
+from rope.base import evaluate |
+from rope.base import exceptions |
+from rope.base import libutils |
+from rope.base import pynames |
+from rope.base import taskhandle |
+from rope.base import utils |
+from rope.base import worder |
+from rope.base.change import ChangeSet, ChangeContents |
+from rope.refactor import sourceutils, occurrences |
+ |
+ |
+class EncapsulateField(object): |
+ |
+ def __init__(self, project, resource, offset): |
+ self.project = project |
+ self.name = worder.get_name_at(resource, offset) |
+ this_pymodule = self.project.get_pymodule(resource) |
+ self.pyname = evaluate.eval_location(this_pymodule, offset) |
+ if not self._is_an_attribute(self.pyname): |
+ raise exceptions.RefactoringError( |
+ 'Encapsulate field should be performed on class attributes.') |
+ self.resource = self.pyname.get_definition_location()[0].get_resource() |
+ |
+ def get_changes(self, getter=None, setter=None, resources=None, |
+ task_handle=taskhandle.NullTaskHandle()): |
+ """Get the changes this refactoring makes |
+ |
+ If `getter` is not `None`, that will be the name of the |
+ getter, otherwise ``get_${field_name}`` will be used. The |
+ same is true for `setter` and if it is None set_${field_name} is |
+ used. |
+ |
+ `resources` can be a list of `rope.base.resource.File`\s that |
+ the refactoring should be applied on; if `None` all python |
+ files in the project are searched. |
+ |
+ """ |
+ if resources is None: |
+ resources = self.project.get_python_files() |
+ changes = ChangeSet('Encapsulate field <%s>' % self.name) |
+ job_set = task_handle.create_jobset('Collecting Changes', |
+ len(resources)) |
+ if getter is None: |
+ getter = 'get_' + self.name |
+ if setter is None: |
+ setter = 'set_' + self.name |
+ renamer = GetterSetterRenameInModule( |
+ self.project, self.name, self.pyname, getter, setter) |
+ for file in resources: |
+ job_set.started_job(file.path) |
+ if file == self.resource: |
+ result = self._change_holding_module(changes, renamer, |
+ getter, setter) |
+ changes.add_change(ChangeContents(self.resource, result)) |
+ else: |
+ result = renamer.get_changed_module(file) |
+ if result is not None: |
+ changes.add_change(ChangeContents(file, result)) |
+ job_set.finished_job() |
+ return changes |
+ |
+ def get_field_name(self): |
+ """Get the name of the field to be encapsulated""" |
+ return self.name |
+ |
+ def _is_an_attribute(self, pyname): |
+ if pyname is not None and isinstance(pyname, pynames.AssignedName): |
+ pymodule, lineno = self.pyname.get_definition_location() |
+ scope = pymodule.get_scope().\ |
+ get_inner_scope_for_line(lineno) |
+ if scope.get_kind() == 'Class': |
+ return pyname in scope.get_names().values() |
+ parent = scope.parent |
+ if parent is not None and parent.get_kind() == 'Class': |
+ return pyname in parent.get_names().values() |
+ return False |
+ |
+ def _get_defining_class_scope(self): |
+ defining_scope = self._get_defining_scope() |
+ if defining_scope.get_kind() == 'Function': |
+ defining_scope = defining_scope.parent |
+ return defining_scope |
+ |
+ def _get_defining_scope(self): |
+ pymodule, line = self.pyname.get_definition_location() |
+ return pymodule.get_scope().get_inner_scope_for_line(line) |
+ |
+ def _change_holding_module(self, changes, renamer, getter, setter): |
+ pymodule = self.project.get_pymodule(self.resource) |
+ class_scope = self._get_defining_class_scope() |
+ defining_object = self._get_defining_scope().pyobject |
+ start, end = sourceutils.get_body_region(defining_object) |
+ |
+ new_source = renamer.get_changed_module(pymodule=pymodule, |
+ skip_start=start, skip_end=end) |
+ if new_source is not None: |
+ pymodule = libutils.get_string_module( |
+ self.project, new_source, self.resource) |
+ class_scope = pymodule.get_scope().\ |
+ get_inner_scope_for_line(class_scope.get_start()) |
+ indents = sourceutils.get_indent(self.project) * ' ' |
+ getter = 'def %s(self):\n%sreturn self.%s' % \ |
+ (getter, indents, self.name) |
+ setter = 'def %s(self, value):\n%sself.%s = value' % \ |
+ (setter, indents, self.name) |
+ new_source = sourceutils.add_methods(pymodule, class_scope, |
+ [getter, setter]) |
+ return new_source |
+ |
+ |
+class GetterSetterRenameInModule(object): |
+ |
+ def __init__(self, project, name, pyname, getter, setter): |
+ self.project = project |
+ self.name = name |
+ self.finder = occurrences.create_finder(project, name, pyname) |
+ self.getter = getter |
+ self.setter = setter |
+ |
+ def get_changed_module(self, resource=None, pymodule=None, |
+ skip_start=0, skip_end=0): |
+ change_finder = _FindChangesForModule(self, resource, pymodule, |
+ skip_start, skip_end) |
+ return change_finder.get_changed_module() |
+ |
+ |
+class _FindChangesForModule(object): |
+ |
+ def __init__(self, finder, resource, pymodule, skip_start, skip_end): |
+ self.project = finder.project |
+ self.finder = finder.finder |
+ self.getter = finder.getter |
+ self.setter = finder.setter |
+ self.resource = resource |
+ self.pymodule = pymodule |
+ self.last_modified = 0 |
+ self.last_set = None |
+ self.set_index = None |
+ self.skip_start = skip_start |
+ self.skip_end = skip_end |
+ |
+ def get_changed_module(self): |
+ result = [] |
+ for occurrence in self.finder.find_occurrences(self.resource, |
+ self.pymodule): |
+ start, end = occurrence.get_word_range() |
+ if self.skip_start <= start < self.skip_end: |
+ continue |
+ self._manage_writes(start, result) |
+ result.append(self.source[self.last_modified:start]) |
+ if self._is_assigned_in_a_tuple_assignment(occurrence): |
+ raise exceptions.RefactoringError( |
+ 'Cannot handle tuple assignments in encapsulate field.') |
+ if occurrence.is_written(): |
+ assignment_type = self.worder.get_assignment_type(start) |
+ if assignment_type == '=': |
+ result.append(self.setter + '(') |
+ else: |
+ var_name = self.source[occurrence.get_primary_range()[0]: |
+ start] + self.getter + '()' |
+ result.append(self.setter + '(' + var_name |
+ + ' %s ' % assignment_type[:-1]) |
+ current_line = self.lines.get_line_number(start) |
+ start_line, end_line = self.pymodule.logical_lines.\ |
+ logical_line_in(current_line) |
+ self.last_set = self.lines.get_line_end(end_line) |
+ end = self.source.index('=', end) + 1 |
+ self.set_index = len(result) |
+ else: |
+ result.append(self.getter + '()') |
+ self.last_modified = end |
+ if self.last_modified != 0: |
+ self._manage_writes(len(self.source), result) |
+ result.append(self.source[self.last_modified:]) |
+ return ''.join(result) |
+ return None |
+ |
+ def _manage_writes(self, offset, result): |
+ if self.last_set is not None and self.last_set <= offset: |
+ result.append(self.source[self.last_modified:self.last_set]) |
+ set_value = ''.join(result[self.set_index:]).strip() |
+ del result[self.set_index:] |
+ result.append(set_value + ')') |
+ self.last_modified = self.last_set |
+ self.last_set = None |
+ |
+ def _is_assigned_in_a_tuple_assignment(self, occurance): |
+ offset = occurance.get_word_range()[0] |
+ return self.worder.is_assigned_in_a_tuple_assignment(offset) |
+ |
+ @property |
+ @utils.saveit |
+ def source(self): |
+ if self.resource is not None: |
+ return self.resource.read() |
+ else: |
+ return self.pymodule.source_code |
+ |
+ @property |
+ @utils.saveit |
+ def lines(self): |
+ if self.pymodule is None: |
+ self.pymodule = self.project.get_pymodule(self.resource) |
+ return self.pymodule.lines |
+ |
+ @property |
+ @utils.saveit |
+ def worder(self): |
+ return worder.Worder(self.source) |