Index: tools/telemetry/third_party/rope/rope/contrib/fixsyntax.py |
diff --git a/tools/telemetry/third_party/rope/rope/contrib/fixsyntax.py b/tools/telemetry/third_party/rope/rope/contrib/fixsyntax.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cc45ad19b3458a3a0cacfad11492dac828e32312 |
--- /dev/null |
+++ b/tools/telemetry/third_party/rope/rope/contrib/fixsyntax.py |
@@ -0,0 +1,181 @@ |
+import rope.base.codeanalyze |
+import rope.base.evaluate |
+from rope.base import exceptions |
+from rope.base import libutils |
+from rope.base import utils |
+from rope.base import worder |
+from rope.base.codeanalyze import ArrayLinesAdapter, LogicalLineFinder |
+ |
+ |
+class FixSyntax(object): |
+ |
+ def __init__(self, project, code, resource, maxfixes=1): |
+ self.project = project |
+ self.code = code |
+ self.resource = resource |
+ self.maxfixes = maxfixes |
+ |
+ @utils.saveit |
+ def get_pymodule(self): |
+ """Get a `PyModule`""" |
+ msg = None |
+ code = self.code |
+ tries = 0 |
+ while True: |
+ try: |
+ if tries == 0 and self.resource is not None and \ |
+ self.resource.read() == code: |
+ return self.project.get_pymodule(self.resource, |
+ force_errors=True) |
+ return libutils.get_string_module( |
+ self.project, code, resource=self.resource, |
+ force_errors=True) |
+ except exceptions.ModuleSyntaxError as e: |
+ if msg is None: |
+ msg = '%s:%s %s' % (e.filename, e.lineno, e.message_) |
+ if tries < self.maxfixes: |
+ tries += 1 |
+ self.commenter.comment(e.lineno) |
+ code = '\n'.join(self.commenter.lines) |
+ else: |
+ raise exceptions.ModuleSyntaxError( |
+ e.filename, e.lineno, |
+ 'Failed to fix error: {0}'.format(msg)) |
+ |
+ @property |
+ @utils.saveit |
+ def commenter(self): |
+ return _Commenter(self.code) |
+ |
+ def pyname_at(self, offset): |
+ pymodule = self.get_pymodule() |
+ |
+ def old_pyname(): |
+ word_finder = worder.Worder(self.code, True) |
+ expression = word_finder.get_primary_at(offset) |
+ expression = expression.replace('\\\n', ' ').replace('\n', ' ') |
+ lineno = self.code.count('\n', 0, offset) |
+ scope = pymodule.get_scope().get_inner_scope_for_line(lineno) |
+ return rope.base.evaluate.eval_str(scope, expression) |
+ new_code = pymodule.source_code |
+ |
+ def new_pyname(): |
+ newoffset = self.commenter.transfered_offset(offset) |
+ return rope.base.evaluate.eval_location(pymodule, newoffset) |
+ if new_code.startswith(self.code[:offset + 1]): |
+ return new_pyname() |
+ result = old_pyname() |
+ if result is None: |
+ return new_pyname() |
+ return result |
+ |
+ |
+class _Commenter(object): |
+ |
+ def __init__(self, code): |
+ self.code = code |
+ self.lines = self.code.split('\n') |
+ self.lines.append('\n') |
+ self.origs = range(len(self.lines) + 1) |
+ self.diffs = [0] * (len(self.lines) + 1) |
+ |
+ def comment(self, lineno): |
+ start = _logical_start(self.lines, lineno, check_prev=True) - 1 |
+ # using self._get_stmt_end() instead of self._get_block_end() |
+ # to lower commented lines |
+ end = self._get_stmt_end(start) |
+ indents = _get_line_indents(self.lines[start]) |
+ if 0 < start: |
+ last_lineno = self._last_non_blank(start - 1) |
+ last_line = self.lines[last_lineno] |
+ if last_line.rstrip().endswith(':'): |
+ indents = _get_line_indents(last_line) + 4 |
+ self._set(start, ' ' * indents + 'pass') |
+ for line in range(start + 1, end + 1): |
+ self._set(line, self.lines[start]) |
+ self._fix_incomplete_try_blocks(lineno, indents) |
+ |
+ def transfered_offset(self, offset): |
+ lineno = self.code.count('\n', 0, offset) |
+ diff = sum(self.diffs[:lineno]) |
+ return offset + diff |
+ |
+ def _last_non_blank(self, start): |
+ while start > 0 and self.lines[start].strip() == '': |
+ start -= 1 |
+ return start |
+ |
+ def _get_block_end(self, lineno): |
+ end_line = lineno |
+ base_indents = _get_line_indents(self.lines[lineno]) |
+ for i in range(lineno + 1, len(self.lines)): |
+ if _get_line_indents(self.lines[i]) >= base_indents: |
+ end_line = i |
+ else: |
+ break |
+ return end_line |
+ |
+ def _get_stmt_end(self, lineno): |
+ base_indents = _get_line_indents(self.lines[lineno]) |
+ for i in range(lineno + 1, len(self.lines)): |
+ if _get_line_indents(self.lines[i]) <= base_indents: |
+ return i - 1 |
+ return lineno |
+ |
+ def _fix_incomplete_try_blocks(self, lineno, indents): |
+ block_start = lineno |
+ last_indents = indents |
+ while block_start > 0: |
+ block_start = rope.base.codeanalyze.get_block_start( |
+ ArrayLinesAdapter(self.lines), block_start) - 1 |
+ if self.lines[block_start].strip().startswith('try:'): |
+ indents = _get_line_indents(self.lines[block_start]) |
+ if indents > last_indents: |
+ continue |
+ last_indents = indents |
+ block_end = self._find_matching_deindent(block_start) |
+ line = self.lines[block_end].strip() |
+ if not (line.startswith('finally:') or |
+ line.startswith('except ') or |
+ line.startswith('except:')): |
+ self._insert(block_end, ' ' * indents + 'finally:') |
+ self._insert(block_end + 1, ' ' * indents + ' pass') |
+ |
+ def _find_matching_deindent(self, line_number): |
+ indents = _get_line_indents(self.lines[line_number]) |
+ current_line = line_number + 1 |
+ while current_line < len(self.lines): |
+ line = self.lines[current_line] |
+ if not line.strip().startswith('#') and not line.strip() == '': |
+ # HACK: We should have used logical lines here |
+ if _get_line_indents(self.lines[current_line]) <= indents: |
+ return current_line |
+ current_line += 1 |
+ return len(self.lines) - 1 |
+ |
+ def _set(self, lineno, line): |
+ self.diffs[self.origs[lineno]] += len(line) - len(self.lines[lineno]) |
+ self.lines[lineno] = line |
+ |
+ def _insert(self, lineno, line): |
+ self.diffs[self.origs[lineno]] += len(line) + 1 |
+ self.origs.insert(lineno, self.origs[lineno]) |
+ self.lines.insert(lineno, line) |
+ |
+ |
+def _logical_start(lines, lineno, check_prev=False): |
+ logical_finder = LogicalLineFinder(ArrayLinesAdapter(lines)) |
+ if check_prev: |
+ prev = lineno - 1 |
+ while prev > 0: |
+ start, end = logical_finder.logical_line_in(prev) |
+ if end is None or start <= lineno < end: |
+ return start |
+ if start <= prev: |
+ break |
+ prev -= 1 |
+ return logical_finder.logical_line_in(lineno)[0] |
+ |
+ |
+def _get_line_indents(line): |
+ return rope.base.codeanalyze.count_line_indents(line) |