~pali/llvm/clang-tools-extra-trunk

« back to all changes in this revision

Viewing changes to clang-tidy/tool/clang-tidy-diff.py

  • Committer: dyung
  • Date: 2019-03-20 23:21:43 UTC
  • Revision ID: svn-v4:91177308-0d34-0410-b5e6-96231b3b80d8:clang-tools-extra/trunk:356630
Revert "Reland r356547 after fixing the tests for Linux."

This reverts commit 538fb72226cf6dff95af83f7777e12b8dbd061ea (r356565).

This is still breaking a build bot:
http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-ubuntu-fast/builds/45557

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
"""
25
25
 
26
26
import argparse
27
 
import glob
28
27
import json
29
 
import multiprocessing
30
 
import os
31
28
import re
32
 
import shutil
33
29
import subprocess
34
30
import sys
35
 
import tempfile
36
 
import threading
37
 
import traceback
38
 
import yaml
39
 
 
40
 
is_py2 = sys.version[0] == '2'
41
 
 
42
 
if is_py2:
43
 
    import Queue as queue
44
 
else:
45
 
    import queue as queue
46
 
 
47
 
 
48
 
def run_tidy(task_queue, lock, timeout):
49
 
  watchdog = None
50
 
  while True:
51
 
    command = task_queue.get()
52
 
    try:
53
 
      proc = subprocess.Popen(command,
54
 
                              stdout=subprocess.PIPE,
55
 
                              stderr=subprocess.PIPE)
56
 
 
57
 
      if timeout is not None:
58
 
        watchdog = threading.Timer(timeout, proc.kill)
59
 
        watchdog.start()
60
 
 
61
 
      stdout, stderr = proc.communicate()
62
 
 
63
 
      with lock:
64
 
        sys.stdout.write(stdout.decode('utf-8') + '\n')
65
 
        sys.stdout.flush()
66
 
        if stderr:
67
 
          sys.stderr.write(stderr.decode('utf-8') + '\n')
68
 
          sys.stderr.flush()
69
 
    except Exception as e:
70
 
      with lock:
71
 
        sys.stderr.write('Failed: ' + str(e) + ': '.join(command) + '\n')
72
 
    finally:
73
 
      with lock:
74
 
        if (not timeout is None) and (not watchdog is None):
75
 
          if not watchdog.is_alive():
76
 
              sys.stderr.write('Terminated by timeout: ' +
77
 
                               ' '.join(command) + '\n')
78
 
          watchdog.cancel()
79
 
      task_queue.task_done()
80
 
 
81
 
 
82
 
def start_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
83
 
  for _ in range(max_tasks):
84
 
    t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
85
 
    t.daemon = True
86
 
    t.start()
87
 
 
88
 
def merge_replacement_files(tmpdir, mergefile):
89
 
  """Merge all replacement files in a directory into a single file"""
90
 
  # The fixes suggested by clang-tidy >= 4.0.0 are given under
91
 
  # the top level key 'Diagnostics' in the output yaml files
92
 
  mergekey = "Diagnostics"
93
 
  merged = []
94
 
  for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
95
 
    content = yaml.safe_load(open(replacefile, 'r'))
96
 
    if not content:
97
 
      continue # Skip empty files.
98
 
    merged.extend(content.get(mergekey, []))
99
 
 
100
 
  if merged:
101
 
    # MainSourceFile: The key is required by the definition inside
102
 
    # include/clang/Tooling/ReplacementsYaml.h, but the value
103
 
    # is actually never used inside clang-apply-replacements,
104
 
    # so we set it to '' here.
105
 
    output = { 'MainSourceFile': '', mergekey: merged }
106
 
    with open(mergefile, 'w') as out:
107
 
      yaml.safe_dump(output, out)
108
 
  else:
109
 
    # Empty the file:
110
 
    open(mergefile, 'w').close()
111
31
 
112
32
 
113
33
def main():
127
47
                      r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
128
48
                      help='custom pattern selecting file paths to check '
129
49
                      '(case insensitive, overridden by -regex)')
130
 
  parser.add_argument('-j', type=int, default=1,
131
 
                      help='number of tidy instances to be run in parallel.')
132
 
  parser.add_argument('-timeout', type=int, default=None,
133
 
                      help='timeout per each file in seconds.')
 
50
 
134
51
  parser.add_argument('-fix', action='store_true', default=False,
135
52
                      help='apply suggested fixes')
136
53
  parser.add_argument('-checks',
167
84
    match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
168
85
    if match:
169
86
      filename = match.group(2)
170
 
    if filename is None:
 
87
    if filename == None:
171
88
      continue
172
89
 
173
90
    if args.regex is not None:
185
102
        line_count = int(match.group(3))
186
103
      if line_count == 0:
187
104
        continue
188
 
      end_line = start_line + line_count - 1
 
105
      end_line = start_line + line_count - 1;
189
106
      lines_by_file.setdefault(filename, []).append([start_line, end_line])
190
107
 
191
 
  if not any(lines_by_file):
 
108
  if len(lines_by_file) == 0:
192
109
    print("No relevant changes found.")
193
110
    sys.exit(0)
194
111
 
195
 
  max_task_count = args.j
196
 
  if max_task_count == 0:
197
 
      max_task_count = multiprocessing.cpu_count()
198
 
  max_task_count = min(len(lines_by_file), max_task_count)
199
 
 
200
 
  tmpdir = None
201
 
  if args.export_fixes:
202
 
    tmpdir = tempfile.mkdtemp()
203
 
 
204
 
  # Tasks for clang-tidy.
205
 
  task_queue = queue.Queue(max_task_count)
206
 
  # A lock for console output.
207
 
  lock = threading.Lock()
208
 
 
209
 
  # Run a pool of clang-tidy workers.
210
 
  start_workers(max_task_count, run_tidy, task_queue, lock, args.timeout)
211
 
 
212
 
  # Form the common args list.
213
 
  common_clang_tidy_args = []
 
112
  line_filter_json = json.dumps(
 
113
    [{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
 
114
    separators = (',', ':'))
 
115
 
 
116
  quote = "";
 
117
  if sys.platform == 'win32':
 
118
    line_filter_json=re.sub(r'"', r'"""', line_filter_json)
 
119
  else:
 
120
    quote = "'";
 
121
 
 
122
  # Run clang-tidy on files containing changes.
 
123
  command = [args.clang_tidy_binary]
 
124
  command.append('-line-filter=' + quote + line_filter_json + quote)
214
125
  if args.fix:
215
 
    common_clang_tidy_args.append('-fix')
 
126
    command.append('-fix')
 
127
  if args.export_fixes:
 
128
    command.append('-export-fixes=' + args.export_fixes)
216
129
  if args.checks != '':
217
 
    common_clang_tidy_args.append('-checks=' + args.checks)
 
130
    command.append('-checks=' + quote + args.checks + quote)
218
131
  if args.quiet:
219
 
    common_clang_tidy_args.append('-quiet')
 
132
    command.append('-quiet')
220
133
  if args.build_path is not None:
221
 
    common_clang_tidy_args.append('-p=%s' % args.build_path)
 
134
    command.append('-p=%s' % args.build_path)
 
135
  command.extend(lines_by_file.keys())
222
136
  for arg in args.extra_arg:
223
 
    common_clang_tidy_args.append('-extra-arg=%s' % arg)
 
137
      command.append('-extra-arg=%s' % arg)
224
138
  for arg in args.extra_arg_before:
225
 
    common_clang_tidy_args.append('-extra-arg-before=%s' % arg)
226
 
 
227
 
  for name in lines_by_file:
228
 
    line_filter_json = json.dumps(
229
 
      [{"name": name, "lines": lines_by_file[name]}],
230
 
      separators=(',', ':'))
231
 
 
232
 
    # Run clang-tidy on files containing changes.
233
 
    command = [args.clang_tidy_binary]
234
 
    command.append('-line-filter=' + line_filter_json)
235
 
    if args.export_fixes:
236
 
      # Get a temporary file. We immediately close the handle so clang-tidy can
237
 
      # overwrite it.
238
 
      (handle, tmp_name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
239
 
      os.close(handle)
240
 
      command.append('-export-fixes=' + tmp_name)
241
 
    command.extend(common_clang_tidy_args)
242
 
    command.append(name)
243
 
    command.extend(clang_tidy_args)
244
 
 
245
 
    task_queue.put(command)
246
 
 
247
 
  # Wait for all threads to be done.
248
 
  task_queue.join()
249
 
 
250
 
  if args.export_fixes:
251
 
    print('Writing fixes to ' + args.export_fixes + ' ...')
252
 
    try:
253
 
      merge_replacement_files(tmpdir, args.export_fixes)
254
 
    except:
255
 
      sys.stderr.write('Error exporting fixes.\n')
256
 
      traceback.print_exc()
257
 
 
258
 
  if tmpdir:
259
 
    shutil.rmtree(tmpdir)
260
 
 
 
139
      command.append('-extra-arg-before=%s' % arg)
 
140
  command.extend(clang_tidy_args)
 
141
 
 
142
  sys.exit(subprocess.call(' '.join(command), shell=True))
261
143
 
262
144
if __name__ == '__main__':
263
145
  main()