2 import os, os.path, sys, re, argparse
11 #### définition des hooks.
13 # * avoir le prototype suivant : def <nom_hook>(<unicode>) avec <unicode> la ligne de texte à corriger
14 # * retourner deux valeurs : la ligne corrigée, en unicode et un booléen indiquant s'il faut faire un check humain avant de corriger
15 # * être inséré dans HOOKS_DICT en y faisant correspondre un dico explicitant les critères de séléction de ce hook
18 ### whitespace/semicolon ###
20 def extra_space_before_last_semicolon(ligne, previous_ligne = None, warning=None):
21 liste=ligne.split(u';\n')
23 ligne3=ligne2.rstrip()
25 return ligne, previous_ligne, False
27 def missing_space_after_semicolon(ligne, previous_ligne = None, warning=None):
28 ligne=ligne.replace(u';',u'; ')
29 return ligne, previous_ligne, False
31 #########################
33 ### whitespace/operators ###
35 def missing_space_around_operator_egal(ligne, previous_ligne = None, warning=None):
38 previouschar=ligne[i-1]
39 if nextchar not in OPERATORS and previouschar not in OPERATORS:
40 if nextchar.isspace() == False and previouschar.isspace()==True:
41 ligne=ligne.replace(u'=', u'= ')
42 elif nextchar.isspace() == True and previouschar.isspace()==False:
43 ligne=ligne.replace(u'=', u' =')
44 elif nextchar.isspace() == False and previouschar.isspace()==False:
45 ligne=ligne.replace(u'=', u' = ')
48 return ligne, previous_ligne, False
50 def extra_space_for_operator_add(ligne, previous_ligne = None, warning=None):
51 while ligne.find(u'++ ') > -1:
52 ligne = ligne.replace(u'++ ',u'++')
53 while ligne.find(u' ++') > -1 and ligne.find(u'; ++') == -1:
54 ligne = ligne.replace(u' ++',u'++')
55 return ligne, previous_ligne, False
57 def extra_space_for_operator_diff(ligne, previous_ligne = None, warning=None):
58 while ligne.find(u'! ') > -1:
59 ligne = ligne.replace(u'! ',u'!')
60 return ligne, previous_ligne, False
62 def missing_space_around_operator_double_chevron(ligne, previous_ligne = None, warning=None):
65 previouschar=ligne[i-1]
66 if nextchar.isspace() == False and previouschar.isspace()==True:
67 ligne=ligne.replace(u'<<', u'<< ')
68 elif nextchar.isspace() == True and previouschar.isspace()==False:
69 ligne=ligne.replace(u'<<', u' <<')
70 elif nextchar.isspace() == False and previouschar.isspace()==False:
71 ligne=ligne.replace(u'<<', u' << ')
74 return ligne, previous_ligne, False
76 def missing_space_around_operator_simple_chevron(ligne, previous_ligne = None, warning=None):
79 previouschar=ligne[i-1]
80 if nextchar not in OPERATORS and previouschar not in OPERATORS:
81 if nextchar.isspace() == False and previouschar.isspace()==True:
82 ligne=ligne.replace(u'<', u'< ')
83 elif nextchar.isspace() == True and previouschar.isspace()==False:
84 ligne=ligne.replace(u'<', u' <')
85 elif nextchar.isspace() == False and previouschar.isspace()==False:
86 ligne=ligne.replace(u'<', u' < ')
89 return ligne, previous_ligne, False
92 def missing_space_around_operator_diff_egal(ligne, previous_ligne = None, warning=None):
95 previouschar=ligne[i-1]
96 if nextchar.isspace() == False and previouschar.isspace()==True:
97 ligne=ligne.replace(u'!=', u'!= ')
98 elif nextchar.isspace() == True and previouschar.isspace()==False:
99 ligne=ligne.replace(u'!=', u' !=')
100 elif nextchar.isspace() == False and previouschar.isspace()==False:
101 ligne=ligne.replace(u'!=', u' != ')
104 return ligne, previous_ligne, False
106 def missing_space_around_operator_double_egal(ligne, previous_ligne = None, warning=None):
109 previouschar=ligne[i-1]
110 if nextchar.isspace() == False and previouschar.isspace()==True:
111 ligne=ligne.replace(u'==', u'== ')
112 elif nextchar.isspace() == True and previouschar.isspace()==False:
113 ligne=ligne.replace(u'==', u' ==')
114 elif nextchar.isspace() == False and previouschar.isspace()==False:
115 ligne=ligne.replace(u'==', u' == ')
118 return ligne, previous_ligne, False
121 #########################
123 ### whitespace/comments ###
125 def space_between_comments_and_code(ligne, previous_ligne = None, warning=None):
126 if ligne.find(u'//')>=0 :
127 ligne=ligne.replace(u'//', u' //')
128 elif ligne.find(u' //')>=0 :
129 ligne=ligne.replace(u' //', u' //')
132 return ligne, previous_ligne, False
134 def space_between_comments_and_double_slash(ligne, previous_ligne = None, warning=None):
135 return ligne.replace(u'//', u'// '), previous_ligne, False
137 #########################
140 ### legal/copyright ###
142 def legal_copyright(ficpath, ficline, warning=None):
143 replace_fic_copyright(ficpath)
145 #########################
147 ### build/header_guard
149 def ifndef_header(ficpath, ficline, warning):
150 replace_fic_ifndef(ficpath, ficline, warning, "wrong_style")
152 #def no_ifndef_header(ficpath, ficline, warning):
153 # replace_fic_ifndef(ficpath, ficline, warning, "no_guard_found")
155 def endif_line(ligne, previous_ligne = None, warning=None):
156 liste1=warning.split(u'// ')
158 liste2=ligne1.split(u'"')
159 header_guard=liste2[0]
160 ligne= u'#endif // ' + header_guard +u'\n'
161 return ligne, previous_ligne, False
163 #########################
165 ### whitespace/end_of_ligne ###
167 def whitespace_end_of_line(ligne, previous_ligne = None, warning=None):
168 ligne = ligne.rstrip()+'\n'
170 return ligne, previous_ligne, False
172 #########################
174 ### whitespace/comma ###
176 def missing_space_after_comma(ligne, previous_ligne = None, warning=None):
177 ligne=ligne.replace(u',',u', ')
178 return ligne, previous_ligne, False
180 #########################
182 ### readability/namespace ###
184 def namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
185 ligne2=ligne.rstrip(u'\n')
186 liste = warning.split(u'"')
188 if ligne.find(u'\r')>=0:
189 ligne=ligne2+u' '+namespace+u'\r\n'
191 ligne=ligne2+u' '+namespace+u'\n'
192 return ligne, previous_ligne, False
194 def anonymous_namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
195 ligne2=ligne.rstrip(u'\n')
196 ligne=ligne2+u' // namespace\n'
197 return ligne, previous_ligne, False
199 #########################
201 ### whitespace/parens ###
203 def extra_space_after_opening_paranthesis(ligne, previous_ligne = None, warning=None):
204 while ligne.find(u'( ') > -1:
205 ligne = ligne.replace(u'( ',u'(')
206 return ligne, previous_ligne, False
208 def extra_space_before_closing_paranthesis(ligne, previous_ligne = None, warning=None):
209 while ligne.find(u' )') > -1:
210 ligne = ligne.replace(u' )',u')')
211 return ligne, previous_ligne, False
213 def extra_space_before_opening_paranthesis_in_function_call(ligne, previous_ligne = None, warning=None):
214 while ligne.find(u' (') > -1 and ligne.find(u', (')==-1:
215 ligne = ligne.replace(u' (',u'(')
216 return ligne, previous_ligne, False
218 def missing_space_before_opening_parenthesis_in_for(ligne, previous_ligne = None, warning=None):
219 return ligne.replace(u'for(',u'for ('), previous_ligne, False
221 def missing_space_before_opening_parenthesis_in_if(ligne, previous_ligne = None, warning=None):
222 return ligne.replace(u'if(',u'if ('), previous_ligne, False
224 def missing_space_before_opening_parenthesis_in_switch(ligne, previous_ligne = None, warning=None):
225 return ligne.replace(u'switch(',u'switch ('), previous_ligne, False
227 def missing_space_before_opening_parenthesis_in_while(ligne, previous_ligne = None, warning=None):
228 return ligne.replace(u'while(',u'while ('), previous_ligne, False
230 def mismatching_spaces_inside_paranthesis(ligne, previous_ligne = None, warning=None):
231 while ligne.find(u'( ') > -1:
232 ligne = ligne.replace(u'( ',u'(')
233 while ligne.find(u' )') > -1:
234 ligne = ligne.replace(u' )',u')')
235 return ligne, previous_ligne, False
237 #########################
239 ### whitespace/newline ###
241 def else_should_be_previous_line(ligne, previous_ligne=None, warning=None):
242 return position_of_else(ligne, previous_ligne, warning)
244 #########################
246 ### whitespace/indent ###
248 def missing_space_before_public_protected_private(ligne, previous_ligne = None, warning=None):
249 # Ajout d'un espace avant public:, protected: et :private
250 if re.match("public.*:|protected.*:|private.*:", ligne):
253 return ligne, previous_ligne, False
255 def wrong_number_of_spaces_while_indenting(ligne, previous_ligne = None, warning=None):
256 # Le nombre d'espaces pour l'indentation doit être pair
257 if re.match("\s{1}\S+|\s{3}\S+|\s{5}\S+|\s{7}\S+|\s{9}\S+", ligne):
258 if not re.match(" public.*:| protected.*:| private.*:| \*", ligne):
260 # Suppression des espaces superflus sur une ligne sans code
264 # Remplacement des tabulations par 8 espaces en début de ligne
265 ligne = ligne.replace("\t", " ")
267 return ligne, previous_ligne, False
268 #########################
270 ### whitespace/ending_newline ###
272 def no_newline_at_the_end_of_file(ligne, previous_ligne = None, warning=None):
274 return ligne, None, False
276 #################################
278 ### build/storage_class ###
280 def order_of_storage_class_specifier(ligne, previous_ligne = None, warning=None):
281 if re.match("\s*const static", ligne):
282 # Inversion de const static en static const
283 ligne = ligne.replace("const static", "static const")
285 return ligne, previous_ligne, False
287 ###########################
289 ### whitespace/tab ###
291 def use_spaces_instead_of_tab(ligne, previous_ligne = None, warning=None):
292 if re.match(".*\t", ligne):
293 # Remplacement des tabulations par 8 espaces
294 ligne = ligne.replace("\t", " ")
296 return ligne, previous_ligne, False
298 ######################
300 ### readability/braces ###
302 def no_semicolon_after_brace(ligne, previous_ligne = None, warning=None):
303 return ligne.replace(u'};',u'}'), previous_ligne, False
305 def position_of_else(ligne, previous_ligne=None, warning=None):
306 '''Remonte une ligne du type } else {'''
308 if '}' not in previous_ligne:
309 # Si on ne trouve pas de '}' sur la ligne précédente, on ne fait rien
310 return ligne, None, False
312 m = re.match("(.*)else(.*)", ligne)
314 previous_ligne = previous_ligne.rstrip("\n") + ' else' + m.group(2) + '\n'
316 return ligne, previous_ligne, False
318 ##########################
320 ### whitespace/braces ###
322 def position_of_opening_brace(ligne, previous_ligne=None, warning=None):
323 '''Remonte le { sur la ligne du dessus'''
325 m = re.match("(\s*){(.*)", ligne)
327 # On ne fait rien si on trouve un commentaire sur la ligne précédente (ce sera une correction manuelle)
328 if previous_ligne.find(u'//') == -1:
329 previous_ligne = previous_ligne.rstrip("\n") + ' {' + m.group(2) + '\n'
332 print "The previous line contains a comment, fixing has to be manual."
334 return ligne, previous_ligne, False
336 def missing_space_before_opening_brace(ligne, previous_ligne = None, warning=None):
337 m = re.match("(.+)(\S){(.*)", ligne)
339 print 'group_0', m.group(0)
340 print 'group_1', m.group(1)
341 print 'group_2', m.group(2)
342 print 'group_3', m.group(3)
343 ligne = m.group(1) + m.group(2) + ' {' + m.group(3) + '\n'
345 return ligne, previous_ligne, False
348 #########################
351 def missing_space_before_else(ligne, previous_ligne = None, warning=None):
352 m = re.match("(.+)(\S)else(.*)", ligne)
354 print 'group_0', m.group(0)
355 print 'group_1', m.group(1)
356 print 'group_2', m.group(2)
357 print 'group_3', m.group(3)
358 ligne = m.group(1) + m.group(2) + ' else' + m.group(3) + '\n'
360 return ligne, previous_ligne, False
362 ### runtime/references ###
364 def make_const_reference(ficpath, ligne, previous_ligne = None, warning=None):
365 """ Adding keyword 'const' """
366 print "ficpath = ", ficpath
367 print "ligne = ", ligne
368 print "warning = ", warning
369 m = re.match("(.+)Is this a non-const reference\? If so, make const or use a pointer: (.+) (.+)", warning)
371 print 'group_0', m.group(0)
372 print 'group_1', m.group(1)
373 print 'group_2', m.group(2)
374 print 'group_3', m.group(3)
375 arg_to_modify = m.group(2)
376 ligne = ligne.replace(arg_to_modify, "const "+arg_to_modify)
378 # Répercution des corrections dans le fichier ".cpp" correspondant si c'est un fichier ".h"
379 if ficpath.find('.h') > -1:
380 cpp_file_path = ficpath.replace('.h', '.cpp')
381 make_const_reference_cpp_file(cpp_file_path, arg_to_modify)
382 global H_FILE_MAKE_CONST_REFERENCE_MODIFIED
383 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = True
385 print "ERROR : The following pattern was not found : 'Is this a non-const reference? If so, make const or use a pointer:'"
387 return ligne, previous_ligne, False
389 def make_const_reference_cpp_file(ficpath, arg_to_modify):
390 if not os.path.isfile(ficpath):
391 print "WARNING : The file ", ficpath, " doesn't exist, manual fixing is required in methods of the file ", ficpath.replace('.cpp', '.h'), " in which arguments have been declared 'const'"
394 fic = open(get_src_path(ficpath),'r')
395 liste = fic_readlines(fic)
399 # Recherche de l'argument à modifier
400 if(ligne.find(arg_to_modify) > -1 and ligne.find('const '+arg_to_modify) == -1):
401 new_liste.append(ligne.replace(arg_to_modify, "const "+arg_to_modify))
403 new_liste.append(ligne)
405 newliste=fic_writelines(new_liste)
406 fichier = open(get_src_path(ficpath), "w")
407 fichier.writelines(newliste)
412 ##########################
416 def replace_short_by_int16(ligne, previous_ligne = None, warning=None):
417 ligne = ligne.replace(u'short', u'int16_t')
419 return ligne, None, False
421 def replace_long_by_int64(ligne, previous_ligne = None, warning=None):
422 ligne = ligne.replace(u'long', u'int64_t')
424 return ligne, None, False
428 ### runtime/explicit ###
430 def make_constructor_explicit(ligne, previous_ligne = None, warning=None):
431 m = re.match("(\s*)(.+)", ligne)
433 print 'group_0', m.group(0)
434 print 'group_1', m.group(1)
435 print 'group_2', m.group(2)
436 ligne = ligne.replace(m.group(2), u'explicit '+m.group(2))
438 return ligne, None, False
440 ########################
442 ### build/include ###
444 def cpp_file_should_include_h_file(ficpath, ficline, warning):
445 fic = open(get_src_path(ficpath),'r')
446 liste = fic_readlines(fic)
449 m = re.match("(.+) should include its header file (.+) (.+)", warning)
451 print 'group_0', m.group(0)
452 print 'group_1', m.group(1)
453 print 'group_2', m.group(2)
454 # Nouveau chemin du fichier .h
455 new_h_file_path = m.group(2)
458 h_file_name = os.path.basename(new_h_file_path)
460 # Recherche de la ligne à modifier
462 m2 = re.match("#include.*"+h_file_name+".*", ligne)
464 print "FOUND : ", ligne
465 new_liste.append("#include \""+new_h_file_path+"\"\n")
467 print "NOT FOUND : ", ligne
468 new_liste.append(ligne)
470 print "ERROR : Pattern not found : \"should include its header file\""
472 newliste=fic_writelines(new_liste)
473 fichier = open(get_src_path(ficpath), "w")
474 fichier.writelines(newliste)
476 def _h_file_already_included(ligne, previous_ligne = None, warning=None):
477 return "", None, False
480 #####################
482 ### whitespace/blank_line ###
484 def do_not_leave_blank_line_after_public_protected_private(ficpath, ficline, warning):
485 fic = open(get_src_path(ficpath),'r')
486 liste = fic_readlines(fic)
491 if re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
492 # Détection d'une ligne public:, protected: ou :private
494 if flag and ligne.isspace():
495 # Supprimer les lignes vides après public:, protected: et :private
496 print "Deleting empty line"
499 if not ligne.isspace() and not re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
501 new_liste.append(ligne)
503 newliste=fic_writelines(new_liste)
504 fichier = open(get_src_path(ficpath), "w")
505 fichier.writelines(newliste)
507 def do_not_leave_blank_line_at_the_start_of_code_block(ficpath, ficline, warning):
508 fic = open(get_src_path(ficpath),'r')
509 liste = fic_readlines(fic)
514 if re.match(".*{", ligne):
515 # Détection d'un début de bloc
517 if flag and ligne.isspace():
518 # Supprimer les lignes vides après un début de bloc
519 print "Deleting empty line"
522 if not ligne.isspace() and not re.match(".*{", ligne):
524 new_liste.append(ligne)
526 newliste=fic_writelines(new_liste)
527 fichier = open(get_src_path(ficpath), "w")
528 fichier.writelines(newliste)
530 def do_not_leave_blank_line_at_the_end_of_code_block(ficpath, ficline, warning):
531 fic = open(get_src_path(ficpath),'r')
532 liste = fic_readlines(fic)
537 if re.match(".*}", ligne):
538 # Détection d'une fin de bloc -> suppression des nb_blank_lines lignes vides précédentes
539 for i in range(0, nb_blank_lines):
545 new_liste.append(ligne)
547 newliste=fic_writelines(new_liste)
548 fichier = open(get_src_path(ficpath), "w")
549 fichier.writelines(newliste)
551 def add_blank_line_before_public(ligne, previous_ligne = None, warning=None):
554 return ligne, None, False
556 def add_blank_line_before_protected(ligne, previous_ligne = None, warning=None):
559 return ligne, None, False
561 def add_blank_line_before_private(ligne, previous_ligne = None, warning=None):
564 return ligne, None, False
566 ##############################
568 ### build/include_what_you_use ###
570 def add_include_what_you_use(ficpath, ficline, warning):
572 Ajoute le #include suggéré dans le warning
575 fic = open(get_src_path(ficpath), "r")
576 liste = fic_readlines(fic)
578 m = re.match("\s*Add (.+) for (.+)", warning)
580 print 'group_0', m.group(0)
581 print 'group_1', m.group(1)
584 # Recherche la ligne dans laquelle ajouter le #include
585 # On l'ajoutera après le dernier "#include <..."
587 num_ligne_include_system = 0
588 num_ligne_include_local = 0
591 if ligne.find('#include <') > -1:
592 num_ligne_include_system = num_ligne
593 elif ligne.find('#include "') > -1:
594 num_ligne_include_local = num_ligne
596 num_ligne_include = max(num_ligne_include_system, num_ligne_include_local)
597 if num_ligne_include == 0:
598 print "WARNING : #include not found in file ", ficpath
603 fic2 = open(get_src_path(ficpath), "r")
604 liste2 = fic_readlines(fic2)
607 new_liste.append(ligne)
608 if num_ligne == num_ligne_include:
609 new_liste.append(include+'\n')
611 newliste=fic_writelines(new_liste)
612 fichier = open(get_src_path(ficpath), "w")
613 fichier.writelines(newliste)
615 print "ERROR : Pattern of include_what_you_use not found"
618 ##################################
622 extra_space_before_last_semicolon:{'pattern':u'whitespace/semicolon', 'pattern_AND':u'Extra space before last semicolon'},
623 missing_space_after_semicolon:{'pattern':u'whitespace/semicolon', 'pattern_AND':u'Missing space after'},
624 missing_space_around_operator_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around = '},
625 extra_space_for_operator_add:{'pattern':u'whitespace/operators', 'pattern_AND':u'Extra space for operator ++'},
626 extra_space_for_operator_diff:{'pattern':u'whitespace/operators', 'pattern_AND':u'Extra space for operator !'},
627 missing_space_around_operator_double_chevron:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around << '},
628 missing_space_around_operator_simple_chevron:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around < '},
629 missing_space_around_operator_diff_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around !='},
630 missing_space_around_operator_double_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around =='},
631 space_between_comments_and_code:{'pattern':u'whitespace/comments', 'pattern_AND':u'At least two spaces is best between code and comments'},
632 space_between_comments_and_double_slash:{'pattern':u'whitespace/comments', 'pattern_AND':u'Should have a space between // and comment '},
633 legal_copyright:{'pattern':u'legal/copyright'}, # Script à n'executer qu'une fois
634 ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'#ifndef header guard has wrong style, please use'},
635 # no_ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'No #ifndef header guard found'},
636 endif_line:{'pattern':u'build/header_guard', 'pattern_AND':u'#endif line should be'},
637 whitespace_end_of_line:{'pattern':u'whitespace/end_of_line', 'pattern_AND':u'Line ends in whitespace'},
638 missing_space_after_comma:{'pattern':u'whitespace/comma'},
639 namespace_should_be_terminated:{'pattern':u'readability/namespace', 'pattern_AND':u'Namespace should be terminated with'},
640 anonymous_namespace_should_be_terminated:{'pattern':u'readability/namespace', 'pattern_AND':u'Anonymous namespace should be terminated with'},
641 extra_space_after_opening_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Extra space after ('},
642 extra_space_before_closing_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Extra space before )'},
643 extra_space_before_opening_paranthesis_in_function_call:{'pattern':u'whitespace/parens', 'pattern':u'Extra space before ( in function call'},
644 missing_space_before_opening_parenthesis_in_for:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in for('},
645 missing_space_before_opening_parenthesis_in_if:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in if('},
646 missing_space_before_opening_parenthesis_in_switch:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in switch('},
647 missing_space_before_opening_parenthesis_in_while:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in while('},
648 mismatching_spaces_inside_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Mismatching spaces inside ()'},
649 missing_space_before_public_protected_private:{'pattern':u'whitespace/indent', 'pattern_AND':u' should be indented +1 space inside class'},
651 wrong_number_of_spaces_while_indenting:{'pattern':u'whitespace/indent', 'pattern_AND':u'Weird number of spaces at line-start'},
653 no_newline_at_the_end_of_file:{'pattern':u'whitespace/ending_newline'},
655 order_of_storage_class_specifier:{'pattern':u'build/storage_class'},
657 use_spaces_instead_of_tab:{'pattern':u'whitespace/tab'},
659 no_semicolon_after_brace:{'pattern':u'readability/braces', 'pattern_AND':u'You don\'t need a ; after a }'},
660 # position_of_else:{'pattern':u'readability/braces', 'pattern_AND':u'If an else has a brace on one side'},
661 # else_should_be_previous_line:{'pattern':u'whitespace/newline', 'pattern_AND':u'An else should appear on the same line as the preceding'},
662 position_of_opening_brace:{'pattern':u'whitespace/braces', 'pattern_AND':u'{ should almost always be at the end of the previous line'},
663 missing_space_before_opening_brace:{'pattern':u'whitespace/braces', 'pattern_AND':u'Missing space before {'},
664 missing_space_before_else:{'pattern':u'whitespace/braces', 'pattern_AND':u'Missing space before else'},
666 make_const_reference:{'pattern':u'runtime/references', 'pattern_AND':u'Is this a non-const reference? If so, make const or use a pointer'},
668 make_constructor_explicit:{'pattern':u'runtime/explicit'},
670 cpp_file_should_include_h_file:{'pattern':u'build/include', 'pattern_AND':u'should include its header file'},
671 _h_file_already_included:{'pattern':u'build/include', 'pattern_AND':u'already included at'},
673 replace_short_by_int16:{'pattern':u'runtime/int', 'pattern_AND':u'Use int16/int64/etc, rather than the C type short'},
674 replace_long_by_int64:{'pattern':u'runtime/int', 'pattern_AND':u'Use int16/int64/etc, rather than the C type long'},
676 do_not_leave_blank_line_after_public_protected_private:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Do not leave a blank line after'},
677 do_not_leave_blank_line_at_the_start_of_code_block:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Redundant blank line at the start of a code block should be deleted'},
678 do_not_leave_blank_line_at_the_end_of_code_block:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Redundant blank line at the end of a code block should be deleted'},
679 add_blank_line_before_public:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"public:" should be preceded by a blank line'},
680 add_blank_line_before_protected:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"protected:" should be preceded by a blank line'},
681 add_blank_line_before_private:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"private:" should be preceded by a blank line'},
683 add_include_what_you_use:{'pattern':u'build/include_what_you_use'},
687 HOOKS_DELETING_OR_ADDING_LINES = [no_newline_at_the_end_of_file, position_of_opening_brace, _h_file_already_included,
688 add_blank_line_before_public, add_blank_line_before_protected, add_blank_line_before_private, do_not_leave_blank_line_after_public_protected_private, do_not_leave_blank_line_at_the_start_of_code_block, do_not_leave_blank_line_at_the_end_of_code_block, legal_copyright, add_include_what_you_use]
689 HOOKS_PARSING_THE_WHOLE_FILE = [cpp_file_should_include_h_file, do_not_leave_blank_line_after_public_protected_private,
690 do_not_leave_blank_line_at_the_start_of_code_block, do_not_leave_blank_line_at_the_end_of_code_block, legal_copyright, ifndef_header, add_include_what_you_use] #Hook à éxecuter avant les autres hooks
692 def replace_line_no(path, nol, oldline, newline):
694 Remplace, la ligne No nol du fichier path (relatif à SRCROOTDIR) par la chaîne newline (un unicode)
695 oldline sert uniquement pour vérifier que tout est ok
697 print "replace_line_no : ", oldline, " by ", newline
698 # récupérer le contenu du fichier
699 fic = open(get_src_path(path), "r")
700 liste = fic.readlines()
703 if liste[nol-1].decode(ENCODING) != oldline :
704 raise Exception(u"Le fichier source %s semble être corrompu" %path)
705 # remplacement de la ligne
706 liste[nol-1] = newline.encode(ENCODING)
707 # recréation du fichier corrigé
708 fic = open(get_src_path(path), "w")
709 fic.writelines(liste)
712 def replace_fic_copyright(ficpath, warning=None):
714 Remplace le fichier sans la ligne copyright par le fichier avec la ligne copyright
717 fic = open(get_src_path(ficpath), "r")
718 liste=fic_readlines(fic)
721 if liste[0].find(u'/ Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n')== -1:
722 newliste=[u'// Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n']+liste
723 newliste=fic_writelines(newliste)
724 fic = open(get_src_path(ficpath), "w")
725 fic.writelines(newliste)
729 def replace_fic_ifndef(ficpath, ficline, warning, mode):
731 Remplace dans le fichier, toutes les erreurs sur le style des #define et #ifndef à partir du warning
733 fic = open(get_src_path(ficpath),'r')
734 liste = fic_readlines(fic)
737 if mode == "no_guard_found":
738 m = re.match("(.*)No #ifndef header guard found, suggested CPP variable is: (.+) (.+)", warning)
740 m = re.match("(.*)ifndef header guard has wrong style, please use: (.+) (.+)", warning)
743 print 'group_0', m.group(0)
744 print 'group_1', m.group(1)
745 print 'group_2', m.group(2)
748 header_guard=m.group(2)
750 # Recherche de la ligne à modifier
756 if ligne.find(u'#ifndef') >= 0:
757 new_liste.append("#ifndef "+header_guard+"\n")
760 print "ERROR : Pattern #ifndef not found in line ", ficline
764 if ligne.find(u'#define') >= 0:
765 new_liste.append("#define "+header_guard+"\n")
768 print "WARNING : Pattern #define not found in the line following the pattern #ifndef, we abandon."
771 new_liste.append(ligne)
773 print "ERROR : Pattern not found : \"#ifndef header guard has wrong style, please use\""
775 newliste=fic_writelines(new_liste)
776 fichier = open(get_src_path(ficpath), "w")
777 fichier.writelines(newliste)
780 def get_hook(warning, fichier):
782 Fait le matching entre un warning et le hook permettant de le traiter.
783 Les critères pour sélectionner un ou l'autre des hook sont consignés dans un dict associé (dans HOOKS_DICT) à chaque hook disponible.
784 Le format de chaque dict de critère est le suivant :
786 "pattern": <motif principal devant se trouver dans le texte du warning>,
787 "pattern_AND": <motif secondaire devant se trouver également dans le texte du warning>,
788 "pattern_NOT": <motif secondaire ne devant pas se trouver dans le texte du warning>,
789 "ext": <extension du fichier considéré>
791 Seul le premier hook trouvé est renvoyé.
792 Les arguments sont les suivants :
793 * warning : le texte unicode du warning
794 * fichier : le chemin vers le fichier concerné
796 def test_it(condition, data, warning, fichier):
797 if condition in ["pattern", "pattern_AND"] :
800 elif condition in ["PATTERN_NOT"]:
801 if data not in warning:
803 elif condition in ["ext"]:
804 if data not in os.path.splitext(fichier)[1]:
808 for key, val in HOOKS_DICT.items(): # boucle sur les hooks existants
810 for condition, data in val.items():
812 # si une condition n'est pas réalisée => c'est pas le bon hook
814 test = test_it(condition, data, warning, fichier)
819 def main_routine(cpplint_output_file):
820 logfile = open(cpplint_output_file,"r")
821 generateur_w = create_warning_generator(logfile)
822 last_ficpath_with_modified_nb_lines = ""
823 for ficpath, ficline, warning in generateur_w:
824 oldline = get_line_no(ficpath, ficline)
826 previous_oldline = get_line_no(ficpath, ficline-1)
828 previous_oldline = None
829 print "===\nNew warning:"
830 print "\tFile = "+ficpath
831 print "\tlast_ficpath_with_modified_nb_lines = "+last_ficpath_with_modified_nb_lines
832 print "\tNo ligne =" , ficline
833 if VERBOSE_FLAG == "True":
834 print "\tWarning ='"+warning+"'"
835 print "\tOld text of current line = '"+oldline+"'"
837 print "\tOld text of previous line = '"+previous_oldline+"'"
838 if ficpath == last_ficpath_with_modified_nb_lines:
839 print "File ", ficpath, "already modified. Waiting next cpplint run to process it."
841 hook = get_hook(warning, ficpath)
842 print "hook = ", hook
844 print u"No hook found"
847 if VERBOSE_FLAG == "True":
848 print "\t=> Processing with hook", hook
850 if hook in HOOKS_DELETING_OR_ADDING_LINES:
851 last_ficpath_with_modified_nb_lines = ficpath
853 if hook in HOOKS_PARSING_THE_WHOLE_FILE:
854 hook(ficpath, ficline, warning)
858 # Cas particulier pour le hook make_const_reference : il faut faire un traitement sur le fichier .cpp associé au fichier .h concerné par le hook
859 if hook in [make_const_reference]:
860 if ficpath.find('.h') > -1:
861 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
863 if H_FILE_MAKE_CONST_REFERENCE_MODIFIED:
866 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
868 newline, previous_newline, huchk = hook(oldline, previous_oldline, warning)
870 if VERBOSE_FLAG == "True":
871 print "\tNew text = '"+newline+"'"
874 print "Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(previous_oldline, previous_newline)
875 reponse = raw_input()
876 if reponse in ['O', 'o']:
877 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
878 print "Replacement done."
880 print "Replacement aborted."
882 print "Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(oldline, newline)
883 reponse = raw_input()
884 if reponse in ['O', 'o']:
885 replace_line_no(ficpath, ficline, oldline, newline)
886 print "Replacement done."
888 print "Replacement aborted."
893 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
894 replace_line_no(ficpath, ficline, oldline, newline)
898 if __name__ == '__main__':
899 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = False
901 parser = argparse.ArgumentParser()
902 parser.add_argument("--cpplint_output_file", type=str, help="Fichier de rapport cpplint à lire en entrée")
903 args = parser.parse_args()
905 if not args.cpplint_output_file:
908 main_routine(args.cpplint_output_file)