File: apply_fixits.py

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (87 lines) | stat: -rwxr-xr-x 3,259 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/usr/bin/env python
# Copyright 2015 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Script to apply fixits generated by clang. This is to work around the fact
# that clang's -Xclang -fixit-recompile flag, which automatically applies fixits
# and recompiles, doesn't work well with parallel invocations of clang.
#
# Usage:
# 1. Enable parseable fixits and disable warnings as errors. Instructions for
#    doing this vary based on the build environment, but for GN, warnings as
#    errors can be disabled by setting treat_warnings_as_errors = false
#    Enabling parseable fixits requires editing build/config/compiler/BUILD.gn
#    and adding `-fdiagnostics-parseable-fixits` to cflags.
# 2. Build everything and capture the output:
#      ninja -C <build_directory> &> generated-fixits
# 3. Apply the fixits with this script:
#      python apply_fixits.py -p <build_directory> < generated-fixits

from __future__ import print_function

import argparse
import collections
import fileinput
import os
import re
import sys

# fix-it:"../../base/threading/sequenced_worker_pool.h":{341:3-341:11}:""
# Note that the file path is relative to the build directory.
_FIXIT_RE = re.compile(r'^fix-it:"(?P<file>.+?)":'
                       r'{(?P<start_line>\d+?):(?P<start_col>\d+?)-'
                       r'(?P<end_line>\d+?):(?P<end_col>\d+?)}:'
                       r'"(?P<text>.*?)"$')

FixIt = collections.namedtuple(
    'FixIt', ('start_line', 'start_col', 'end_line', 'end_col', 'text'))


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '-p',
      required=True,
      help='path to the build directory to complete relative paths in fixits')
  args = parser.parse_args()

  fixits = collections.defaultdict(list)
  for line in fileinput.input(['-']):
    if not line.startswith('fix-it:'):
      continue
    m = _FIXIT_RE.match(line)
    if not m:
      continue
    # The negative line numbers are a cheap hack so we can sort things in line
    # order but reverse column order. Applying the fixits in reverse order makes
    # things simpler, since offsets won't have to be adjusted as the text is
    # changed.
    fixits[m.group('file')].append(FixIt(
        int(m.group('start_line')), -int(m.group('start_col')), int(m.group(
            'end_line')), -int(m.group('end_col')), m.group('text')))
  for k, v in fixits.iteritems():
    v.sort()
    with open(os.path.join(args.p, k), 'rb+') as f:
      lines = f.readlines()
      last_fixit = None
      for fixit in v:
        if fixit.start_line != fixit.end_line:
          print('error: multiline fixits not supported! file: %s, fixit: %s' %
                (k, fixit))
          sys.exit(1)
        if fixit == last_fixit:
          continue
        last_fixit = fixit
        # The line/column numbers emitted in fixit hints start at 1, so offset
        # is appropriately.
        line = lines[fixit.start_line - 1]
        lines[fixit.start_line - 1] = (line[:-fixit.start_col - 1] + fixit.text
                                       + line[-fixit.end_col - 1:])
      f.seek(0)
      f.truncate()
      f.writelines(lines)


if __name__ == '__main__':
  sys.exit(main())