3 ## Copyright (C) 2014-2017 CEA/DEN, EDF R&D
5 ## This library is free software; you can redistribute it and/or
6 ## modify it under the terms of the GNU Lesser General Public
7 ## License as published by the Free Software Foundation; either
8 ## version 2.1 of the License, or (at your option) any later version.
10 ## This library is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ## Lesser General Public License for more details.
15 ## You should have received a copy of the GNU Lesser General Public
16 ## License along with this library; if not, write to the Free Software
17 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ## See http:##www.salome-platform.org/ or
20 ## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
24 import os, os.path, sys, re, argparse
33 #### définition des hooks.
35 # * avoir le prototype suivant : def <nom_hook>(<unicode>) avec <unicode> la ligne de texte à corriger
36 # * retourner deux valeurs : la ligne corrigée, en unicode et un booléen indiquant s'il faut faire un check humain avant de corriger
37 # * être inséré dans HOOKS_DICT en y faisant correspondre un dico explicitant les critères de séléction de ce hook
40 ### whitespace/semicolon ###
42 def extra_space_before_last_semicolon(ligne, previous_ligne = None, warning=None):
43 liste=ligne.split(u';\n')
45 ligne3=ligne2.rstrip()
47 return ligne, previous_ligne, False
49 def missing_space_after_semicolon(ligne, previous_ligne = None, warning=None):
50 ligne=ligne.replace(u';',u'; ')
51 return ligne, previous_ligne, False
53 #########################
55 ### whitespace/operators ###
57 def missing_space_around_operator_egal(ligne, previous_ligne = None, warning=None):
60 previouschar=ligne[i-1]
61 if nextchar not in OPERATORS and previouschar not in OPERATORS:
62 if nextchar.isspace() == False and previouschar.isspace()==True:
63 ligne=ligne.replace(u'=', u'= ')
64 elif nextchar.isspace() == True and previouschar.isspace()==False:
65 ligne=ligne.replace(u'=', u' =')
66 elif nextchar.isspace() == False and previouschar.isspace()==False:
67 ligne=ligne.replace(u'=', u' = ')
70 return ligne, previous_ligne, False
72 def extra_space_for_operator_add(ligne, previous_ligne = None, warning=None):
73 while ligne.find(u'++ ') > -1:
74 ligne = ligne.replace(u'++ ',u'++')
75 while ligne.find(u' ++') > -1 and ligne.find(u'; ++') == -1:
76 ligne = ligne.replace(u' ++',u'++')
77 return ligne, previous_ligne, False
79 def extra_space_for_operator_diff(ligne, previous_ligne = None, warning=None):
80 while ligne.find(u'! ') > -1:
81 ligne = ligne.replace(u'! ',u'!')
82 return ligne, previous_ligne, False
84 def missing_space_around_operator_double_chevron(ligne, previous_ligne = None, warning=None):
87 previouschar=ligne[i-1]
88 if nextchar.isspace() == False and previouschar.isspace()==True:
89 ligne=ligne.replace(u'<<', u'<< ')
90 elif nextchar.isspace() == True and previouschar.isspace()==False:
91 ligne=ligne.replace(u'<<', u' <<')
92 elif nextchar.isspace() == False and previouschar.isspace()==False:
93 ligne=ligne.replace(u'<<', u' << ')
96 return ligne, previous_ligne, False
98 def missing_space_around_operator_simple_chevron(ligne, previous_ligne = None, warning=None):
101 previouschar=ligne[i-1]
102 if nextchar not in OPERATORS and previouschar not in OPERATORS:
103 if nextchar.isspace() == False and previouschar.isspace()==True:
104 ligne=ligne.replace(u'<', u'< ')
105 elif nextchar.isspace() == True and previouschar.isspace()==False:
106 ligne=ligne.replace(u'<', u' <')
107 elif nextchar.isspace() == False and previouschar.isspace()==False:
108 ligne=ligne.replace(u'<', u' < ')
111 return ligne, previous_ligne, False
114 def missing_space_around_operator_diff_egal(ligne, previous_ligne = None, warning=None):
117 previouschar=ligne[i-1]
118 if nextchar.isspace() == False and previouschar.isspace()==True:
119 ligne=ligne.replace(u'!=', u'!= ')
120 elif nextchar.isspace() == True and previouschar.isspace()==False:
121 ligne=ligne.replace(u'!=', u' !=')
122 elif nextchar.isspace() == False and previouschar.isspace()==False:
123 ligne=ligne.replace(u'!=', u' != ')
126 return ligne, previous_ligne, False
128 def missing_space_around_operator_double_egal(ligne, previous_ligne = None, warning=None):
131 previouschar=ligne[i-1]
132 if nextchar.isspace() == False and previouschar.isspace()==True:
133 ligne=ligne.replace(u'==', u'== ')
134 elif nextchar.isspace() == True and previouschar.isspace()==False:
135 ligne=ligne.replace(u'==', u' ==')
136 elif nextchar.isspace() == False and previouschar.isspace()==False:
137 ligne=ligne.replace(u'==', u' == ')
140 return ligne, previous_ligne, False
143 #########################
145 ### whitespace/comments ###
147 def space_between_comments_and_code(ligne, previous_ligne = None, warning=None):
148 if ligne.find(u'//')>=0 :
149 ligne=ligne.replace(u'//', u' //')
150 elif ligne.find(u' //')>=0 :
151 ligne=ligne.replace(u' //', u' //')
154 return ligne, previous_ligne, False
156 def space_between_comments_and_double_slash(ligne, previous_ligne = None, warning=None):
157 return ligne.replace(u'//', u'// '), previous_ligne, False
159 #########################
162 ### legal/copyright ###
164 def legal_copyright(ficpath, ficline, warning=None):
165 replace_fic_copyright(ficpath)
167 #########################
169 ### build/header_guard
171 def ifndef_header(ficpath, ficline, warning):
172 replace_fic_ifndef(ficpath, ficline, warning, "wrong_style")
174 #def no_ifndef_header(ficpath, ficline, warning):
175 # replace_fic_ifndef(ficpath, ficline, warning, "no_guard_found")
177 def endif_line(ligne, previous_ligne = None, warning=None):
178 liste1=warning.split(u'// ')
180 liste2=ligne1.split(u'"')
181 header_guard=liste2[0]
182 ligne= u'#endif // ' + header_guard +u'\n'
183 return ligne, previous_ligne, False
185 #########################
187 ### whitespace/end_of_ligne ###
189 def whitespace_end_of_line(ligne, previous_ligne = None, warning=None):
190 ligne = ligne.rstrip()+'\n'
192 return ligne, previous_ligne, False
194 #########################
196 ### whitespace/comma ###
198 def missing_space_after_comma(ligne, previous_ligne = None, warning=None):
199 ligne=ligne.replace(u',',u', ')
200 return ligne, previous_ligne, False
202 #########################
204 ### readability/namespace ###
206 def namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
207 ligne2=ligne.rstrip(u'\n')
208 liste = warning.split(u'"')
210 if ligne.find(u'\r')>=0:
211 ligne=ligne2+u' '+namespace+u'\r\n'
213 ligne=ligne2+u' '+namespace+u'\n'
214 return ligne, previous_ligne, False
216 def anonymous_namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
217 ligne2=ligne.rstrip(u'\n')
218 ligne=ligne2+u' // namespace\n'
219 return ligne, previous_ligne, False
221 #########################
223 ### whitespace/parens ###
225 def extra_space_after_opening_paranthesis(ligne, previous_ligne = None, warning=None):
226 while ligne.find(u'( ') > -1:
227 ligne = ligne.replace(u'( ',u'(')
228 return ligne, previous_ligne, False
230 def extra_space_before_closing_paranthesis(ligne, previous_ligne = None, warning=None):
231 while ligne.find(u' )') > -1:
232 ligne = ligne.replace(u' )',u')')
233 return ligne, previous_ligne, False
235 def extra_space_before_opening_paranthesis_in_function_call(ligne, previous_ligne = None, warning=None):
236 while ligne.find(u' (') > -1 and ligne.find(u', (')==-1:
237 ligne = ligne.replace(u' (',u'(')
238 return ligne, previous_ligne, False
240 def missing_space_before_opening_parenthesis_in_for(ligne, previous_ligne = None, warning=None):
241 return ligne.replace(u'for(',u'for ('), previous_ligne, False
243 def missing_space_before_opening_parenthesis_in_if(ligne, previous_ligne = None, warning=None):
244 return ligne.replace(u'if(',u'if ('), previous_ligne, False
246 def missing_space_before_opening_parenthesis_in_switch(ligne, previous_ligne = None, warning=None):
247 return ligne.replace(u'switch(',u'switch ('), previous_ligne, False
249 def missing_space_before_opening_parenthesis_in_while(ligne, previous_ligne = None, warning=None):
250 return ligne.replace(u'while(',u'while ('), previous_ligne, False
252 def mismatching_spaces_inside_paranthesis(ligne, previous_ligne = None, warning=None):
253 while ligne.find(u'( ') > -1:
254 ligne = ligne.replace(u'( ',u'(')
255 while ligne.find(u' )') > -1:
256 ligne = ligne.replace(u' )',u')')
257 return ligne, previous_ligne, False
259 #########################
261 ### whitespace/newline ###
263 def else_should_be_previous_line(ligne, previous_ligne=None, warning=None):
264 return position_of_else(ligne, previous_ligne, warning)
266 #########################
268 ### whitespace/indent ###
270 def missing_space_before_public_protected_private(ligne, previous_ligne = None, warning=None):
271 # Ajout d'un espace avant public:, protected: et :private
272 if re.match("public.*:|protected.*:|private.*:", ligne):
275 return ligne, previous_ligne, False
277 def wrong_number_of_spaces_while_indenting(ligne, previous_ligne = None, warning=None):
278 # Le nombre d'espaces pour l'indentation doit être pair
279 if re.match("\s{1}\S+|\s{3}\S+|\s{5}\S+|\s{7}\S+|\s{9}\S+", ligne):
280 if not re.match(" public.*:| protected.*:| private.*:| \*", ligne):
282 # Suppression des espaces superflus sur une ligne sans code
286 # Remplacement des tabulations par 8 espaces en début de ligne
287 ligne = ligne.replace("\t", " ")
289 return ligne, previous_ligne, False
290 #########################
292 ### whitespace/ending_newline ###
294 def no_newline_at_the_end_of_file(ligne, previous_ligne = None, warning=None):
296 return ligne, None, False
298 #################################
300 ### build/storage_class ###
302 def order_of_storage_class_specifier(ligne, previous_ligne = None, warning=None):
303 if re.match("\s*const static", ligne):
304 # Inversion de const static en static const
305 ligne = ligne.replace("const static", "static const")
307 return ligne, previous_ligne, False
309 ###########################
311 ### whitespace/tab ###
313 def use_spaces_instead_of_tab(ligne, previous_ligne = None, warning=None):
314 if re.match(".*\t", ligne):
315 # Remplacement des tabulations par 8 espaces
316 ligne = ligne.replace("\t", " ")
318 return ligne, previous_ligne, False
320 ######################
322 ### readability/braces ###
324 def no_semicolon_after_brace(ligne, previous_ligne = None, warning=None):
325 return ligne.replace(u'};',u'}'), previous_ligne, False
327 def position_of_else(ligne, previous_ligne=None, warning=None):
328 '''Remonte une ligne du type } else {'''
330 if '}' not in previous_ligne:
331 # Si on ne trouve pas de '}' sur la ligne précédente, on ne fait rien
332 return ligne, None, False
334 m = re.match("(.*)else(.*)", ligne)
336 previous_ligne = previous_ligne.rstrip("\n") + ' else' + m.group(2) + '\n'
338 return ligne, previous_ligne, False
340 ##########################
342 ### whitespace/braces ###
344 def position_of_opening_brace(ligne, previous_ligne=None, warning=None):
345 '''Remonte le { sur la ligne du dessus'''
347 m = re.match("(\s*){(.*)", ligne)
349 # On ne fait rien si on trouve un commentaire sur la ligne précédente (ce sera une correction manuelle)
350 if previous_ligne.find(u'//') == -1:
351 previous_ligne = previous_ligne.rstrip("\n") + ' {' + m.group(2) + '\n'
354 print "The previous line contains a comment, fixing has to be manual."
356 return ligne, previous_ligne, False
358 def missing_space_before_opening_brace(ligne, previous_ligne = None, warning=None):
359 m = re.match("(.+)(\S){(.*)", ligne)
361 print 'group_0', m.group(0)
362 print 'group_1', m.group(1)
363 print 'group_2', m.group(2)
364 print 'group_3', m.group(3)
365 ligne = m.group(1) + m.group(2) + ' {' + m.group(3) + '\n'
367 return ligne, previous_ligne, False
370 #########################
373 def missing_space_before_else(ligne, previous_ligne = None, warning=None):
374 m = re.match("(.+)(\S)else(.*)", ligne)
376 print 'group_0', m.group(0)
377 print 'group_1', m.group(1)
378 print 'group_2', m.group(2)
379 print 'group_3', m.group(3)
380 ligne = m.group(1) + m.group(2) + ' else' + m.group(3) + '\n'
382 return ligne, previous_ligne, False
384 ### runtime/references ###
386 def make_const_reference(ficpath, ligne, previous_ligne = None, warning=None):
387 """ Adding keyword 'const' """
388 print "ficpath = ", ficpath
389 print "ligne = ", ligne
390 print "warning = ", warning
391 m = re.match("(.+)Is this a non-const reference\? If so, make const or use a pointer: (.+) (.+)", warning)
393 print 'group_0', m.group(0)
394 print 'group_1', m.group(1)
395 print 'group_2', m.group(2)
396 print 'group_3', m.group(3)
397 arg_to_modify = m.group(2)
398 ligne = ligne.replace(arg_to_modify, "const "+arg_to_modify)
400 # Répercution des corrections dans le fichier ".cpp" correspondant si c'est un fichier ".h"
401 if ficpath.find('.h') > -1:
402 cpp_file_path = ficpath.replace('.h', '.cpp')
403 make_const_reference_cpp_file(cpp_file_path, arg_to_modify)
404 global H_FILE_MAKE_CONST_REFERENCE_MODIFIED
405 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = True
407 print "ERROR : The following pattern was not found : 'Is this a non-const reference? If so, make const or use a pointer:'"
409 return ligne, previous_ligne, False
411 def make_const_reference_cpp_file(ficpath, arg_to_modify):
412 if not os.path.isfile(ficpath):
413 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'"
416 fic = open(get_src_path(ficpath),'r')
417 liste = fic_readlines(fic)
421 # Recherche de l'argument à modifier
422 if(ligne.find(arg_to_modify) > -1 and ligne.find('const '+arg_to_modify) == -1):
423 new_liste.append(ligne.replace(arg_to_modify, "const "+arg_to_modify))
425 new_liste.append(ligne)
427 newliste=fic_writelines(new_liste)
428 fichier = open(get_src_path(ficpath), "w")
429 fichier.writelines(newliste)
434 ##########################
438 def replace_short_by_int16(ligne, previous_ligne = None, warning=None):
439 ligne = ligne.replace(u'short', u'int16_t')
441 return ligne, None, False
443 def replace_long_by_int64(ligne, previous_ligne = None, warning=None):
444 ligne = ligne.replace(u'long', u'int64_t')
446 return ligne, None, False
450 ### runtime/explicit ###
452 def make_constructor_explicit(ligne, previous_ligne = None, warning=None):
453 m = re.match("(\s*)(.+)", ligne)
455 print 'group_0', m.group(0)
456 print 'group_1', m.group(1)
457 print 'group_2', m.group(2)
458 ligne = ligne.replace(m.group(2), u'explicit '+m.group(2))
460 return ligne, None, False
462 ########################
464 ### build/include ###
466 def cpp_file_should_include_h_file(ficpath, ficline, warning):
467 fic = open(get_src_path(ficpath),'r')
468 liste = fic_readlines(fic)
471 m = re.match("(.+) should include its header file (.+) (.+)", warning)
473 print 'group_0', m.group(0)
474 print 'group_1', m.group(1)
475 print 'group_2', m.group(2)
476 # Nouveau chemin du fichier .h
477 new_h_file_path = m.group(2)
480 h_file_name = os.path.basename(new_h_file_path)
482 # Recherche de la ligne à modifier
484 m2 = re.match("#include.*"+h_file_name+".*", ligne)
486 print "FOUND : ", ligne
487 new_liste.append("#include \""+new_h_file_path+"\"\n")
489 print "NOT FOUND : ", ligne
490 new_liste.append(ligne)
492 print "ERROR : Pattern not found : \"should include its header file\""
494 newliste=fic_writelines(new_liste)
495 fichier = open(get_src_path(ficpath), "w")
496 fichier.writelines(newliste)
498 def _h_file_already_included(ligne, previous_ligne = None, warning=None):
499 return "", None, False
502 #####################
504 ### whitespace/blank_line ###
506 def do_not_leave_blank_line_after_public_protected_private(ficpath, ficline, warning):
507 fic = open(get_src_path(ficpath),'r')
508 liste = fic_readlines(fic)
513 if re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
514 # Détection d'une ligne public:, protected: ou :private
516 if flag and ligne.isspace():
517 # Supprimer les lignes vides après public:, protected: et :private
518 print "Deleting empty line"
521 if not ligne.isspace() and not re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
523 new_liste.append(ligne)
525 newliste=fic_writelines(new_liste)
526 fichier = open(get_src_path(ficpath), "w")
527 fichier.writelines(newliste)
529 def do_not_leave_blank_line_at_the_start_of_code_block(ficpath, ficline, warning):
530 fic = open(get_src_path(ficpath),'r')
531 liste = fic_readlines(fic)
536 if re.match(".*{", ligne):
537 # Détection d'un début de bloc
539 if flag and ligne.isspace():
540 # Supprimer les lignes vides après un début de bloc
541 print "Deleting empty line"
544 if not ligne.isspace() and not re.match(".*{", ligne):
546 new_liste.append(ligne)
548 newliste=fic_writelines(new_liste)
549 fichier = open(get_src_path(ficpath), "w")
550 fichier.writelines(newliste)
552 def do_not_leave_blank_line_at_the_end_of_code_block(ficpath, ficline, warning):
553 fic = open(get_src_path(ficpath),'r')
554 liste = fic_readlines(fic)
559 if re.match(".*}", ligne):
560 # Détection d'une fin de bloc -> suppression des nb_blank_lines lignes vides précédentes
561 for i in range(0, nb_blank_lines):
567 new_liste.append(ligne)
569 newliste=fic_writelines(new_liste)
570 fichier = open(get_src_path(ficpath), "w")
571 fichier.writelines(newliste)
573 def add_blank_line_before_public(ligne, previous_ligne = None, warning=None):
576 return ligne, None, False
578 def add_blank_line_before_protected(ligne, previous_ligne = None, warning=None):
581 return ligne, None, False
583 def add_blank_line_before_private(ligne, previous_ligne = None, warning=None):
586 return ligne, None, False
588 ##############################
590 ### build/include_what_you_use ###
592 def add_include_what_you_use(ficpath, ficline, warning):
594 Ajoute le #include suggéré dans le warning
597 fic = open(get_src_path(ficpath), "r")
598 liste = fic_readlines(fic)
600 m = re.match("\s*Add (.+) for (.+)", warning)
602 print 'group_0', m.group(0)
603 print 'group_1', m.group(1)
606 # Recherche la ligne dans laquelle ajouter le #include
607 # On l'ajoutera après le dernier "#include <..."
609 num_ligne_include_system = 0
610 num_ligne_include_local = 0
613 if ligne.find('#include <') > -1:
614 num_ligne_include_system = num_ligne
615 elif ligne.find('#include "') > -1:
616 num_ligne_include_local = num_ligne
618 num_ligne_include = max(num_ligne_include_system, num_ligne_include_local)
619 if num_ligne_include == 0:
620 print "WARNING : #include not found in file ", ficpath
625 fic2 = open(get_src_path(ficpath), "r")
626 liste2 = fic_readlines(fic2)
629 new_liste.append(ligne)
630 if num_ligne == num_ligne_include:
631 new_liste.append(include+'\n')
633 newliste=fic_writelines(new_liste)
634 fichier = open(get_src_path(ficpath), "w")
635 fichier.writelines(newliste)
637 print "ERROR : Pattern of include_what_you_use not found"
640 ##################################
644 extra_space_before_last_semicolon:{'pattern':u'whitespace/semicolon', 'pattern_AND':u'Extra space before last semicolon'},
645 missing_space_after_semicolon:{'pattern':u'whitespace/semicolon', 'pattern_AND':u'Missing space after'},
646 missing_space_around_operator_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around = '},
647 extra_space_for_operator_add:{'pattern':u'whitespace/operators', 'pattern_AND':u'Extra space for operator ++'},
648 extra_space_for_operator_diff:{'pattern':u'whitespace/operators', 'pattern_AND':u'Extra space for operator !'},
649 missing_space_around_operator_double_chevron:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around << '},
650 missing_space_around_operator_simple_chevron:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around < '},
651 missing_space_around_operator_diff_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around !='},
652 missing_space_around_operator_double_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around =='},
653 space_between_comments_and_code:{'pattern':u'whitespace/comments', 'pattern_AND':u'At least two spaces is best between code and comments'},
654 space_between_comments_and_double_slash:{'pattern':u'whitespace/comments', 'pattern_AND':u'Should have a space between // and comment '},
655 legal_copyright:{'pattern':u'legal/copyright'}, # Script à n'executer qu'une fois
656 ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'#ifndef header guard has wrong style, please use'},
657 # no_ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'No #ifndef header guard found'},
658 endif_line:{'pattern':u'build/header_guard', 'pattern_AND':u'#endif line should be'},
659 whitespace_end_of_line:{'pattern':u'whitespace/end_of_line', 'pattern_AND':u'Line ends in whitespace'},
660 missing_space_after_comma:{'pattern':u'whitespace/comma'},
661 namespace_should_be_terminated:{'pattern':u'readability/namespace', 'pattern_AND':u'Namespace should be terminated with'},
662 anonymous_namespace_should_be_terminated:{'pattern':u'readability/namespace', 'pattern_AND':u'Anonymous namespace should be terminated with'},
663 extra_space_after_opening_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Extra space after ('},
664 extra_space_before_closing_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Extra space before )'},
665 extra_space_before_opening_paranthesis_in_function_call:{'pattern':u'whitespace/parens', 'pattern':u'Extra space before ( in function call'},
666 missing_space_before_opening_parenthesis_in_for:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in for('},
667 missing_space_before_opening_parenthesis_in_if:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in if('},
668 missing_space_before_opening_parenthesis_in_switch:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in switch('},
669 missing_space_before_opening_parenthesis_in_while:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in while('},
670 mismatching_spaces_inside_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Mismatching spaces inside ()'},
671 missing_space_before_public_protected_private:{'pattern':u'whitespace/indent', 'pattern_AND':u' should be indented +1 space inside class'},
673 wrong_number_of_spaces_while_indenting:{'pattern':u'whitespace/indent', 'pattern_AND':u'Weird number of spaces at line-start'},
675 no_newline_at_the_end_of_file:{'pattern':u'whitespace/ending_newline'},
677 order_of_storage_class_specifier:{'pattern':u'build/storage_class'},
679 use_spaces_instead_of_tab:{'pattern':u'whitespace/tab'},
681 no_semicolon_after_brace:{'pattern':u'readability/braces', 'pattern_AND':u'You don\'t need a ; after a }'},
682 # position_of_else:{'pattern':u'readability/braces', 'pattern_AND':u'If an else has a brace on one side'},
683 # else_should_be_previous_line:{'pattern':u'whitespace/newline', 'pattern_AND':u'An else should appear on the same line as the preceding'},
684 position_of_opening_brace:{'pattern':u'whitespace/braces', 'pattern_AND':u'{ should almost always be at the end of the previous line'},
685 missing_space_before_opening_brace:{'pattern':u'whitespace/braces', 'pattern_AND':u'Missing space before {'},
686 missing_space_before_else:{'pattern':u'whitespace/braces', 'pattern_AND':u'Missing space before else'},
688 make_const_reference:{'pattern':u'runtime/references', 'pattern_AND':u'Is this a non-const reference? If so, make const or use a pointer'},
690 make_constructor_explicit:{'pattern':u'runtime/explicit'},
692 cpp_file_should_include_h_file:{'pattern':u'build/include', 'pattern_AND':u'should include its header file'},
693 _h_file_already_included:{'pattern':u'build/include', 'pattern_AND':u'already included at'},
695 replace_short_by_int16:{'pattern':u'runtime/int', 'pattern_AND':u'Use int16/int64/etc, rather than the C type short'},
696 replace_long_by_int64:{'pattern':u'runtime/int', 'pattern_AND':u'Use int16/int64/etc, rather than the C type long'},
698 do_not_leave_blank_line_after_public_protected_private:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Do not leave a blank line after'},
699 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'},
700 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'},
701 add_blank_line_before_public:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"public:" should be preceded by a blank line'},
702 add_blank_line_before_protected:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"protected:" should be preceded by a blank line'},
703 add_blank_line_before_private:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"private:" should be preceded by a blank line'},
705 add_include_what_you_use:{'pattern':u'build/include_what_you_use'},
709 HOOKS_DELETING_OR_ADDING_LINES = [no_newline_at_the_end_of_file, position_of_opening_brace, _h_file_already_included,
710 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]
711 HOOKS_PARSING_THE_WHOLE_FILE = [cpp_file_should_include_h_file, do_not_leave_blank_line_after_public_protected_private,
712 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
714 def replace_line_no(path, nol, oldline, newline):
716 Remplace, la ligne No nol du fichier path (relatif à SRCROOTDIR) par la chaîne newline (un unicode)
717 oldline sert uniquement pour vérifier que tout est ok
719 print "replace_line_no : ", oldline, " by ", newline
720 # récupérer le contenu du fichier
721 fic = open(get_src_path(path), "r")
722 liste = fic.readlines()
725 if liste[nol-1].decode(ENCODING) != oldline :
726 raise Exception(u"Le fichier source %s semble être corrompu" %path)
727 # remplacement de la ligne
728 liste[nol-1] = newline.encode(ENCODING)
729 # recréation du fichier corrigé
730 fic = open(get_src_path(path), "w")
731 fic.writelines(liste)
734 def replace_fic_copyright(ficpath, warning=None):
736 Remplace le fichier sans la ligne copyright par le fichier avec la ligne copyright
739 fic = open(get_src_path(ficpath), "r")
740 liste=fic_readlines(fic)
743 if liste[0].find(u'/ Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n')== -1:
744 newliste=[u'// Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n']+liste
745 newliste=fic_writelines(newliste)
746 fic = open(get_src_path(ficpath), "w")
747 fic.writelines(newliste)
751 def replace_fic_ifndef(ficpath, ficline, warning, mode):
753 Remplace dans le fichier, toutes les erreurs sur le style des #define et #ifndef à partir du warning
755 fic = open(get_src_path(ficpath),'r')
756 liste = fic_readlines(fic)
759 if mode == "no_guard_found":
760 m = re.match("(.*)No #ifndef header guard found, suggested CPP variable is: (.+) (.+)", warning)
762 m = re.match("(.*)ifndef header guard has wrong style, please use: (.+) (.+)", warning)
765 print 'group_0', m.group(0)
766 print 'group_1', m.group(1)
767 print 'group_2', m.group(2)
770 header_guard=m.group(2)
772 # Recherche de la ligne à modifier
778 if ligne.find(u'#ifndef') >= 0:
779 new_liste.append("#ifndef "+header_guard+"\n")
782 print "ERROR : Pattern #ifndef not found in line ", ficline
786 if ligne.find(u'#define') >= 0:
787 new_liste.append("#define "+header_guard+"\n")
790 print "WARNING : Pattern #define not found in the line following the pattern #ifndef, we abandon."
793 new_liste.append(ligne)
795 print "ERROR : Pattern not found : \"#ifndef header guard has wrong style, please use\""
797 newliste=fic_writelines(new_liste)
798 fichier = open(get_src_path(ficpath), "w")
799 fichier.writelines(newliste)
802 def get_hook(warning, fichier):
804 Fait le matching entre un warning et le hook permettant de le traiter.
805 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.
806 Le format de chaque dict de critère est le suivant :
808 "pattern": <motif principal devant se trouver dans le texte du warning>,
809 "pattern_AND": <motif secondaire devant se trouver également dans le texte du warning>,
810 "pattern_NOT": <motif secondaire ne devant pas se trouver dans le texte du warning>,
811 "ext": <extension du fichier considéré>
813 Seul le premier hook trouvé est renvoyé.
814 Les arguments sont les suivants :
815 * warning : le texte unicode du warning
816 * fichier : le chemin vers le fichier concerné
818 def test_it(condition, data, warning, fichier):
819 if condition in ["pattern", "pattern_AND"] :
822 elif condition in ["PATTERN_NOT"]:
823 if data not in warning:
825 elif condition in ["ext"]:
826 if data not in os.path.splitext(fichier)[1]:
830 for key, val in HOOKS_DICT.items(): # boucle sur les hooks existants
832 for condition, data in val.items():
834 # si une condition n'est pas réalisée => c'est pas le bon hook
836 test = test_it(condition, data, warning, fichier)
841 def main_routine(cpplint_output_file):
842 logfile = open(cpplint_output_file,"r")
843 generateur_w = create_warning_generator(logfile)
844 last_ficpath_with_modified_nb_lines = ""
845 for ficpath, ficline, warning in generateur_w:
846 oldline = get_line_no(ficpath, ficline)
848 previous_oldline = get_line_no(ficpath, ficline-1)
850 previous_oldline = None
851 print "===\nNew warning:"
852 print "\tFile = "+ficpath
853 print "\tlast_ficpath_with_modified_nb_lines = "+last_ficpath_with_modified_nb_lines
854 print "\tNo ligne =" , ficline
855 if VERBOSE_FLAG == "True":
856 print "\tWarning ='"+warning+"'"
857 print "\tOld text of current line = '"+oldline+"'"
859 print "\tOld text of previous line = '"+previous_oldline+"'"
860 if ficpath == last_ficpath_with_modified_nb_lines:
861 print "File ", ficpath, "already modified. Waiting next cpplint run to process it."
863 hook = get_hook(warning, ficpath)
864 print "hook = ", hook
866 print u"No hook found"
869 if VERBOSE_FLAG == "True":
870 print "\t=> Processing with hook", hook
872 if hook in HOOKS_DELETING_OR_ADDING_LINES:
873 last_ficpath_with_modified_nb_lines = ficpath
875 if hook in HOOKS_PARSING_THE_WHOLE_FILE:
876 hook(ficpath, ficline, warning)
880 # 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
881 if hook in [make_const_reference]:
882 if ficpath.find('.h') > -1:
883 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
885 if H_FILE_MAKE_CONST_REFERENCE_MODIFIED:
888 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
890 newline, previous_newline, huchk = hook(oldline, previous_oldline, warning)
892 if VERBOSE_FLAG == "True":
893 print "\tNew text = '"+newline+"'"
896 print "Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(previous_oldline, previous_newline)
897 reponse = raw_input()
898 if reponse in ['O', 'o']:
899 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
900 print "Replacement done."
902 print "Replacement aborted."
904 print "Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(oldline, newline)
905 reponse = raw_input()
906 if reponse in ['O', 'o']:
907 replace_line_no(ficpath, ficline, oldline, newline)
908 print "Replacement done."
910 print "Replacement aborted."
915 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
916 replace_line_no(ficpath, ficline, oldline, newline)
920 if __name__ == '__main__':
921 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = False
923 parser = argparse.ArgumentParser()
924 parser.add_argument("--cpplint_output_file", type=str, help="Fichier de rapport cpplint à lire en entrée")
925 args = parser.parse_args()
927 if not args.cpplint_output_file:
930 main_routine(args.cpplint_output_file)