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

Side by Side Diff: tools/unused-grit-header.py

Issue 524743002: More unused grit header script improvements: (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@grit_clean_chromium_strings_401588_a_remove
Patch Set: Created 6 years, 3 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/resources/list_unused_grit_header.py ('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 2014 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 """A tool to scan source files for unneeded grit includes."""
7
8 import os
9 import sys
10 import xml.etree.ElementTree
11
12 IF_ELSE_TAGS = ('if', 'else')
13
14
15 def Usage(prog_name):
16 print prog_name, 'GRD_FILE DIRS_TO_SCAN'
17
18
19 def GetResourcesForNode(node, parent_file, resource_tag):
20 """Recursively iterate through a node and extract resource names.
21
22 Args:
23 node: The node to iterate through.
24 parent_file: The file that contains node.
25 resource_tag: The resource tag to extract names from.
26
27 Returns:
28 A list of resource names.
29 """
30 resources = []
31 for child in node.getchildren():
32 if child.tag == resource_tag:
33 resources.append(child.attrib['name'])
34 elif child.tag in IF_ELSE_TAGS:
35 resources.extend(GetResourcesForNode(child, parent_file, resource_tag))
36 elif child.tag == 'part':
37 parent_dir = os.path.dirname(parent_file)
38 part_file = os.path.join(parent_dir, child.attrib['file'])
39 part_tree = xml.etree.ElementTree.parse(part_file)
40 part_root = part_tree.getroot()
41 assert part_root.tag == 'grit-part'
42 resources.extend(GetResourcesForNode(part_root, part_file, resource_tag))
43 else:
44 raise Exception('unknown tag:', child.tag)
45 return resources
46
47
48 def FindNodeWithTag(node, tag):
49 """Look through a node's children for a child node with a given tag.
50
51 Args:
52 root: The node to examine.
53 tag: The tag on a child node to look for.
54
55 Returns:
56 A child node with the given tag, or None.
57 """
58 result = None
59 for n in node.getchildren():
60 if n.tag == tag:
61 assert not result
62 result = n
63 return result
64
65
66 def GetResourcesForGrdFile(tree, grd_file):
67 """Find all the message and include resources from a given grit file.
68
69 Args:
70 tree: The XML tree.
71 grd_file: The file that contains the XML tree.
72
73 Returns:
74 A list of resource names.
75 """
76 root = tree.getroot()
77 assert root.tag == 'grit'
78 release_node = FindNodeWithTag(root, 'release')
79 assert release_node != None
80
81 resources = set()
82 for node_type in ('message', 'include', 'structure'):
83 resources_node = FindNodeWithTag(release_node, node_type + 's')
84 if resources_node != None:
85 resources = resources.union(
86 set(GetResourcesForNode(resources_node, grd_file, node_type)))
87 return resources
88
89
90 def GetOutputFileForNode(node):
91 """Find the output file starting from a given node.
92
93 Args:
94 node: The root node to scan from.
95
96 Returns:
97 A grit header file name.
98 """
99 output_file = None
100 for child in node.getchildren():
101 if child.tag == 'output':
102 if child.attrib['type'] == 'rc_header':
103 assert output_file is None
104 output_file = child.attrib['filename']
105 elif child.tag in IF_ELSE_TAGS:
106 child_output_file = GetOutputFileForNode(child)
107 if not child_output_file:
108 continue
109 assert output_file is None
110 output_file = child_output_file
111 else:
112 raise Exception('unknown tag:', child.tag)
113 return output_file
114
115
116 def GetOutputHeaderFile(tree):
117 """Find the output file for a given tree.
118
119 Args:
120 tree: The tree to scan.
121
122 Returns:
123 A grit header file name.
124 """
125 root = tree.getroot()
126 assert root.tag == 'grit'
127 output_node = FindNodeWithTag(root, 'outputs')
128 assert output_node != None
129 return GetOutputFileForNode(output_node)
130
131
132 def ShouldScanFile(filename):
133 """Return if the filename has one of the extensions below."""
134 extensions = ['.cc', '.cpp', '.h', '.mm']
135 file_extension = os.path.splitext(filename)[1]
136 return file_extension in extensions
137
138
139 def NeedsGritInclude(grit_header, resources, filename):
140 """Return whether a file needs a given grit header or not.
141
142 Args:
143 grit_header: The grit header file name.
144 resources: The list of resource names in grit_header.
145 filename: The file to scan.
146
147 Returns:
148 True if the file should include the grit header.
149 """
150 # A list of special keywords that implies the file needs grit headers.
151 # To be more thorough, one would need to run a pre-processor.
152 SPECIAL_KEYWORDS = (
153 'IMAGE_GRID(', # Macro in nine_image_painter_factory.h
154 '#include "ui_localizer_table.h"', # ui_localizer.mm
155 'DEFINE_RESOURCE_ID', # chrome/browser/android/resource_mapper.cc
156 )
157 with open(filename, 'rb') as f:
158 grit_header_line = grit_header + '"\n'
159 has_grit_header = False
160 while True:
161 line = f.readline()
162 if not line:
163 break
164 if line.endswith(grit_header_line):
165 has_grit_header = True
166 break
167
168 if not has_grit_header:
169 return True
170 rest_of_the_file = f.read()
171 return (any(resource in rest_of_the_file for resource in resources) or
172 any(keyword in rest_of_the_file for keyword in SPECIAL_KEYWORDS))
173
174
175 def main(argv):
176 if len(argv) < 3:
177 Usage(argv[0])
178 return 1
179 grd_file = argv[1]
180 dirs_to_scan = argv[2:]
181 for f in dirs_to_scan:
182 if not os.path.exists(f):
183 print 'Error: %s does not exist' % f
184 return 1
185
186 tree = xml.etree.ElementTree.parse(grd_file)
187 grit_header = GetOutputHeaderFile(tree)
188 if not grit_header:
189 print 'Error: %s does not generate any output headers.' % grit_header
190 return 1
191 resources = GetResourcesForGrdFile(tree, grd_file)
192
193 files_with_unneeded_grit_includes = []
194 for dir_to_scan in dirs_to_scan:
195 for root, dirs, files in os.walk(dir_to_scan):
196 if '.git' in dirs:
197 dirs.remove('.git')
198 full_paths = [os.path.join(root, f) for f in files if ShouldScanFile(f)]
199 files_with_unneeded_grit_includes.extend(
200 [f for f in full_paths
201 if not NeedsGritInclude(grit_header, resources, f)])
202 if files_with_unneeded_grit_includes:
203 print '\n'.join(files_with_unneeded_grit_includes)
204 return 2
205 return 0
206
207
208 if __name__ == '__main__':
209 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « tools/resources/list_unused_grit_header.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698