9
9
#
10
10
#===------------------------------------------------------------------------===#
11
11
12
- import os
13
- import glob
14
12
import argparse
13
+ import glob
14
+ import os
15
+ import re
15
16
16
17
17
18
def replaceInFile (fileName , sFrom , sTo ):
@@ -25,7 +26,7 @@ def replaceInFile(fileName, sFrom, sTo):
25
26
return
26
27
27
28
txt = txt .replace (sFrom , sTo )
28
- print ("Replace '%s' -> '%s' in '%s'" % (sFrom , sTo , fileName ))
29
+ print ("Replacing '%s' -> '%s' in '%s'... " % (sFrom , sTo , fileName ))
29
30
with open (fileName , "w" ) as f :
30
31
f .write (txt )
31
32
@@ -47,13 +48,28 @@ def generateCommentLineSource(filename):
47
48
48
49
49
50
def fileRename (fileName , sFrom , sTo ):
50
- if sFrom not in fileName :
51
+ if sFrom not in fileName or sFrom == sTo :
51
52
return fileName
52
53
newFileName = fileName .replace (sFrom , sTo )
53
- print ("Rename '%s' -> '%s'" % (fileName , newFileName ))
54
+ print ("Renaming '%s' -> '%s'... " % (fileName , newFileName ))
54
55
os .rename (fileName , newFileName )
55
56
return newFileName
56
57
58
+ def deleteMatchingLines (fileName , pattern ):
59
+ lines = None
60
+ with open (fileName , "r" ) as f :
61
+ lines = f .readlines ()
62
+
63
+ not_matching_lines = [l for l in lines if not re .search (pattern , l )]
64
+ if not_matching_lines .count == lines .count :
65
+ return False
66
+
67
+ print ("Removing lines matching '%s' in '%s'..." % (pattern , fileName ))
68
+ print (' ' + ' ' .join ([l for l in lines if re .search (pattern , l )]))
69
+ with open (fileName , "w" ) as f :
70
+ f .writelines (not_matching_lines )
71
+
72
+ return True
57
73
58
74
def getListOfFiles (clang_tidy_path ):
59
75
files = glob .glob (os .path .join (clang_tidy_path , '*' ))
@@ -66,43 +82,170 @@ def getListOfFiles(clang_tidy_path):
66
82
'clang-tidy' , 'checks' , '*' ))
67
83
return [filename for filename in files if os .path .isfile (filename )]
68
84
85
+ # Adapts the module's CMakelist file. Returns 'True' if it could add a new entry
86
+ # and 'False' if the entry already existed.
87
+ def adapt_cmake (module_path , check_name_camel ):
88
+ filename = os .path .join (module_path , 'CMakeLists.txt' )
89
+ with open (filename , 'r' ) as f :
90
+ lines = f .readlines ()
91
+
92
+ cpp_file = check_name_camel + '.cpp'
93
+
94
+ # Figure out whether this check already exists.
95
+ for line in lines :
96
+ if line .strip () == cpp_file :
97
+ return False
98
+
99
+ print ('Updating %s...' % filename )
100
+ with open (filename , 'wb' ) as f :
101
+ cpp_found = False
102
+ file_added = False
103
+ for line in lines :
104
+ cpp_line = line .strip ().endswith ('.cpp' )
105
+ if (not file_added ) and (cpp_line or cpp_found ):
106
+ cpp_found = True
107
+ if (line .strip () > cpp_file ) or (not cpp_line ):
108
+ f .write (' ' + cpp_file + '\n ' )
109
+ file_added = True
110
+ f .write (line )
111
+
112
+ return True
113
+
114
+ # Modifies the module to include the new check.
115
+ def adapt_module (module_path , module , check_name , check_name_camel ):
116
+ modulecpp = filter (lambda p : p .lower () == module .lower () + 'tidymodule.cpp' ,
117
+ os .listdir (module_path ))[0 ]
118
+ filename = os .path .join (module_path , modulecpp )
119
+ with open (filename , 'r' ) as f :
120
+ lines = f .readlines ()
121
+
122
+ print ('Updating %s...' % filename )
123
+ with open (filename , 'wb' ) as f :
124
+ header_added = False
125
+ header_found = False
126
+ check_added = False
127
+ check_decl = (' CheckFactories.registerCheck<' + check_name_camel +
128
+ '>(\n "' + check_name + '");\n ' )
129
+
130
+ for line in lines :
131
+ if not header_added :
132
+ match = re .search ('#include "(.*)"' , line )
133
+ if match :
134
+ header_found = True
135
+ if match .group (1 ) > check_name_camel :
136
+ header_added = True
137
+ f .write ('#include "' + check_name_camel + '.h"\n ' )
138
+ elif header_found :
139
+ header_added = True
140
+ f .write ('#include "' + check_name_camel + '.h"\n ' )
141
+
142
+ if not check_added :
143
+ if line .strip () == '}' :
144
+ check_added = True
145
+ f .write (check_decl )
146
+ else :
147
+ match = re .search ('registerCheck<(.*)>' , line )
148
+ if match and match .group (1 ) > check_name_camel :
149
+ check_added = True
150
+ f .write (check_decl )
151
+ f .write (line )
152
+
153
+
154
+ # Adds a release notes entry.
155
+ def add_release_notes (clang_tidy_path , old_check_name , new_check_name ):
156
+ filename = os .path .normpath (os .path .join (clang_tidy_path ,
157
+ '../docs/ReleaseNotes.rst' ))
158
+ with open (filename , 'r' ) as f :
159
+ lines = f .readlines ()
160
+
161
+ print ('Updating %s...' % filename )
162
+ with open (filename , 'wb' ) as f :
163
+ note_added = False
164
+ header_found = False
165
+
166
+ for line in lines :
167
+ if not note_added :
168
+ match = re .search ('Improvements to clang-tidy' , line )
169
+ if match :
170
+ header_found = True
171
+ elif header_found :
172
+ if not line .startswith ('----' ):
173
+ f .write ("""
174
+ - The '%s' check was renamed to `%s
175
+ <http://clang.llvm.org/extra/clang-tidy/checks/%s.html>`_
176
+ """ % (old_check_name , new_check_name , new_check_name ))
177
+ note_added = True
178
+
179
+ f .write (line )
69
180
70
181
def main ():
71
182
parser = argparse .ArgumentParser (description = 'Rename clang-tidy check.' )
72
- parser .add_argument ('module' , type = str ,
73
- help = 'Module where the renamed check is defined' )
74
183
parser .add_argument ('old_check_name' , type = str ,
75
184
help = 'Old check name.' )
76
185
parser .add_argument ('new_check_name' , type = str ,
77
186
help = 'New check name.' )
78
187
args = parser .parse_args ()
79
188
80
- args .module = args .module .lower ()
189
+ old_module = args .old_check_name .split ('-' )[0 ]
190
+ new_module = args .new_check_name .split ('-' )[0 ]
81
191
check_name_camel = '' .join (map (lambda elem : elem .capitalize (),
82
- args .old_check_name .split ('-' ))) + 'Check'
83
- check_name_new_camel = ('' .join (map (lambda elem : elem .capitalize (),
84
- args .new_check_name .split ('-' ))) +
192
+ args .old_check_name .split ('-' )[ 1 :] )) + 'Check'
193
+ new_check_name_camel = ('' .join (map (lambda elem : elem .capitalize (),
194
+ args .new_check_name .split ('-' )[ 1 :] )) +
85
195
'Check' )
86
196
87
197
clang_tidy_path = os .path .dirname (__file__ )
88
198
89
- header_guard_old = (args .module .upper () + '_' +
90
- args .old_check_name .upper ().replace ('-' , '_' ))
91
- header_guard_new = (args .module .upper () + '_' +
92
- args .new_check_name .upper ().replace ('-' , '_' ))
199
+ header_guard_old = args .old_check_name .upper ().replace ('-' , '_' )
200
+ header_guard_new = args .new_check_name .upper ().replace ('-' , '_' )
201
+
202
+ old_module_path = os .path .join (clang_tidy_path , old_module )
203
+ new_module_path = os .path .join (clang_tidy_path , new_module )
204
+
205
+ # Remove the check from the old module.
206
+ cmake_lists = os .path .join (old_module_path , 'CMakeLists.txt' )
207
+ check_found = deleteMatchingLines (cmake_lists , check_name_camel )
208
+ if not check_found :
209
+ print ("Check name '%s' not found in %s. Exiting." %
210
+ (check_name_camel , cmake_lists ))
211
+ return 1
212
+
213
+ modulecpp = filter (
214
+ lambda p : p .lower () == old_module .lower () + 'tidymodule.cpp' ,
215
+ os .listdir (old_module_path ))[0 ]
216
+ deleteMatchingLines (os .path .join (old_module_path , modulecpp ),
217
+ check_name_camel + '|' + args .old_check_name )
93
218
94
219
for filename in getListOfFiles (clang_tidy_path ):
95
220
originalName = filename
96
221
filename = fileRename (filename , args .old_check_name ,
97
222
args .new_check_name )
98
- filename = fileRename (filename , check_name_camel , check_name_new_camel )
223
+ filename = fileRename (filename , check_name_camel , new_check_name_camel )
99
224
replaceInFile (filename , generateCommentLineHeader (originalName ),
100
225
generateCommentLineHeader (filename ))
101
226
replaceInFile (filename , generateCommentLineSource (originalName ),
102
227
generateCommentLineSource (filename ))
103
228
replaceInFile (filename , header_guard_old , header_guard_new )
104
229
replaceInFile (filename , args .old_check_name , args .new_check_name )
105
- replaceInFile (filename , check_name_camel , check_name_new_camel )
230
+ replaceInFile (filename , check_name_camel , new_check_name_camel )
231
+
232
+ if old_module != new_module :
233
+ check_implementation_files = glob .glob (
234
+ os .path .join (old_module_path , new_check_name_camel + '*' ))
235
+ for filename in check_implementation_files :
236
+ # Move check implementation to the directory of the new module.
237
+ filename = fileRename (filename , old_module_path , new_module_path )
238
+ replaceInFile (filename , 'namespace ' + old_module ,
239
+ 'namespace ' + new_module )
240
+
241
+ # Add check to the new module.
242
+ adapt_cmake (new_module_path , new_check_name_camel )
243
+ adapt_module (new_module_path , new_module , args .new_check_name ,
244
+ new_check_name_camel )
245
+
246
+ os .system (os .path .join (clang_tidy_path , 'add_new_check.py' )
247
+ + ' --update-docs' )
248
+ add_release_notes (clang_tidy_path , args .old_check_name , args .new_check_name )
106
249
107
250
if __name__ == '__main__' :
108
251
main ()
0 commit comments