Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: tools/ui/dialog_audit.py

Issue 2675653002: Chrome dialog audit
Patch Set: Map a few more, and update at r449542 Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/ui/dialog_audit.cache ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 import csv
16
17 CLASS_UNKNOWN = '<class unknown>'
18 CLASS_UNKNOWN = '?'
19 VERBOSE = False
20
21 BLACKLIST = {
22 'ViewEventTestBase', # Has lots of uninteresting descendants in test files.
23 'TestDelegate', # Causes infinite recursion.
24 'UI' # Used in mash/webtest/webtest.cc - confuses regex.
25 }
26
27 def InheritsRe(klass):
28 return r'public.*[: ]{}[, ]'.format(klass)
29
30 def ChildRe(klass):
31 return r'class ([\w :]+)\s*: [^{]*' + klass + r'[^{]*[{]'
32
33 def FindFilesInheritingFromClass(klass):
34 process = subprocess.Popen(['git', 'grep', '-l', InheritsRe(klass), '--',
35 '*.h', '*.mm', '*.cc'],
36 stdout=subprocess.PIPE)
37 return process.communicate()[0].splitlines()
38
39 def ToLine(lines, offset):
40 line = 0
41 pos = 0
42 while pos < offset[0]:
43 pos += len(lines[line])
44 line += 1
45 return line
46
47 def FindClassesInFilesInheritingFromClass(files, klass):
48 children = []
49 child_re = re.compile(ChildRe(klass), re.MULTILINE)
50 for filename in files:
51 with open(filename, 'r+') as f:
52 lines = f.readlines()
53 text = " ".join([l[:-1] for l in lines])
54 found = child_re.finditer(text)
55 before = len(children)
56 for child in found:
57 child_klass = child.group(1).split()[-1]
58 children.append((child_klass, filename, ToLine(lines, child.span()),
59 re.sub(' +', ' ', child.group(0)), klass))
60 if len(children) == before:
61 sys.stderr.write(
62 "ERROR: Couldn't find a child of {} in {}\n".format(klass,
63 filename))
64 return children
65
66 def HuntForDecendants(result, parent, klasses, depth=''):
67 for klass in klasses:
68 if klass[0] in BLACKLIST:
69 sys.stderr.write('{}Skipping (blacklisted): {}\n'.format(depth, klass[0]))
70 continue
71
72 result.append(klass)
73 sys.stderr.write('{}{}'.format(depth, klass[0]))
74 files = FindFilesInheritingFromClass(klass[0])
75 children = FindClassesInFilesInheritingFromClass(files, klass[0])
76 sys.stderr.write( ' has {} children\n'.format(len(children)))
77 HuntForDecendants(result, klass, children, depth + ' ')
78
79 def DefaultHunt():
80 seed = 'WidgetDelegate'
81 #$seed = 'DialogDelegate'
82 #seed = 'DialogDelegateView'
83 #seed = 'LocationBarBubbleDelegateView'
84 result = []
85 HuntForDecendants(result, 'Seed', [(seed, '', 0, '', 'Seed')])
86 return result
87
88 def ToUrl(filename, klass, line):
89 return 'https://cs.chromium.org/chromium/src/{}?q={}&l={}'.format(
90 filename, klass, line)
91
92 def Hyperlink(klass, url):
93 return '=HYPERLINK("{}", "{}")'.format(url, klass)
94
95 def Process(data):
96 cells = eval("".join(open('tools/ui/cells.cache').readlines()))
97 newcells = []
98 cellmap = {}
99 for row in range(len(cells)):
100 ux_name = cells[row][1]
101 klass = cells[row][0]
102 if klass == '' and ux_name != '':
103 newcells.append([CLASS_UNKNOWN, ux_name])
104 print "Unmatched: {} {}".format(row, ux_name)
105 else:
106 cellmap.setdefault(klass, []).append(row)
107 newcells.append([klass, ux_name])
108 print ""
109 ignored = []
110 parents = {}
111 missing = {}
112 dupe_check = {}
113 for (klass, filename, line, match, parent) in data:
114 # Ignore test files
115 if filename.find('test.') > 0:
116 ignored.append((klass, filename))
117 continue
118
119 dupe_check.setdefault(klass, []).append(filename)
120 if len(dupe_check[klass]) > 1:
121 print "WARNING: {} found in {}".format(klass, dupe_check[klass])
122
123 # Track classes that have children and ignore them.
124 parents.setdefault(parent, [('f', 'c', 0, 'p'), []])[1].append(klass)
125 if parent in missing:
126 parents[parent][0] = missing[parent]
127 del missing[parent]
128
129 url = ToUrl(filename, klass, line)
130 if klass in cellmap:
131 for row in cellmap[klass]:
132 newcells[row][0] = Hyperlink(klass, url)
133 newcells[row].append(filename)
134 newcells[row].append(parent)
135 if VERBOSE:
136 print 'Matched: {}'.format(klass)
137 continue
138
139 missing[klass] = (filename, klass, line, parent)
140
141 sys.stderr.write('\nIgnored (Tests):')
142 for ignore in ignored:
143 sys.stderr.write(' {}({})'.format(ignore[0], os.path.basename(ignore[1])))
144 sys.stderr.write('\n')
145
146 sys.stderr.write('\nIgnored (Parents):')
147 for pk in parents:
148 parent = parents[pk]
149 filename, klass, line, p = parent[0]
150 children = " ".join(parent[1])
151 basename = os.path.basename(filename)
152 sys.stderr.write('\n\t {}({}): {}'.format(pk, basename, children))
153 sys.stderr.write('\n')
154
155 # Sort by filename.
156 missing_list = missing.values()
157 missing_list.sort()
158
159 # Write out CSV
160 with open('tools/ui/sheet.csv', 'wb') as csvfile:
161 writer = csv.writer(csvfile, dialect='excel-tab')
162 for row in range(len(cells)):
163 if row == 0:
164 writer.writerow(['DialogClass', 'Description', 'File', 'ParentClass',
165 'Children'])
166 continue
167 writer.writerow(newcells[row])
168
169 for m in missing_list:
170 filename, klass, line, parent = m
171 url = ToUrl(filename, klass, line)
172 missing_text = 'What is this?'
173 writer.writerow([Hyperlink(klass, url), missing_text, filename, parent])
174 print 'Missing: {:40} from {}'.format(klass, url)
175
176 for pk in parents:
177 filename, klass, line, parent = parents[pk][0]
178 url = ToUrl(filename, klass, line)
179 num_children = len(parents[pk][1])
180 parent_text = 'Has {} Child{}'.format(num_children,
181 num_children != 1 and "ren" or "")
182 writer.writerow([Hyperlink(klass, url), parent_text, filename, parent,
183 ",".join(parents[pk][1])])
184 for ignore in ignored:
185 writer.writerow([ignore[0], '<test>', ignore[1]])
186
187 def main():
188 try:
189 data = eval(open('tools/ui/dialog_audit.cache').readline())
190 Process(data)
191 except IOError as e:
192 data = DefaultHunt()
193 print data
194 sys.stderr.write("""
195 Try `tools/ui/dialog_audit.py > tools/ui/dialog_audit.cache.new && \
196 mv tools/ui/dialog_audit.cache.new tools/ui/dialog_audit.cache`
197 """)
198
199 if __name__ == '__main__':
200 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/ui/dialog_audit.cache ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698