| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """ |
| 7 Systematically search the Chrome codebase for dialog invocations. |
| 8 """ |
| 9 |
| 10 import subprocess |
| 11 import sys |
| 12 import re |
| 13 import mmap |
| 14 import os |
| 15 |
| 16 def InheritsRe(klass): |
| 17 return r'public.*[: ]{}[, ]'.format(klass) |
| 18 |
| 19 def ChildRe(klass): |
| 20 return r'class ([\w :]+)\s*:[^{]*' + klass + r'[^{]*[{]' |
| 21 |
| 22 def FindFilesInheritingFromClass(klass): |
| 23 process = subprocess.Popen(['git', 'grep', '-l', InheritsRe(klass), '--', |
| 24 '*.h', '*.mm', '*.cc'], |
| 25 stdout=subprocess.PIPE) |
| 26 return process.communicate()[0].splitlines(); |
| 27 |
| 28 def ToLine(lines, offset): |
| 29 line = 0 |
| 30 pos = 0 |
| 31 while pos < offset[0]: |
| 32 pos += len(lines[line]) |
| 33 line += 1 |
| 34 return line |
| 35 |
| 36 def FindClassesInFilesInheritingFromClass(files, klass): |
| 37 children = [] |
| 38 child_re = re.compile(ChildRe(klass), re.MULTILINE) |
| 39 for filename in files: |
| 40 with open(filename, 'r+') as f: |
| 41 lines = f.readlines() |
| 42 text = " ".join([l[:-1] for l in lines]) |
| 43 found = child_re.finditer(text) |
| 44 before = len(children) |
| 45 for child in found: |
| 46 child_klass = child.group(1).split()[-1] |
| 47 children.append((child_klass, filename, ToLine(lines, child.span()), |
| 48 re.sub(' +', ' ', child.group(0)), klass)) |
| 49 if len(children) == before: |
| 50 sys.stderr.write( |
| 51 "ERROR: Couldn't find a child of {} in {}\n".format(klass, |
| 52 filename)) |
| 53 return children |
| 54 |
| 55 def HuntForDecendants(result, parent, klasses, depth=''): |
| 56 for klass in klasses: |
| 57 result.append(klass) |
| 58 sys.stderr.write('{}{}'.format(depth, klass[0])) |
| 59 files = FindFilesInheritingFromClass(klass[0]) |
| 60 children = FindClassesInFilesInheritingFromClass(files, klass[0]); |
| 61 sys.stderr.write( ' has {} children\n'.format(len(children))) |
| 62 HuntForDecendants(result, klass, children, depth + ' ') |
| 63 |
| 64 def DefaultHunt(): |
| 65 seed = 'DialogDelegate' |
| 66 #seed = 'DialogDelegateView' |
| 67 #seed = 'LocationBarBubbleDelegateView' |
| 68 result = [] |
| 69 HuntForDecendants(result, 'Seed', [(seed, '', 0, '', 'Seed')]) |
| 70 return result |
| 71 |
| 72 def ToUrl(filename, klass, line): |
| 73 return 'https://cs.chromium.org/chromium/src/{}?q={}&l={}'.format( |
| 74 filename, klass, line) |
| 75 |
| 76 def Process(data): |
| 77 cells = eval("".join(open('tools/ui/cells.cache').readlines())) |
| 78 cellmap = {} |
| 79 for row in range(len(cells)): |
| 80 if cells[row][0] == '' and cells[row][1] != '': |
| 81 print "Unmatched: {} {}".format(row, cells[row][1]) |
| 82 else: |
| 83 cellmap[cells[row][0]] = row |
| 84 ignored = [] |
| 85 parents = {} |
| 86 missing = {} |
| 87 for (klass, filename, line, match, parent) in data: |
| 88 if klass in cellmap: |
| 89 row = cells[cellmap[klass]] |
| 90 cells[cellmap[klass]] = (row[1], klass, ) |
| 91 print 'Matched: {}'.format(klass) |
| 92 continue |
| 93 |
| 94 # Ignore test files |
| 95 if filename.find('test.') > 0: |
| 96 ignored.append((klass, filename)) |
| 97 continue |
| 98 |
| 99 # Track classes that have children and ignore them. |
| 100 parents.setdefault(parent, [('f', 'c', 0), []])[1].append(klass) |
| 101 if parent in missing: |
| 102 parents[parent][0] = missing[parent] |
| 103 del missing[parent] |
| 104 continue |
| 105 |
| 106 missing[klass] = (filename, klass, line) |
| 107 |
| 108 sys.stderr.write('\nIgnored (Tests):') |
| 109 for ignore in ignored: |
| 110 sys.stderr.write(' {}({})'.format(ignore[0], os.path.basename(ignore[1]))) |
| 111 sys.stderr.write('\n') |
| 112 |
| 113 sys.stderr.write('\nIgnored (Parents):') |
| 114 for pk in parents: |
| 115 parent = parents[pk] |
| 116 filename, klass, line = parent[0] |
| 117 children = " ".join(parent[1]) |
| 118 basename = os.path.basename(filename) |
| 119 sys.stderr.write('\n\t {}({}): {}'.format(pk, basename, children)) |
| 120 sys.stderr.write('\n') |
| 121 |
| 122 # Sort by filename. |
| 123 missing_list = missing.values() |
| 124 missing_list.sort(); |
| 125 |
| 126 for m in missing_list: |
| 127 (filename, klass, line) = m |
| 128 print 'Missing: {:40} from {}'.format(klass, ToUrl(filename, klass, line)) |
| 129 |
| 130 def main(): |
| 131 try: |
| 132 data = eval(open('tools/ui/dialog_audit.cache').readline()) |
| 133 Process(data) |
| 134 except IOError as e: |
| 135 data = DefaultHunt() |
| 136 print data |
| 137 sys.stderr.write(""" |
| 138 Try `tools/ui/dialog_audit.py > tools/ui/dialog_audit.cache.new && \ |
| 139 mv tools/ui/dialog_audit.cache.new tools/ui/dialog_audit.cache` |
| 140 """) |
| 141 |
| 142 if __name__ == '__main__': |
| 143 sys.exit(main()) |
| OLD | NEW |