3 # Copyright (C) 2014-2019 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 email : webmaster.salome@opencascade.com
23 import os, os.path, sys, re, argparse
32 #### définition des hooks.
34 # * avoir le prototype suivant : def <nom_hook>(<unicode>) avec <unicode> la ligne de texte à corriger
35 # * retourner deux valeurs : la ligne corrigée, en unicode et un booléen indiquant s'il faut faire un check humain avant de corriger
36 # * être inséré dans HOOKS_DICT en y faisant correspondre un dico explicitant les critères de séléction de ce hook
39 ### whitespace/semicolon ###
41 def extra_space_before_last_semicolon(ligne, previous_ligne = None, warning=None):
42 liste=ligne.split(';\n')
44 ligne3=ligne2.rstrip()
46 return ligne, previous_ligne, False
48 def missing_space_after_semicolon(ligne, previous_ligne = None, warning=None):
49 ligne=ligne.replace(';','; ')
50 return ligne, previous_ligne, False
52 #########################
54 ### whitespace/operators ###
56 def missing_space_around_operator_egal(ligne, previous_ligne = None, warning=None):
59 previouschar=ligne[i-1]
60 if nextchar not in OPERATORS and previouschar not in OPERATORS:
61 if nextchar.isspace() == False and previouschar.isspace()==True:
62 ligne=ligne.replace('=', '= ')
63 elif nextchar.isspace() == True and previouschar.isspace()==False:
64 ligne=ligne.replace('=', ' =')
65 elif nextchar.isspace() == False and previouschar.isspace()==False:
66 ligne=ligne.replace('=', ' = ')
69 return ligne, previous_ligne, False
71 def extra_space_for_operator_add(ligne, previous_ligne = None, warning=None):
72 while ligne.find('++ ') > -1:
73 ligne = ligne.replace('++ ','++')
74 while ligne.find(' ++') > -1 and ligne.find('; ++') == -1:
75 ligne = ligne.replace(' ++','++')
76 return ligne, previous_ligne, False
78 def extra_space_for_operator_diff(ligne, previous_ligne = None, warning=None):
79 while ligne.find('! ') > -1:
80 ligne = ligne.replace('! ','!')
81 return ligne, previous_ligne, False
83 def missing_space_around_operator_double_chevron(ligne, previous_ligne = None, warning=None):
86 previouschar=ligne[i-1]
87 if nextchar.isspace() == False and previouschar.isspace()==True:
88 ligne=ligne.replace('<<', '<< ')
89 elif nextchar.isspace() == True and previouschar.isspace()==False:
90 ligne=ligne.replace('<<', ' <<')
91 elif nextchar.isspace() == False and previouschar.isspace()==False:
92 ligne=ligne.replace('<<', ' << ')
95 return ligne, previous_ligne, False
97 def missing_space_around_operator_simple_chevron(ligne, previous_ligne = None, warning=None):
100 previouschar=ligne[i-1]
101 if nextchar not in OPERATORS and previouschar not in OPERATORS:
102 if nextchar.isspace() == False and previouschar.isspace()==True:
103 ligne=ligne.replace('<', '< ')
104 elif nextchar.isspace() == True and previouschar.isspace()==False:
105 ligne=ligne.replace('<', ' <')
106 elif nextchar.isspace() == False and previouschar.isspace()==False:
107 ligne=ligne.replace('<', ' < ')
110 return ligne, previous_ligne, False
113 def missing_space_around_operator_diff_egal(ligne, previous_ligne = None, warning=None):
116 previouschar=ligne[i-1]
117 if nextchar.isspace() == False and previouschar.isspace()==True:
118 ligne=ligne.replace('!=', '!= ')
119 elif nextchar.isspace() == True and previouschar.isspace()==False:
120 ligne=ligne.replace('!=', ' !=')
121 elif nextchar.isspace() == False and previouschar.isspace()==False:
122 ligne=ligne.replace('!=', ' != ')
125 return ligne, previous_ligne, False
127 def missing_space_around_operator_double_egal(ligne, previous_ligne = None, warning=None):
130 previouschar=ligne[i-1]
131 if nextchar.isspace() == False and previouschar.isspace()==True:
132 ligne=ligne.replace('==', '== ')
133 elif nextchar.isspace() == True and previouschar.isspace()==False:
134 ligne=ligne.replace('==', ' ==')
135 elif nextchar.isspace() == False and previouschar.isspace()==False:
136 ligne=ligne.replace('==', ' == ')
139 return ligne, previous_ligne, False
142 #########################
144 ### whitespace/comments ###
146 def space_between_comments_and_code(ligne, previous_ligne = None, warning=None):
147 if ligne.find('//')>=0 :
148 ligne=ligne.replace('//', ' //')
149 elif ligne.find(' //')>=0 :
150 ligne=ligne.replace(' //', ' //')
153 return ligne, previous_ligne, False
155 def space_between_comments_and_double_slash(ligne, previous_ligne = None, warning=None):
156 return ligne.replace('//', '// '), previous_ligne, False
158 #########################
161 ### legal/copyright ###
163 def legal_copyright(ficpath, ficline, warning=None):
164 replace_fic_copyright(ficpath)
166 #########################
168 ### build/header_guard
170 def ifndef_header(ficpath, ficline, warning):
171 replace_fic_ifndef(ficpath, ficline, warning, "wrong_style")
173 #def no_ifndef_header(ficpath, ficline, warning):
174 # replace_fic_ifndef(ficpath, ficline, warning, "no_guard_found")
176 def endif_line(ligne, previous_ligne = None, warning=None):
177 liste1=warning.split('// ')
179 liste2=ligne1.split('"')
180 header_guard=liste2[0]
181 ligne= '#endif // ' + header_guard +'\n'
182 return ligne, previous_ligne, False
184 #########################
186 ### whitespace/end_of_ligne ###
188 def whitespace_end_of_line(ligne, previous_ligne = None, warning=None):
189 ligne = ligne.rstrip()+'\n'
191 return ligne, previous_ligne, False
193 #########################
195 ### whitespace/comma ###
197 def missing_space_after_comma(ligne, previous_ligne = None, warning=None):
198 ligne=ligne.replace(',',', ')
199 return ligne, previous_ligne, False
201 #########################
203 ### readability/namespace ###
205 def namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
206 ligne2=ligne.rstrip('\n')
207 liste = warning.split('"')
209 if ligne.find('\r')>=0:
210 ligne=ligne2+' '+namespace+'\r\n'
212 ligne=ligne2+' '+namespace+'\n'
213 return ligne, previous_ligne, False
215 def anonymous_namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
216 ligne2=ligne.rstrip('\n')
217 ligne=ligne2+' // namespace\n'
218 return ligne, previous_ligne, False
220 #########################
222 ### whitespace/parens ###
224 def extra_space_after_opening_paranthesis(ligne, previous_ligne = None, warning=None):
225 while ligne.find('( ') > -1:
226 ligne = ligne.replace('( ','(')
227 return ligne, previous_ligne, False
229 def extra_space_before_closing_paranthesis(ligne, previous_ligne = None, warning=None):
230 while ligne.find(' )') > -1:
231 ligne = ligne.replace(' )',')')
232 return ligne, previous_ligne, False
234 def extra_space_before_opening_paranthesis_in_function_call(ligne, previous_ligne = None, warning=None):
235 while ligne.find(' (') > -1 and ligne.find(', (')==-1:
236 ligne = ligne.replace(' (','(')
237 return ligne, previous_ligne, False
239 def missing_space_before_opening_parenthesis_in_for(ligne, previous_ligne = None, warning=None):
240 return ligne.replace('for(','for ('), previous_ligne, False
242 def missing_space_before_opening_parenthesis_in_if(ligne, previous_ligne = None, warning=None):
243 return ligne.replace('if(','if ('), previous_ligne, False
245 def missing_space_before_opening_parenthesis_in_switch(ligne, previous_ligne = None, warning=None):
246 return ligne.replace('switch(','switch ('), previous_ligne, False
248 def missing_space_before_opening_parenthesis_in_while(ligne, previous_ligne = None, warning=None):
249 return ligne.replace('while(','while ('), previous_ligne, False
251 def mismatching_spaces_inside_paranthesis(ligne, previous_ligne = None, warning=None):
252 while ligne.find('( ') > -1:
253 ligne = ligne.replace('( ','(')
254 while ligne.find(' )') > -1:
255 ligne = ligne.replace(' )',')')
256 return ligne, previous_ligne, False
258 #########################
260 ### whitespace/newline ###
262 def else_should_be_previous_line(ligne, previous_ligne=None, warning=None):
263 return position_of_else(ligne, previous_ligne, warning)
265 #########################
267 ### whitespace/indent ###
269 def missing_space_before_public_protected_private(ligne, previous_ligne = None, warning=None):
270 # Ajout d'un espace avant public:, protected: et :private
271 if re.match("public.*:|protected.*:|private.*:", ligne):
274 return ligne, previous_ligne, False
276 def wrong_number_of_spaces_while_indenting(ligne, previous_ligne = None, warning=None):
277 # Le nombre d'espaces pour l'indentation doit être pair
278 if re.match("\s{1}\S+|\s{3}\S+|\s{5}\S+|\s{7}\S+|\s{9}\S+", ligne):
279 if not re.match(" public.*:| protected.*:| private.*:| \*", ligne):
281 # Suppression des espaces superflus sur une ligne sans code
285 # Remplacement des tabulations par 8 espaces en début de ligne
286 ligne = ligne.replace("\t", " ")
288 return ligne, previous_ligne, False
289 #########################
291 ### whitespace/ending_newline ###
293 def no_newline_at_the_end_of_file(ligne, previous_ligne = None, warning=None):
295 return ligne, None, False
297 #################################
299 ### build/storage_class ###
301 def order_of_storage_class_specifier(ligne, previous_ligne = None, warning=None):
302 if re.match("\s*const static", ligne):
303 # Inversion de const static en static const
304 ligne = ligne.replace("const static", "static const")
306 return ligne, previous_ligne, False
308 ###########################
310 ### whitespace/tab ###
312 def use_spaces_instead_of_tab(ligne, previous_ligne = None, warning=None):
313 if re.match(".*\t", ligne):
314 # Remplacement des tabulations par 8 espaces
315 ligne = ligne.replace("\t", " ")
317 return ligne, previous_ligne, False
319 ######################
321 ### readability/braces ###
323 def no_semicolon_after_brace(ligne, previous_ligne = None, warning=None):
324 return ligne.replace('};','}'), previous_ligne, False
326 def position_of_else(ligne, previous_ligne=None, warning=None):
327 '''Remonte une ligne du type } else {'''
329 if '}' not in previous_ligne:
330 # Si on ne trouve pas de '}' sur la ligne précédente, on ne fait rien
331 return ligne, None, False
333 m = re.match("(.*)else(.*)", ligne)
335 previous_ligne = previous_ligne.rstrip("\n") + ' else' + m.group(2) + '\n'
337 return ligne, previous_ligne, False
339 ##########################
341 ### whitespace/braces ###
343 def position_of_opening_brace(ligne, previous_ligne=None, warning=None):
344 '''Remonte le { sur la ligne du dessus'''
346 m = re.match("(\s*){(.*)", ligne)
348 # On ne fait rien si on trouve un commentaire sur la ligne précédente (ce sera une correction manuelle)
349 if previous_ligne.find('//') == -1:
350 previous_ligne = previous_ligne.rstrip("\n") + ' {' + m.group(2) + '\n'
353 print("The previous line contains a comment, fixing has to be manual.")
355 return ligne, previous_ligne, False
357 def missing_space_before_opening_brace(ligne, previous_ligne = None, warning=None):
358 m = re.match("(.+)(\S){(.*)", ligne)
360 print('group_0', m.group(0))
361 print('group_1', m.group(1))
362 print('group_2', m.group(2))
363 print('group_3', m.group(3))
364 ligne = m.group(1) + m.group(2) + ' {' + m.group(3) + '\n'
366 return ligne, previous_ligne, False
369 #########################
372 def missing_space_before_else(ligne, previous_ligne = None, warning=None):
373 m = re.match("(.+)(\S)else(.*)", ligne)
375 print('group_0', m.group(0))
376 print('group_1', m.group(1))
377 print('group_2', m.group(2))
378 print('group_3', m.group(3))
379 ligne = m.group(1) + m.group(2) + ' else' + m.group(3) + '\n'
381 return ligne, previous_ligne, False
383 ### runtime/references ###
385 def make_const_reference(ficpath, ligne, previous_ligne = None, warning=None):
386 """ Adding keyword 'const' """
387 print("ficpath = ", ficpath)
388 print("ligne = ", ligne)
389 print("warning = ", warning)
390 m = re.match("(.+)Is this a non-const reference\? If so, make const or use a pointer: (.+) (.+)", warning)
392 print('group_0', m.group(0))
393 print('group_1', m.group(1))
394 print('group_2', m.group(2))
395 print('group_3', m.group(3))
396 arg_to_modify = m.group(2)
397 ligne = ligne.replace(arg_to_modify, "const "+arg_to_modify)
399 # Répercution des corrections dans le fichier ".cpp" correspondant si c'est un fichier ".h"
400 if ficpath.find('.h') > -1:
401 cpp_file_path = ficpath.replace('.h', '.cpp')
402 make_const_reference_cpp_file(cpp_file_path, arg_to_modify)
403 global H_FILE_MAKE_CONST_REFERENCE_MODIFIED
404 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = True
406 print("ERROR : The following pattern was not found : 'Is this a non-const reference? If so, make const or use a pointer:'")
408 return ligne, previous_ligne, False
410 def make_const_reference_cpp_file(ficpath, arg_to_modify):
411 if not os.path.isfile(ficpath):
412 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'")
415 fic = open(get_src_path(ficpath),'r')
416 liste = fic_readlines(fic)
420 # Recherche de l'argument à modifier
421 if(ligne.find(arg_to_modify) > -1 and ligne.find('const '+arg_to_modify) == -1):
422 new_liste.append(ligne.replace(arg_to_modify, "const "+arg_to_modify))
424 new_liste.append(ligne)
426 newliste=fic_writelines(new_liste)
427 fichier = open(get_src_path(ficpath), "w")
428 fichier.writelines(newliste)
433 ##########################
437 def replace_short_by_int16(ligne, previous_ligne = None, warning=None):
438 ligne = ligne.replace('short', 'int16_t')
440 return ligne, None, False
442 def replace_long_by_int64(ligne, previous_ligne = None, warning=None):
443 ligne = ligne.replace('long', 'int64_t')
445 return ligne, None, False
449 ### runtime/explicit ###
451 def make_constructor_explicit(ligne, previous_ligne = None, warning=None):
452 m = re.match("(\s*)(.+)", ligne)
454 print('group_0', m.group(0))
455 print('group_1', m.group(1))
456 print('group_2', m.group(2))
457 ligne = ligne.replace(m.group(2), 'explicit '+m.group(2))
459 return ligne, None, False
461 ########################
463 ### build/include ###
465 def cpp_file_should_include_h_file(ficpath, ficline, warning):
466 fic = open(get_src_path(ficpath),'r')
467 liste = fic_readlines(fic)
470 m = re.match("(.+) should include its header file (.+) (.+)", warning)
472 print('group_0', m.group(0))
473 print('group_1', m.group(1))
474 print('group_2', m.group(2))
475 # Nouveau chemin du fichier .h
476 new_h_file_path = m.group(2)
479 h_file_name = os.path.basename(new_h_file_path)
481 # Recherche de la ligne à modifier
483 m2 = re.match("#include.*"+h_file_name+".*", ligne)
485 print("FOUND : ", ligne)
486 new_liste.append("#include \""+new_h_file_path+"\"\n")
488 print("NOT FOUND : ", ligne)
489 new_liste.append(ligne)
491 print("ERROR : Pattern not found : \"should include its header file\"")
493 newliste=fic_writelines(new_liste)
494 fichier = open(get_src_path(ficpath), "w")
495 fichier.writelines(newliste)
497 def _h_file_already_included(ligne, previous_ligne = None, warning=None):
498 return "", None, False
501 #####################
503 ### whitespace/blank_line ###
505 def do_not_leave_blank_line_after_public_protected_private(ficpath, ficline, warning):
506 fic = open(get_src_path(ficpath),'r')
507 liste = fic_readlines(fic)
512 if re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
513 # Détection d'une ligne public:, protected: ou :private
515 if flag and ligne.isspace():
516 # Supprimer les lignes vides après public:, protected: et :private
517 print("Deleting empty line")
520 if not ligne.isspace() and not re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
522 new_liste.append(ligne)
524 newliste=fic_writelines(new_liste)
525 fichier = open(get_src_path(ficpath), "w")
526 fichier.writelines(newliste)
528 def do_not_leave_blank_line_at_the_start_of_code_block(ficpath, ficline, warning):
529 fic = open(get_src_path(ficpath),'r')
530 liste = fic_readlines(fic)
535 if re.match(".*{", ligne):
536 # Détection d'un début de bloc
538 if flag and ligne.isspace():
539 # Supprimer les lignes vides après un début de bloc
540 print("Deleting empty line")
543 if not ligne.isspace() and not re.match(".*{", ligne):
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 do_not_leave_blank_line_at_the_end_of_code_block(ficpath, ficline, warning):
552 fic = open(get_src_path(ficpath),'r')
553 liste = fic_readlines(fic)
558 if re.match(".*}", ligne):
559 # Détection d'une fin de bloc -> suppression des nb_blank_lines lignes vides précédentes
560 for i in range(0, nb_blank_lines):
566 new_liste.append(ligne)
568 newliste=fic_writelines(new_liste)
569 fichier = open(get_src_path(ficpath), "w")
570 fichier.writelines(newliste)
572 def add_blank_line_before_public(ligne, previous_ligne = None, warning=None):
575 return ligne, None, False
577 def add_blank_line_before_protected(ligne, previous_ligne = None, warning=None):
580 return ligne, None, False
582 def add_blank_line_before_private(ligne, previous_ligne = None, warning=None):
585 return ligne, None, False
587 ##############################
589 ### build/include_what_you_use ###
591 def add_include_what_you_use(ficpath, ficline, warning):
593 Ajoute le #include suggéré dans le warning
596 fic = open(get_src_path(ficpath), "r")
597 liste = fic_readlines(fic)
599 m = re.match("\s*Add (.+) for (.+)", warning)
601 print('group_0', m.group(0))
602 print('group_1', m.group(1))
605 # Recherche la ligne dans laquelle ajouter le #include
606 # On l'ajoutera après le dernier "#include <..."
608 num_ligne_include_system = 0
609 num_ligne_include_local = 0
612 if ligne.find('#include <') > -1:
613 num_ligne_include_system = num_ligne
614 elif ligne.find('#include "') > -1:
615 num_ligne_include_local = num_ligne
617 num_ligne_include = max(num_ligne_include_system, num_ligne_include_local)
618 if num_ligne_include == 0:
619 print("WARNING : #include not found in file ", ficpath)
624 fic2 = open(get_src_path(ficpath), "r")
625 liste2 = fic_readlines(fic2)
628 new_liste.append(ligne)
629 if num_ligne == num_ligne_include:
630 new_liste.append(include+'\n')
632 newliste=fic_writelines(new_liste)
633 fichier = open(get_src_path(ficpath), "w")
634 fichier.writelines(newliste)
636 print("ERROR : Pattern of include_what_you_use not found")
639 ##################################
643 extra_space_before_last_semicolon:{'pattern':'whitespace/semicolon', 'pattern_AND':'Extra space before last semicolon'},
644 missing_space_after_semicolon:{'pattern':'whitespace/semicolon', 'pattern_AND':'Missing space after'},
645 missing_space_around_operator_egal:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around = '},
646 extra_space_for_operator_add:{'pattern':'whitespace/operators', 'pattern_AND':'Extra space for operator ++'},
647 extra_space_for_operator_diff:{'pattern':'whitespace/operators', 'pattern_AND':'Extra space for operator !'},
648 missing_space_around_operator_double_chevron:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around << '},
649 missing_space_around_operator_simple_chevron:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around < '},
650 missing_space_around_operator_diff_egal:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around !='},
651 missing_space_around_operator_double_egal:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around =='},
652 space_between_comments_and_code:{'pattern':'whitespace/comments', 'pattern_AND':'At least two spaces is best between code and comments'},
653 space_between_comments_and_double_slash:{'pattern':'whitespace/comments', 'pattern_AND':'Should have a space between // and comment '},
654 legal_copyright:{'pattern':'legal/copyright'}, # Script à n'executer qu'une fois
655 ifndef_header:{'pattern':'build/header_guard', 'pattern_AND':'#ifndef header guard has wrong style, please use'},
656 # no_ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'No #ifndef header guard found'},
657 endif_line:{'pattern':'build/header_guard', 'pattern_AND':'#endif line should be'},
658 whitespace_end_of_line:{'pattern':'whitespace/end_of_line', 'pattern_AND':'Line ends in whitespace'},
659 missing_space_after_comma:{'pattern':'whitespace/comma'},
660 namespace_should_be_terminated:{'pattern':'readability/namespace', 'pattern_AND':'Namespace should be terminated with'},
661 anonymous_namespace_should_be_terminated:{'pattern':'readability/namespace', 'pattern_AND':'Anonymous namespace should be terminated with'},
662 extra_space_after_opening_paranthesis:{'pattern':'whitespace/parens', 'pattern_AND':'Extra space after ('},
663 extra_space_before_closing_paranthesis:{'pattern':'whitespace/parens', 'pattern_AND':'Extra space before )'},
664 extra_space_before_opening_paranthesis_in_function_call:{'pattern':'whitespace/parens', 'pattern':'Extra space before ( in function call'},
665 missing_space_before_opening_parenthesis_in_for:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in for('},
666 missing_space_before_opening_parenthesis_in_if:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in if('},
667 missing_space_before_opening_parenthesis_in_switch:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in switch('},
668 missing_space_before_opening_parenthesis_in_while:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in while('},
669 mismatching_spaces_inside_paranthesis:{'pattern':'whitespace/parens', 'pattern_AND':'Mismatching spaces inside ()'},
670 missing_space_before_public_protected_private:{'pattern':'whitespace/indent', 'pattern_AND':' should be indented +1 space inside class'},
672 wrong_number_of_spaces_while_indenting:{'pattern':'whitespace/indent', 'pattern_AND':'Weird number of spaces at line-start'},
674 no_newline_at_the_end_of_file:{'pattern':'whitespace/ending_newline'},
676 order_of_storage_class_specifier:{'pattern':'build/storage_class'},
678 use_spaces_instead_of_tab:{'pattern':'whitespace/tab'},
680 no_semicolon_after_brace:{'pattern':'readability/braces', 'pattern_AND':'You don\'t need a ; after a }'},
681 # position_of_else:{'pattern':u'readability/braces', 'pattern_AND':u'If an else has a brace on one side'},
682 # else_should_be_previous_line:{'pattern':u'whitespace/newline', 'pattern_AND':u'An else should appear on the same line as the preceding'},
683 position_of_opening_brace:{'pattern':'whitespace/braces', 'pattern_AND':'{ should almost always be at the end of the previous line'},
684 missing_space_before_opening_brace:{'pattern':'whitespace/braces', 'pattern_AND':'Missing space before {'},
685 missing_space_before_else:{'pattern':'whitespace/braces', 'pattern_AND':'Missing space before else'},
687 make_const_reference:{'pattern':'runtime/references', 'pattern_AND':'Is this a non-const reference? If so, make const or use a pointer'},
689 make_constructor_explicit:{'pattern':'runtime/explicit'},
691 cpp_file_should_include_h_file:{'pattern':'build/include', 'pattern_AND':'should include its header file'},
692 _h_file_already_included:{'pattern':'build/include', 'pattern_AND':'already included at'},
694 replace_short_by_int16:{'pattern':'runtime/int', 'pattern_AND':'Use int16/int64/etc, rather than the C type short'},
695 replace_long_by_int64:{'pattern':'runtime/int', 'pattern_AND':'Use int16/int64/etc, rather than the C type long'},
697 do_not_leave_blank_line_after_public_protected_private:{'pattern':'whitespace/blank_line', 'pattern_AND':'Do not leave a blank line after'},
698 do_not_leave_blank_line_at_the_start_of_code_block:{'pattern':'whitespace/blank_line', 'pattern_AND':'Redundant blank line at the start of a code block should be deleted'},
699 do_not_leave_blank_line_at_the_end_of_code_block:{'pattern':'whitespace/blank_line', 'pattern_AND':'Redundant blank line at the end of a code block should be deleted'},
700 add_blank_line_before_public:{'pattern':'whitespace/blank_line', 'pattern_AND':'"public:" should be preceded by a blank line'},
701 add_blank_line_before_protected:{'pattern':'whitespace/blank_line', 'pattern_AND':'"protected:" should be preceded by a blank line'},
702 add_blank_line_before_private:{'pattern':'whitespace/blank_line', 'pattern_AND':'"private:" should be preceded by a blank line'},
704 add_include_what_you_use:{'pattern':'build/include_what_you_use'},
708 HOOKS_DELETING_OR_ADDING_LINES = [no_newline_at_the_end_of_file, position_of_opening_brace, _h_file_already_included,
709 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]
710 HOOKS_PARSING_THE_WHOLE_FILE = [cpp_file_should_include_h_file, do_not_leave_blank_line_after_public_protected_private,
711 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
713 def replace_line_no(path, nol, oldline, newline):
715 Remplace, la ligne No nol du fichier path (relatif à SRCROOTDIR) par la chaîne newline (un unicode)
716 oldline sert uniquement pour vérifier que tout est ok
718 print("replace_line_no : ", oldline, " by ", newline)
719 # récupérer le contenu du fichier
720 fic = open(get_src_path(path), "r")
721 liste = fic.readlines()
724 if liste[nol-1].decode(ENCODING) != oldline :
725 raise Exception("Le fichier source %s semble être corrompu" %path)
726 # remplacement de la ligne
727 liste[nol-1] = newline.encode(ENCODING)
728 # recréation du fichier corrigé
729 fic = open(get_src_path(path), "w")
730 fic.writelines(liste)
733 def replace_fic_copyright(ficpath, warning=None):
735 Remplace le fichier sans la ligne copyright par le fichier avec la ligne copyright
738 fic = open(get_src_path(ficpath), "r")
739 liste=fic_readlines(fic)
742 if liste[0].find('/ Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n')== -1:
743 newliste=['// Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n']+liste
744 newliste=fic_writelines(newliste)
745 fic = open(get_src_path(ficpath), "w")
746 fic.writelines(newliste)
750 def replace_fic_ifndef(ficpath, ficline, warning, mode):
752 Remplace dans le fichier, toutes les erreurs sur le style des #define et #ifndef à partir du warning
754 fic = open(get_src_path(ficpath),'r')
755 liste = fic_readlines(fic)
758 if mode == "no_guard_found":
759 m = re.match("(.*)No #ifndef header guard found, suggested CPP variable is: (.+) (.+)", warning)
761 m = re.match("(.*)ifndef header guard has wrong style, please use: (.+) (.+)", warning)
764 print('group_0', m.group(0))
765 print('group_1', m.group(1))
766 print('group_2', m.group(2))
769 header_guard=m.group(2)
771 # Recherche de la ligne à modifier
777 if ligne.find('#ifndef') >= 0:
778 new_liste.append("#ifndef "+header_guard+"\n")
781 print("ERROR : Pattern #ifndef not found in line ", ficline)
785 if ligne.find('#define') >= 0:
786 new_liste.append("#define "+header_guard+"\n")
789 print("WARNING : Pattern #define not found in the line following the pattern #ifndef, we abandon.")
792 new_liste.append(ligne)
794 print("ERROR : Pattern not found : \"#ifndef header guard has wrong style, please use\"")
796 newliste=fic_writelines(new_liste)
797 fichier = open(get_src_path(ficpath), "w")
798 fichier.writelines(newliste)
801 def get_hook(warning, fichier):
803 Fait le matching entre un warning et le hook permettant de le traiter.
804 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.
805 Le format de chaque dict de critère est le suivant :
807 "pattern": <motif principal devant se trouver dans le texte du warning>,
808 "pattern_AND": <motif secondaire devant se trouver également dans le texte du warning>,
809 "pattern_NOT": <motif secondaire ne devant pas se trouver dans le texte du warning>,
810 "ext": <extension du fichier considéré>
812 Seul le premier hook trouvé est renvoyé.
813 Les arguments sont les suivants :
814 * warning : le texte unicode du warning
815 * fichier : le chemin vers le fichier concerné
817 def test_it(condition, data, warning, fichier):
818 if condition in ["pattern", "pattern_AND"] :
821 elif condition in ["PATTERN_NOT"]:
822 if data not in warning:
824 elif condition in ["ext"]:
825 if data not in os.path.splitext(fichier)[1]:
829 for key, val in HOOKS_DICT.items(): # boucle sur les hooks existants
831 for condition, data in val.items():
833 # si une condition n'est pas réalisée => c'est pas le bon hook
835 test = test_it(condition, data, warning, fichier)
840 def main_routine(cpplint_output_file):
841 logfile = open(cpplint_output_file,"r")
842 generateur_w = create_warning_generator(logfile)
843 last_ficpath_with_modified_nb_lines = ""
844 for ficpath, ficline, warning in generateur_w:
845 oldline = get_line_no(ficpath, ficline)
847 previous_oldline = get_line_no(ficpath, ficline-1)
849 previous_oldline = None
850 print("===\nNew warning:")
851 print("\tFile = "+ficpath)
852 print("\tlast_ficpath_with_modified_nb_lines = "+last_ficpath_with_modified_nb_lines)
853 print("\tNo ligne =" , ficline)
854 if VERBOSE_FLAG == "True":
855 print("\tWarning ='"+warning+"'")
856 print("\tOld text of current line = '"+oldline+"'")
858 print("\tOld text of previous line = '"+previous_oldline+"'")
859 if ficpath == last_ficpath_with_modified_nb_lines:
860 print("File ", ficpath, "already modified. Waiting next cpplint run to process it.")
862 hook = get_hook(warning, ficpath)
863 print("hook = ", hook)
865 print("No hook found")
868 if VERBOSE_FLAG == "True":
869 print("\t=> Processing with hook", hook)
871 if hook in HOOKS_DELETING_OR_ADDING_LINES:
872 last_ficpath_with_modified_nb_lines = ficpath
874 if hook in HOOKS_PARSING_THE_WHOLE_FILE:
875 hook(ficpath, ficline, warning)
879 # 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
880 if hook in [make_const_reference]:
881 if ficpath.find('.h') > -1:
882 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
884 if H_FILE_MAKE_CONST_REFERENCE_MODIFIED:
887 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
889 newline, previous_newline, huchk = hook(oldline, previous_oldline, warning)
891 if VERBOSE_FLAG == "True":
892 print("\tNew text = '"+newline+"'")
895 print("Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(previous_oldline, previous_newline))
897 if reponse in ['O', 'o']:
898 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
899 print("Replacement done.")
901 print("Replacement aborted.")
903 print("Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(oldline, newline))
905 if reponse in ['O', 'o']:
906 replace_line_no(ficpath, ficline, oldline, newline)
907 print("Replacement done.")
909 print("Replacement aborted.")
914 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
915 replace_line_no(ficpath, ficline, oldline, newline)
919 if __name__ == '__main__':
920 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = False
922 parser = argparse.ArgumentParser()
923 parser.add_argument("--cpplint_output_file", type=str, help="Fichier de rapport cpplint à lire en entrée")
924 args = parser.parse_args()
926 if not args.cpplint_output_file:
929 main_routine(args.cpplint_output_file)