1 # Copyright (C) 2014-2023 CEA, EDF
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 import os, os.path, sys, re, argparse
30 #### définition des hooks.
32 # * avoir le prototype suivant : def <nom_hook>(<unicode>) avec <unicode> la ligne de texte à corriger
33 # * retourner deux valeurs : la ligne corrigée, en unicode et un booléen indiquant s'il faut faire un check humain avant de corriger
34 # * être inséré dans HOOKS_DICT en y faisant correspondre un dico explicitant les critères de séléction de ce hook
37 ### whitespace/semicolon ###
39 def extra_space_before_last_semicolon(ligne, previous_ligne = None, warning=None):
40 liste=ligne.split(';\n')
42 ligne3=ligne2.rstrip()
44 return ligne, previous_ligne, False
46 def missing_space_after_semicolon(ligne, previous_ligne = None, warning=None):
47 ligne=ligne.replace(';','; ')
48 return ligne, previous_ligne, False
50 #########################
52 ### whitespace/operators ###
54 def missing_space_around_operator_egal(ligne, previous_ligne = None, warning=None):
57 previouschar=ligne[i-1]
58 if nextchar not in OPERATORS and previouschar not in OPERATORS:
59 if nextchar.isspace() == False and previouschar.isspace()==True:
60 ligne=ligne.replace('=', '= ')
61 elif nextchar.isspace() == True and previouschar.isspace()==False:
62 ligne=ligne.replace('=', ' =')
63 elif nextchar.isspace() == False and previouschar.isspace()==False:
64 ligne=ligne.replace('=', ' = ')
67 return ligne, previous_ligne, False
69 def extra_space_for_operator_add(ligne, previous_ligne = None, warning=None):
70 while ligne.find('++ ') > -1:
71 ligne = ligne.replace('++ ','++')
72 while ligne.find(' ++') > -1 and ligne.find('; ++') == -1:
73 ligne = ligne.replace(' ++','++')
74 return ligne, previous_ligne, False
76 def extra_space_for_operator_diff(ligne, previous_ligne = None, warning=None):
77 while ligne.find('! ') > -1:
78 ligne = ligne.replace('! ','!')
79 return ligne, previous_ligne, False
81 def missing_space_around_operator_double_chevron(ligne, previous_ligne = None, warning=None):
84 previouschar=ligne[i-1]
85 if nextchar.isspace() == False and previouschar.isspace()==True:
86 ligne=ligne.replace('<<', '<< ')
87 elif nextchar.isspace() == True and previouschar.isspace()==False:
88 ligne=ligne.replace('<<', ' <<')
89 elif nextchar.isspace() == False and previouschar.isspace()==False:
90 ligne=ligne.replace('<<', ' << ')
93 return ligne, previous_ligne, False
95 def missing_space_around_operator_simple_chevron(ligne, previous_ligne = None, warning=None):
98 previouschar=ligne[i-1]
99 if nextchar not in OPERATORS and previouschar not in OPERATORS:
100 if nextchar.isspace() == False and previouschar.isspace()==True:
101 ligne=ligne.replace('<', '< ')
102 elif nextchar.isspace() == True and previouschar.isspace()==False:
103 ligne=ligne.replace('<', ' <')
104 elif nextchar.isspace() == False and previouschar.isspace()==False:
105 ligne=ligne.replace('<', ' < ')
108 return ligne, previous_ligne, False
111 def missing_space_around_operator_diff_egal(ligne, previous_ligne = None, warning=None):
114 previouschar=ligne[i-1]
115 if nextchar.isspace() == False and previouschar.isspace()==True:
116 ligne=ligne.replace('!=', '!= ')
117 elif nextchar.isspace() == True and previouschar.isspace()==False:
118 ligne=ligne.replace('!=', ' !=')
119 elif nextchar.isspace() == False and previouschar.isspace()==False:
120 ligne=ligne.replace('!=', ' != ')
123 return ligne, previous_ligne, False
125 def missing_space_around_operator_double_egal(ligne, previous_ligne = None, warning=None):
128 previouschar=ligne[i-1]
129 if nextchar.isspace() == False and previouschar.isspace()==True:
130 ligne=ligne.replace('==', '== ')
131 elif nextchar.isspace() == True and previouschar.isspace()==False:
132 ligne=ligne.replace('==', ' ==')
133 elif nextchar.isspace() == False and previouschar.isspace()==False:
134 ligne=ligne.replace('==', ' == ')
137 return ligne, previous_ligne, False
140 #########################
142 ### whitespace/comments ###
144 def space_between_comments_and_code(ligne, previous_ligne = None, warning=None):
145 if ligne.find('//')>=0 :
146 ligne=ligne.replace('//', ' //')
147 elif ligne.find(' //')>=0 :
148 ligne=ligne.replace(' //', ' //')
151 return ligne, previous_ligne, False
153 def space_between_comments_and_double_slash(ligne, previous_ligne = None, warning=None):
154 return ligne.replace('//', '// '), previous_ligne, False
156 #########################
159 ### legal/copyright ###
161 def legal_copyright(ficpath, ficline, warning=None):
162 replace_fic_copyright(ficpath)
164 #########################
166 ### build/header_guard
168 def ifndef_header(ficpath, ficline, warning):
169 replace_fic_ifndef(ficpath, ficline, warning, "wrong_style")
171 #def no_ifndef_header(ficpath, ficline, warning):
172 # replace_fic_ifndef(ficpath, ficline, warning, "no_guard_found")
174 def endif_line(ligne, previous_ligne = None, warning=None):
175 liste1=warning.split('// ')
177 liste2=ligne1.split('"')
178 header_guard=liste2[0]
179 ligne= '#endif // ' + header_guard +'\n'
180 return ligne, previous_ligne, False
182 #########################
184 ### whitespace/end_of_ligne ###
186 def whitespace_end_of_line(ligne, previous_ligne = None, warning=None):
187 ligne = ligne.rstrip()+'\n'
189 return ligne, previous_ligne, False
191 #########################
193 ### whitespace/comma ###
195 def missing_space_after_comma(ligne, previous_ligne = None, warning=None):
196 ligne=ligne.replace(',',', ')
197 return ligne, previous_ligne, False
199 #########################
201 ### readability/namespace ###
203 def namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
204 ligne2=ligne.rstrip('\n')
205 liste = warning.split('"')
207 if ligne.find('\r')>=0:
208 ligne=ligne2+' '+namespace+'\r\n'
210 ligne=ligne2+' '+namespace+'\n'
211 return ligne, previous_ligne, False
213 def anonymous_namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
214 ligne2=ligne.rstrip('\n')
215 ligne=ligne2+' // namespace\n'
216 return ligne, previous_ligne, False
218 #########################
220 ### whitespace/parens ###
222 def extra_space_after_opening_paranthesis(ligne, previous_ligne = None, warning=None):
223 while ligne.find('( ') > -1:
224 ligne = ligne.replace('( ','(')
225 return ligne, previous_ligne, False
227 def extra_space_before_closing_paranthesis(ligne, previous_ligne = None, warning=None):
228 while ligne.find(' )') > -1:
229 ligne = ligne.replace(' )',')')
230 return ligne, previous_ligne, False
232 def extra_space_before_opening_paranthesis_in_function_call(ligne, previous_ligne = None, warning=None):
233 while ligne.find(' (') > -1 and ligne.find(', (')==-1:
234 ligne = ligne.replace(' (','(')
235 return ligne, previous_ligne, False
237 def missing_space_before_opening_parenthesis_in_for(ligne, previous_ligne = None, warning=None):
238 return ligne.replace('for(','for ('), previous_ligne, False
240 def missing_space_before_opening_parenthesis_in_if(ligne, previous_ligne = None, warning=None):
241 return ligne.replace('if(','if ('), previous_ligne, False
243 def missing_space_before_opening_parenthesis_in_switch(ligne, previous_ligne = None, warning=None):
244 return ligne.replace('switch(','switch ('), previous_ligne, False
246 def missing_space_before_opening_parenthesis_in_while(ligne, previous_ligne = None, warning=None):
247 return ligne.replace('while(','while ('), previous_ligne, False
249 def mismatching_spaces_inside_paranthesis(ligne, previous_ligne = None, warning=None):
250 while ligne.find('( ') > -1:
251 ligne = ligne.replace('( ','(')
252 while ligne.find(' )') > -1:
253 ligne = ligne.replace(' )',')')
254 return ligne, previous_ligne, False
256 #########################
258 ### whitespace/newline ###
260 def else_should_be_previous_line(ligne, previous_ligne=None, warning=None):
261 return position_of_else(ligne, previous_ligne, warning)
263 #########################
265 ### whitespace/indent ###
267 def missing_space_before_public_protected_private(ligne, previous_ligne = None, warning=None):
268 # Ajout d'un espace avant public:, protected: et :private
269 if re.match("public.*:|protected.*:|private.*:", ligne):
272 return ligne, previous_ligne, False
274 def wrong_number_of_spaces_while_indenting(ligne, previous_ligne = None, warning=None):
275 # Le nombre d'espaces pour l'indentation doit être pair
276 if re.match("\s{1}\S+|\s{3}\S+|\s{5}\S+|\s{7}\S+|\s{9}\S+", ligne):
277 if not re.match(" public.*:| protected.*:| private.*:| \*", ligne):
279 # Suppression des espaces superflus sur une ligne sans code
283 # Remplacement des tabulations par 8 espaces en début de ligne
284 ligne = ligne.replace("\t", " ")
286 return ligne, previous_ligne, False
287 #########################
289 ### whitespace/ending_newline ###
291 def no_newline_at_the_end_of_file(ligne, previous_ligne = None, warning=None):
293 return ligne, None, False
295 #################################
297 ### build/storage_class ###
299 def order_of_storage_class_specifier(ligne, previous_ligne = None, warning=None):
300 if re.match("\s*const static", ligne):
301 # Inversion de const static en static const
302 ligne = ligne.replace("const static", "static const")
304 return ligne, previous_ligne, False
306 ###########################
308 ### whitespace/tab ###
310 def use_spaces_instead_of_tab(ligne, previous_ligne = None, warning=None):
311 if re.match(".*\t", ligne):
312 # Remplacement des tabulations par 8 espaces
313 ligne = ligne.replace("\t", " ")
315 return ligne, previous_ligne, False
317 ######################
319 ### readability/braces ###
321 def no_semicolon_after_brace(ligne, previous_ligne = None, warning=None):
322 return ligne.replace('};','}'), previous_ligne, False
324 def position_of_else(ligne, previous_ligne=None, warning=None):
325 '''Remonte une ligne du type } else {'''
327 if '}' not in previous_ligne:
328 # Si on ne trouve pas de '}' sur la ligne précédente, on ne fait rien
329 return ligne, None, False
331 m = re.match("(.*)else(.*)", ligne)
333 previous_ligne = previous_ligne.rstrip("\n") + ' else' + m.group(2) + '\n'
335 return ligne, previous_ligne, False
337 ##########################
339 ### whitespace/braces ###
341 def position_of_opening_brace(ligne, previous_ligne=None, warning=None):
342 '''Remonte le { sur la ligne du dessus'''
344 m = re.match("(\s*){(.*)", ligne)
346 # On ne fait rien si on trouve un commentaire sur la ligne précédente (ce sera une correction manuelle)
347 if previous_ligne.find('//') == -1:
348 previous_ligne = previous_ligne.rstrip("\n") + ' {' + m.group(2) + '\n'
351 print("The previous line contains a comment, fixing has to be manual.")
353 return ligne, previous_ligne, False
355 def missing_space_before_opening_brace(ligne, previous_ligne = None, warning=None):
356 m = re.match("(.+)(\S){(.*)", ligne)
358 print('group_0', m.group(0))
359 print('group_1', m.group(1))
360 print('group_2', m.group(2))
361 print('group_3', m.group(3))
362 ligne = m.group(1) + m.group(2) + ' {' + m.group(3) + '\n'
364 return ligne, previous_ligne, False
367 #########################
370 def missing_space_before_else(ligne, previous_ligne = None, warning=None):
371 m = re.match("(.+)(\S)else(.*)", ligne)
373 print('group_0', m.group(0))
374 print('group_1', m.group(1))
375 print('group_2', m.group(2))
376 print('group_3', m.group(3))
377 ligne = m.group(1) + m.group(2) + ' else' + m.group(3) + '\n'
379 return ligne, previous_ligne, False
381 ### runtime/references ###
383 def make_const_reference(ficpath, ligne, previous_ligne = None, warning=None):
384 """ Adding keyword 'const' """
385 print("ficpath = ", ficpath)
386 print("ligne = ", ligne)
387 print("warning = ", warning)
388 m = re.match("(.+)Is this a non-const reference\? If so, make const or use a pointer: (.+) (.+)", warning)
390 print('group_0', m.group(0))
391 print('group_1', m.group(1))
392 print('group_2', m.group(2))
393 print('group_3', m.group(3))
394 arg_to_modify = m.group(2)
395 ligne = ligne.replace(arg_to_modify, "const "+arg_to_modify)
397 # Répercution des corrections dans le fichier ".cpp" correspondant si c'est un fichier ".h"
398 if ficpath.find('.h') > -1:
399 cpp_file_path = ficpath.replace('.h', '.cpp')
400 make_const_reference_cpp_file(cpp_file_path, arg_to_modify)
401 global H_FILE_MAKE_CONST_REFERENCE_MODIFIED
402 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = True
404 print("ERROR : The following pattern was not found : 'Is this a non-const reference? If so, make const or use a pointer:'")
406 return ligne, previous_ligne, False
408 def make_const_reference_cpp_file(ficpath, arg_to_modify):
409 if not os.path.isfile(ficpath):
410 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'")
413 fic = open(get_src_path(ficpath),'r')
414 liste = fic_readlines(fic)
418 # Recherche de l'argument à modifier
419 if(ligne.find(arg_to_modify) > -1 and ligne.find('const '+arg_to_modify) == -1):
420 new_liste.append(ligne.replace(arg_to_modify, "const "+arg_to_modify))
422 new_liste.append(ligne)
424 newliste=fic_writelines(new_liste)
425 fichier = open(get_src_path(ficpath), "w")
426 fichier.writelines(newliste)
431 ##########################
435 def replace_short_by_int16(ligne, previous_ligne = None, warning=None):
436 ligne = ligne.replace('short', 'int16_t')
438 return ligne, None, False
440 def replace_long_by_int64(ligne, previous_ligne = None, warning=None):
441 ligne = ligne.replace('long', 'int64_t')
443 return ligne, None, False
447 ### runtime/explicit ###
449 def make_constructor_explicit(ligne, previous_ligne = None, warning=None):
450 m = re.match("(\s*)(.+)", ligne)
452 print('group_0', m.group(0))
453 print('group_1', m.group(1))
454 print('group_2', m.group(2))
455 ligne = ligne.replace(m.group(2), 'explicit '+m.group(2))
457 return ligne, None, False
459 ########################
461 ### build/include ###
463 def cpp_file_should_include_h_file(ficpath, ficline, warning):
464 fic = open(get_src_path(ficpath),'r')
465 liste = fic_readlines(fic)
468 m = re.match("(.+) should include its header file (.+) (.+)", warning)
470 print('group_0', m.group(0))
471 print('group_1', m.group(1))
472 print('group_2', m.group(2))
473 # Nouveau chemin du fichier .h
474 new_h_file_path = m.group(2)
477 h_file_name = os.path.basename(new_h_file_path)
479 # Recherche de la ligne à modifier
481 m2 = re.match("#include.*"+h_file_name+".*", ligne)
483 print("FOUND : ", ligne)
484 new_liste.append("#include \""+new_h_file_path+"\"\n")
486 print("NOT FOUND : ", ligne)
487 new_liste.append(ligne)
489 print("ERROR : Pattern not found : \"should include its header file\"")
491 newliste=fic_writelines(new_liste)
492 fichier = open(get_src_path(ficpath), "w")
493 fichier.writelines(newliste)
495 def _h_file_already_included(ligne, previous_ligne = None, warning=None):
496 return "", None, False
499 #####################
501 ### whitespace/blank_line ###
503 def do_not_leave_blank_line_after_public_protected_private(ficpath, ficline, warning):
504 fic = open(get_src_path(ficpath),'r')
505 liste = fic_readlines(fic)
510 if re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
511 # Détection d'une ligne public:, protected: ou :private
513 if flag and ligne.isspace():
514 # Supprimer les lignes vides après public:, protected: et :private
515 print("Deleting empty line")
518 if not ligne.isspace() and not re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
520 new_liste.append(ligne)
522 newliste=fic_writelines(new_liste)
523 fichier = open(get_src_path(ficpath), "w")
524 fichier.writelines(newliste)
526 def do_not_leave_blank_line_at_the_start_of_code_block(ficpath, ficline, warning):
527 fic = open(get_src_path(ficpath),'r')
528 liste = fic_readlines(fic)
533 if re.match(".*{", ligne):
534 # Détection d'un début de bloc
536 if flag and ligne.isspace():
537 # Supprimer les lignes vides après un début de bloc
538 print("Deleting empty line")
541 if not ligne.isspace() and not re.match(".*{", ligne):
543 new_liste.append(ligne)
545 newliste=fic_writelines(new_liste)
546 fichier = open(get_src_path(ficpath), "w")
547 fichier.writelines(newliste)
549 def do_not_leave_blank_line_at_the_end_of_code_block(ficpath, ficline, warning):
550 fic = open(get_src_path(ficpath),'r')
551 liste = fic_readlines(fic)
556 if re.match(".*}", ligne):
557 # Détection d'une fin de bloc -> suppression des nb_blank_lines lignes vides précédentes
558 for i in range(0, nb_blank_lines):
564 new_liste.append(ligne)
566 newliste=fic_writelines(new_liste)
567 fichier = open(get_src_path(ficpath), "w")
568 fichier.writelines(newliste)
570 def add_blank_line_before_public(ligne, previous_ligne = None, warning=None):
573 return ligne, None, False
575 def add_blank_line_before_protected(ligne, previous_ligne = None, warning=None):
578 return ligne, None, False
580 def add_blank_line_before_private(ligne, previous_ligne = None, warning=None):
583 return ligne, None, False
585 ##############################
587 ### build/include_what_you_use ###
589 def add_include_what_you_use(ficpath, ficline, warning):
591 Ajoute le #include suggéré dans le warning
594 fic = open(get_src_path(ficpath), "r")
595 liste = fic_readlines(fic)
597 m = re.match("\s*Add (.+) for (.+)", warning)
599 print('group_0', m.group(0))
600 print('group_1', m.group(1))
603 # Recherche la ligne dans laquelle ajouter le #include
604 # On l'ajoutera après le dernier "#include <..."
606 num_ligne_include_system = 0
607 num_ligne_include_local = 0
610 if ligne.find('#include <') > -1:
611 num_ligne_include_system = num_ligne
612 elif ligne.find('#include "') > -1:
613 num_ligne_include_local = num_ligne
615 num_ligne_include = max(num_ligne_include_system, num_ligne_include_local)
616 if num_ligne_include == 0:
617 print("WARNING : #include not found in file ", ficpath)
622 fic2 = open(get_src_path(ficpath), "r")
623 liste2 = fic_readlines(fic2)
626 new_liste.append(ligne)
627 if num_ligne == num_ligne_include:
628 new_liste.append(include+'\n')
630 newliste=fic_writelines(new_liste)
631 fichier = open(get_src_path(ficpath), "w")
632 fichier.writelines(newliste)
634 print("ERROR : Pattern of include_what_you_use not found")
637 ##################################
641 extra_space_before_last_semicolon:{'pattern':'whitespace/semicolon', 'pattern_AND':'Extra space before last semicolon'},
642 missing_space_after_semicolon:{'pattern':'whitespace/semicolon', 'pattern_AND':'Missing space after'},
643 missing_space_around_operator_egal:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around = '},
644 extra_space_for_operator_add:{'pattern':'whitespace/operators', 'pattern_AND':'Extra space for operator ++'},
645 extra_space_for_operator_diff:{'pattern':'whitespace/operators', 'pattern_AND':'Extra space for operator !'},
646 missing_space_around_operator_double_chevron:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around << '},
647 missing_space_around_operator_simple_chevron:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around < '},
648 missing_space_around_operator_diff_egal:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around !='},
649 missing_space_around_operator_double_egal:{'pattern':'whitespace/operators', 'pattern_AND':'Missing spaces around =='},
650 space_between_comments_and_code:{'pattern':'whitespace/comments', 'pattern_AND':'At least two spaces is best between code and comments'},
651 space_between_comments_and_double_slash:{'pattern':'whitespace/comments', 'pattern_AND':'Should have a space between // and comment '},
652 legal_copyright:{'pattern':'legal/copyright'}, # Script à n'executer qu'une fois
653 ifndef_header:{'pattern':'build/header_guard', 'pattern_AND':'#ifndef header guard has wrong style, please use'},
654 # no_ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'No #ifndef header guard found'},
655 endif_line:{'pattern':'build/header_guard', 'pattern_AND':'#endif line should be'},
656 whitespace_end_of_line:{'pattern':'whitespace/end_of_line', 'pattern_AND':'Line ends in whitespace'},
657 missing_space_after_comma:{'pattern':'whitespace/comma'},
658 namespace_should_be_terminated:{'pattern':'readability/namespace', 'pattern_AND':'Namespace should be terminated with'},
659 anonymous_namespace_should_be_terminated:{'pattern':'readability/namespace', 'pattern_AND':'Anonymous namespace should be terminated with'},
660 extra_space_after_opening_paranthesis:{'pattern':'whitespace/parens', 'pattern_AND':'Extra space after ('},
661 extra_space_before_closing_paranthesis:{'pattern':'whitespace/parens', 'pattern_AND':'Extra space before )'},
662 extra_space_before_opening_paranthesis_in_function_call:{'pattern':'whitespace/parens', 'pattern':'Extra space before ( in function call'},
663 missing_space_before_opening_parenthesis_in_for:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in for('},
664 missing_space_before_opening_parenthesis_in_if:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in if('},
665 missing_space_before_opening_parenthesis_in_switch:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in switch('},
666 missing_space_before_opening_parenthesis_in_while:{'pattern':'whitespace/parens', 'pattern_AND':'Missing space before ( in while('},
667 mismatching_spaces_inside_paranthesis:{'pattern':'whitespace/parens', 'pattern_AND':'Mismatching spaces inside ()'},
668 missing_space_before_public_protected_private:{'pattern':'whitespace/indent', 'pattern_AND':' should be indented +1 space inside class'},
670 wrong_number_of_spaces_while_indenting:{'pattern':'whitespace/indent', 'pattern_AND':'Weird number of spaces at line-start'},
672 no_newline_at_the_end_of_file:{'pattern':'whitespace/ending_newline'},
674 order_of_storage_class_specifier:{'pattern':'build/storage_class'},
676 use_spaces_instead_of_tab:{'pattern':'whitespace/tab'},
678 no_semicolon_after_brace:{'pattern':'readability/braces', 'pattern_AND':'You don\'t need a ; after a }'},
679 # position_of_else:{'pattern':u'readability/braces', 'pattern_AND':u'If an else has a brace on one side'},
680 # else_should_be_previous_line:{'pattern':u'whitespace/newline', 'pattern_AND':u'An else should appear on the same line as the preceding'},
681 position_of_opening_brace:{'pattern':'whitespace/braces', 'pattern_AND':'{ should almost always be at the end of the previous line'},
682 missing_space_before_opening_brace:{'pattern':'whitespace/braces', 'pattern_AND':'Missing space before {'},
683 missing_space_before_else:{'pattern':'whitespace/braces', 'pattern_AND':'Missing space before else'},
685 make_const_reference:{'pattern':'runtime/references', 'pattern_AND':'Is this a non-const reference? If so, make const or use a pointer'},
687 make_constructor_explicit:{'pattern':'runtime/explicit'},
689 cpp_file_should_include_h_file:{'pattern':'build/include', 'pattern_AND':'should include its header file'},
690 _h_file_already_included:{'pattern':'build/include', 'pattern_AND':'already included at'},
692 replace_short_by_int16:{'pattern':'runtime/int', 'pattern_AND':'Use int16/int64/etc, rather than the C type short'},
693 replace_long_by_int64:{'pattern':'runtime/int', 'pattern_AND':'Use int16/int64/etc, rather than the C type long'},
695 do_not_leave_blank_line_after_public_protected_private:{'pattern':'whitespace/blank_line', 'pattern_AND':'Do not leave a blank line after'},
696 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'},
697 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'},
698 add_blank_line_before_public:{'pattern':'whitespace/blank_line', 'pattern_AND':'"public:" should be preceded by a blank line'},
699 add_blank_line_before_protected:{'pattern':'whitespace/blank_line', 'pattern_AND':'"protected:" should be preceded by a blank line'},
700 add_blank_line_before_private:{'pattern':'whitespace/blank_line', 'pattern_AND':'"private:" should be preceded by a blank line'},
702 add_include_what_you_use:{'pattern':'build/include_what_you_use'},
706 HOOKS_DELETING_OR_ADDING_LINES = [no_newline_at_the_end_of_file, position_of_opening_brace, _h_file_already_included,
707 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]
708 HOOKS_PARSING_THE_WHOLE_FILE = [cpp_file_should_include_h_file, do_not_leave_blank_line_after_public_protected_private,
709 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
711 def replace_line_no(path, nol, oldline, newline):
713 Remplace, la ligne No nol du fichier path (relatif à SRCROOTDIR) par la chaîne newline (un unicode)
714 oldline sert uniquement pour vérifier que tout est ok
716 print("replace_line_no : ", oldline, " by ", newline)
717 # récupérer le contenu du fichier
718 fic = open(get_src_path(path), "r")
719 liste = fic.readlines()
722 if liste[nol-1].decode(ENCODING) != oldline :
723 raise Exception("Le fichier source %s semble être corrompu" %path)
724 # remplacement de la ligne
725 liste[nol-1] = newline.encode(ENCODING)
726 # recréation du fichier corrigé
727 fic = open(get_src_path(path), "w")
728 fic.writelines(liste)
731 def replace_fic_copyright(ficpath, warning=None):
733 Remplace le fichier sans la ligne copyright par le fichier avec la ligne copyright
736 fic = open(get_src_path(ficpath), "r")
737 liste=fic_readlines(fic)
740 if liste[0].find('/ Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n')== -1:
741 newliste=['// Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n']+liste
742 newliste=fic_writelines(newliste)
743 fic = open(get_src_path(ficpath), "w")
744 fic.writelines(newliste)
748 def replace_fic_ifndef(ficpath, ficline, warning, mode):
750 Remplace dans le fichier, toutes les erreurs sur le style des #define et #ifndef à partir du warning
752 fic = open(get_src_path(ficpath),'r')
753 liste = fic_readlines(fic)
756 if mode == "no_guard_found":
757 m = re.match("(.*)No #ifndef header guard found, suggested CPP variable is: (.+) (.+)", warning)
759 m = re.match("(.*)ifndef header guard has wrong style, please use: (.+) (.+)", warning)
762 print('group_0', m.group(0))
763 print('group_1', m.group(1))
764 print('group_2', m.group(2))
767 header_guard=m.group(2)
769 # Recherche de la ligne à modifier
775 if ligne.find('#ifndef') >= 0:
776 new_liste.append("#ifndef "+header_guard+"\n")
779 print("ERROR : Pattern #ifndef not found in line ", ficline)
783 if ligne.find('#define') >= 0:
784 new_liste.append("#define "+header_guard+"\n")
787 print("WARNING : Pattern #define not found in the line following the pattern #ifndef, we abandon.")
790 new_liste.append(ligne)
792 print("ERROR : Pattern not found : \"#ifndef header guard has wrong style, please use\"")
794 newliste=fic_writelines(new_liste)
795 fichier = open(get_src_path(ficpath), "w")
796 fichier.writelines(newliste)
799 def get_hook(warning, fichier):
801 Fait le matching entre un warning et le hook permettant de le traiter.
802 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.
803 Le format de chaque dict de critère est le suivant :
805 "pattern": <motif principal devant se trouver dans le texte du warning>,
806 "pattern_AND": <motif secondaire devant se trouver également dans le texte du warning>,
807 "pattern_NOT": <motif secondaire ne devant pas se trouver dans le texte du warning>,
808 "ext": <extension du fichier considéré>
810 Seul le premier hook trouvé est renvoyé.
811 Les arguments sont les suivants :
812 * warning : le texte unicode du warning
813 * fichier : le chemin vers le fichier concerné
815 def test_it(condition, data, warning, fichier):
816 if condition in ["pattern", "pattern_AND"] :
819 elif condition in ["PATTERN_NOT"]:
820 if data not in warning:
822 elif condition in ["ext"]:
823 if data not in os.path.splitext(fichier)[1]:
827 for key, val in HOOKS_DICT.items(): # boucle sur les hooks existants
829 for condition, data in val.items():
831 # si une condition n'est pas réalisée => c'est pas le bon hook
833 test = test_it(condition, data, warning, fichier)
838 def main_routine(cpplint_output_file):
839 logfile = open(cpplint_output_file,"r")
840 generateur_w = create_warning_generator(logfile)
841 last_ficpath_with_modified_nb_lines = ""
842 for ficpath, ficline, warning in generateur_w:
843 oldline = get_line_no(ficpath, ficline)
845 previous_oldline = get_line_no(ficpath, ficline-1)
847 previous_oldline = None
848 print("===\nNew warning:")
849 print("\tFile = "+ficpath)
850 print("\tlast_ficpath_with_modified_nb_lines = "+last_ficpath_with_modified_nb_lines)
851 print("\tNo ligne =" , ficline)
852 if VERBOSE_FLAG == "True":
853 print("\tWarning ='"+warning+"'")
854 print("\tOld text of current line = '"+oldline+"'")
856 print("\tOld text of previous line = '"+previous_oldline+"'")
857 if ficpath == last_ficpath_with_modified_nb_lines:
858 print("File ", ficpath, "already modified. Waiting next cpplint run to process it.")
860 hook = get_hook(warning, ficpath)
861 print("hook = ", hook)
863 print("No hook found")
866 if VERBOSE_FLAG == "True":
867 print("\t=> Processing with hook", hook)
869 if hook in HOOKS_DELETING_OR_ADDING_LINES:
870 last_ficpath_with_modified_nb_lines = ficpath
872 if hook in HOOKS_PARSING_THE_WHOLE_FILE:
873 hook(ficpath, ficline, warning)
877 # 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
878 if hook in [make_const_reference]:
879 if ficpath.find('.h') > -1:
880 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
882 if H_FILE_MAKE_CONST_REFERENCE_MODIFIED:
885 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
887 newline, previous_newline, huchk = hook(oldline, previous_oldline, warning)
889 if VERBOSE_FLAG == "True":
890 print("\tNew text = '"+newline+"'")
893 print("Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(previous_oldline, previous_newline))
895 if reponse in ['O', 'o']:
896 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
897 print("Replacement done.")
899 print("Replacement aborted.")
901 print("Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(oldline, newline))
903 if reponse in ['O', 'o']:
904 replace_line_no(ficpath, ficline, oldline, newline)
905 print("Replacement done.")
907 print("Replacement aborted.")
912 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
913 replace_line_no(ficpath, ficline, oldline, newline)
917 if __name__ == '__main__':
918 H_FILE_MAKE_CONST_REFERENCE_MODIFIED = False
920 parser = argparse.ArgumentParser()
921 parser.add_argument("--cpplint_output_file", type=str, help="Fichier de rapport cpplint à lire en entrée")
922 args = parser.parse_args()
924 if not args.cpplint_output_file:
927 main_routine(args.cpplint_output_file)