Salome HOME
Issue #1865: Create a field
[modules/shaper.git] / correction_auto_2.py
1 # coding: utf-8
2 import os, os.path, sys, re, argparse
3 from utils import *
4
5
6
7
8
9
10
11 #### définition des hooks.
12 # chaque hook doit :
13 # * avoir le prototype suivant : def <nom_hook>(<unicode>) avec <unicode> la ligne de texte à corriger
14 # * retourner deux valeurs : la ligne corrigée, en unicode et un booléen indiquant s'il faut faire un check humain avant de corriger
15 # * être inséré dans HOOKS_DICT en y faisant correspondre un dico explicitant les critères de séléction de ce hook
16 ####
17
18 ### whitespace/semicolon ###
19
20 def extra_space_before_last_semicolon(ligne, previous_ligne = None, warning=None):
21         liste=ligne.split(u';\n')
22         ligne2=liste[0]
23         ligne3=ligne2.rstrip()
24         ligne=ligne3 + u';\n' 
25         return ligne, previous_ligne, False
26
27 def missing_space_after_semicolon(ligne, previous_ligne = None, warning=None):
28         ligne=ligne.replace(u';',u'; ')
29         return ligne, previous_ligne, False
30         
31 #########################
32
33 ### whitespace/operators ###
34
35 def missing_space_around_operator_egal(ligne, previous_ligne = None, warning=None):
36         i=ligne.find(u'=')
37         nextchar=ligne[i+1]
38         previouschar=ligne[i-1]
39         if nextchar not in OPERATORS and previouschar not in OPERATORS:
40                 if nextchar.isspace() == False and previouschar.isspace()==True:
41                         ligne=ligne.replace(u'=', u'= ')
42                 elif nextchar.isspace() == True and previouschar.isspace()==False:
43                         ligne=ligne.replace(u'=', u' =')
44                 elif nextchar.isspace() == False and previouschar.isspace()==False:
45                         ligne=ligne.replace(u'=', u' = ')
46                 else:
47                         pass
48         return ligne, previous_ligne, False     
49
50 def extra_space_for_operator_add(ligne, previous_ligne = None, warning=None):                   
51         while ligne.find(u'++ ') > -1:
52                 ligne = ligne.replace(u'++ ',u'++')
53         while ligne.find(u' ++') > -1 and ligne.find(u'; ++') == -1:
54                 ligne = ligne.replace(u' ++',u'++')
55         return ligne, previous_ligne, False
56         
57 def extra_space_for_operator_diff(ligne, previous_ligne = None, warning=None):                  
58         while ligne.find(u'! ') > -1:
59                 ligne = ligne.replace(u'! ',u'!')
60         return ligne, previous_ligne, False
61
62 def missing_space_around_operator_double_chevron(ligne, previous_ligne = None, warning=None):
63         i=ligne.find(u'<<')
64         nextchar=ligne[i+1]
65         previouschar=ligne[i-1]
66         if nextchar.isspace() == False and previouschar.isspace()==True:
67                 ligne=ligne.replace(u'<<', u'<< ')
68         elif nextchar.isspace() == True and previouschar.isspace()==False:
69                 ligne=ligne.replace(u'<<', u' <<')
70         elif nextchar.isspace() == False and previouschar.isspace()==False:
71                 ligne=ligne.replace(u'<<', u' << ')
72         else:
73                 pass
74         return ligne, previous_ligne, False
75         
76 def missing_space_around_operator_simple_chevron(ligne, previous_ligne = None, warning=None):
77         i=ligne.find(u'<')
78         nextchar=ligne[i+1]
79         previouschar=ligne[i-1]
80         if nextchar not in OPERATORS and previouschar not in OPERATORS: 
81                 if nextchar.isspace() == False and previouschar.isspace()==True:
82                         ligne=ligne.replace(u'<', u'< ')
83                 elif nextchar.isspace() == True and previouschar.isspace()==False:
84                         ligne=ligne.replace(u'<', u' <')
85                 elif nextchar.isspace() == False and previouschar.isspace()==False:
86                         ligne=ligne.replace(u'<', u' < ')
87                 else:
88                         pass
89         return ligne, previous_ligne, False
90         
91
92 def missing_space_around_operator_diff_egal(ligne, previous_ligne = None, warning=None):
93         i=ligne.find(u'!=')
94         nextchar=ligne[i+1]
95         previouschar=ligne[i-1]
96         if nextchar.isspace() == False and previouschar.isspace()==True:
97                 ligne=ligne.replace(u'!=', u'!= ')
98         elif nextchar.isspace() == True and previouschar.isspace()==False:
99                 ligne=ligne.replace(u'!=', u' !=')
100         elif nextchar.isspace() == False and previouschar.isspace()==False:
101                 ligne=ligne.replace(u'!=', u' != ')
102         else:
103                 pass
104         return ligne, previous_ligne, False
105         
106 def missing_space_around_operator_double_egal(ligne, previous_ligne = None, warning=None):
107         i=ligne.find(u'==')
108         nextchar=ligne[i+1]
109         previouschar=ligne[i-1]
110         if nextchar.isspace() == False and previouschar.isspace()==True:
111                 ligne=ligne.replace(u'==', u'== ')
112         elif nextchar.isspace() == True and previouschar.isspace()==False:
113                 ligne=ligne.replace(u'==', u' ==')
114         elif nextchar.isspace() == False and previouschar.isspace()==False:
115                 ligne=ligne.replace(u'==', u' == ')
116         else:
117                 pass
118         return ligne, previous_ligne, False
119
120         
121 #########################
122
123 ### whitespace/comments ###
124
125 def space_between_comments_and_code(ligne, previous_ligne = None, warning=None):
126         if ligne.find(u'//')>=0 :                       
127                 ligne=ligne.replace(u'//', u'  //')
128         elif ligne.find(u' //')>=0 :                    
129                 ligne=ligne.replace(u' //', u'  //')
130         else:
131             pass        
132         return ligne, previous_ligne, False
133
134 def space_between_comments_and_double_slash(ligne, previous_ligne = None, warning=None):                        
135         return ligne.replace(u'//', u'// '), previous_ligne, False
136         
137 #########################
138
139
140 ### legal/copyright ###
141
142 def legal_copyright(ficpath, ficline, warning=None):
143         replace_fic_copyright(ficpath)
144
145 #########################
146
147 ### build/header_guard
148
149 def ifndef_header(ficpath, ficline, warning):
150         replace_fic_ifndef(ficpath, ficline, warning, "wrong_style")
151                 
152 #def no_ifndef_header(ficpath, ficline, warning):
153 #       replace_fic_ifndef(ficpath, ficline, warning, "no_guard_found")
154                 
155 def endif_line(ligne, previous_ligne = None, warning=None):
156         liste1=warning.split(u'// ')
157         ligne1=liste1[1]
158         liste2=ligne1.split(u'"')
159         header_guard=liste2[0]
160         ligne= u'#endif  // ' + header_guard +u'\n'             
161         return ligne, previous_ligne, False
162
163 #########################
164
165 ### whitespace/end_of_ligne ###
166
167 def whitespace_end_of_line(ligne, previous_ligne = None, warning=None):
168         ligne = ligne.rstrip()+'\n'
169
170         return ligne, previous_ligne, False
171
172 #########################
173
174 ### whitespace/comma ###
175
176 def missing_space_after_comma(ligne, previous_ligne = None, warning=None):
177         ligne=ligne.replace(u',',u', ')
178         return ligne, previous_ligne, False
179
180 #########################
181
182 ### readability/namespace ###
183
184 def namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
185         ligne2=ligne.rstrip(u'\n')
186         liste = warning.split(u'"')
187         namespace=liste[1]
188         if ligne.find(u'\r')>=0:
189                 ligne=ligne2+u'  '+namespace+u'\r\n'
190         else:
191                 ligne=ligne2+u'  '+namespace+u'\n'
192         return ligne, previous_ligne, False
193
194 def anonymous_namespace_should_be_terminated(ligne, previous_ligne = None, warning=None):
195         ligne2=ligne.rstrip(u'\n')
196         ligne=ligne2+u'  // namespace\n'
197         return ligne, previous_ligne, False
198         
199 #########################
200
201 ### whitespace/parens ###
202
203 def extra_space_after_opening_paranthesis(ligne, previous_ligne = None, warning=None):
204         while ligne.find(u'( ') > -1:
205                 ligne = ligne.replace(u'( ',u'(')
206         return ligne, previous_ligne, False
207
208 def extra_space_before_closing_paranthesis(ligne, previous_ligne = None, warning=None):
209         while ligne.find(u' )') > -1:
210                 ligne = ligne.replace(u' )',u')')
211         return ligne, previous_ligne, False
212         
213 def extra_space_before_opening_paranthesis_in_function_call(ligne, previous_ligne = None, warning=None):
214         while ligne.find(u' (') > -1 and ligne.find(u', (')==-1:
215                 ligne = ligne.replace(u' (',u'(')
216         return ligne, previous_ligne, False
217
218 def missing_space_before_opening_parenthesis_in_for(ligne, previous_ligne = None, warning=None):
219         return ligne.replace(u'for(',u'for ('), previous_ligne, False
220
221 def missing_space_before_opening_parenthesis_in_if(ligne, previous_ligne = None, warning=None):
222         return ligne.replace(u'if(',u'if ('), previous_ligne, False
223
224 def missing_space_before_opening_parenthesis_in_switch(ligne, previous_ligne = None, warning=None):
225         return ligne.replace(u'switch(',u'switch ('), previous_ligne, False
226
227 def missing_space_before_opening_parenthesis_in_while(ligne, previous_ligne = None, warning=None):
228         return ligne.replace(u'while(',u'while ('), previous_ligne, False
229
230 def mismatching_spaces_inside_paranthesis(ligne, previous_ligne = None, warning=None):
231         while ligne.find(u'( ') > -1:
232                 ligne = ligne.replace(u'( ',u'(')
233         while ligne.find(u' )') > -1:
234                 ligne = ligne.replace(u' )',u')')
235         return ligne, previous_ligne, False
236         
237 #########################
238
239 ### whitespace/newline ###
240
241 def else_should_be_previous_line(ligne, previous_ligne=None, warning=None):
242         return position_of_else(ligne, previous_ligne, warning)
243
244 #########################
245
246 ### whitespace/indent ###
247
248 def missing_space_before_public_protected_private(ligne, previous_ligne = None, warning=None):
249         # Ajout d'un espace avant public:, protected: et :private
250         if re.match("public.*:|protected.*:|private.*:", ligne):
251                 ligne = " " + ligne
252
253         return ligne, previous_ligne, False
254
255 def wrong_number_of_spaces_while_indenting(ligne, previous_ligne = None, warning=None):
256         # Le nombre d'espaces pour l'indentation doit être pair
257         if re.match("\s{1}\S+|\s{3}\S+|\s{5}\S+|\s{7}\S+|\s{9}\S+", ligne):
258                 if not re.match(" public.*:| protected.*:| private.*:| \*", ligne):
259                         ligne = " " + ligne
260         # Suppression des espaces superflus sur une ligne sans code
261         if ligne.isspace():
262                 ligne = "\n"
263
264         # Remplacement des tabulations par 8 espaces en début de ligne
265         ligne = ligne.replace("\t", "        ")
266
267         return ligne, previous_ligne, False
268 #########################
269
270 ### whitespace/ending_newline ###
271
272 def no_newline_at_the_end_of_file(ligne, previous_ligne = None, warning=None):
273         ligne += '\n\n'
274         return ligne, None, False
275
276 #################################
277
278 ### build/storage_class ###
279
280 def order_of_storage_class_specifier(ligne, previous_ligne = None, warning=None):
281         if re.match("\s*const static", ligne):
282                 # Inversion de const static en static const
283                 ligne = ligne.replace("const static", "static const")
284
285         return ligne, previous_ligne, False
286
287 ###########################
288
289 ### whitespace/tab ###
290
291 def use_spaces_instead_of_tab(ligne, previous_ligne = None, warning=None):
292         if re.match(".*\t", ligne):
293                 # Remplacement des tabulations par 8 espaces
294                 ligne = ligne.replace("\t", "        ")
295
296         return ligne, previous_ligne, False
297
298 ######################
299         
300 ### readability/braces ###
301
302 def no_semicolon_after_brace(ligne, previous_ligne = None, warning=None):
303         return ligne.replace(u'};',u'}'), previous_ligne, False
304
305 def position_of_else(ligne, previous_ligne=None, warning=None):
306         '''Remonte une ligne du type } else {'''
307         
308         if '}' not in previous_ligne:
309                 # Si on ne trouve pas de '}' sur la ligne précédente, on ne fait rien
310                 return ligne, None, False
311
312         m = re.match("(.*)else(.*)", ligne)
313         
314         previous_ligne = previous_ligne.rstrip("\n") + ' else' + m.group(2) + '\n'
315         ligne = ''
316         return ligne, previous_ligne, False
317
318 ##########################
319
320 ### whitespace/braces ###
321
322 def position_of_opening_brace(ligne, previous_ligne=None, warning=None):
323         '''Remonte le { sur la ligne du dessus'''
324         
325         m = re.match("(\s*){(.*)", ligne)
326         
327         # On ne fait rien si on trouve un commentaire sur la ligne précédente (ce sera une correction manuelle)
328         if previous_ligne.find(u'//') == -1:
329                 previous_ligne = previous_ligne.rstrip("\n") + ' {' + m.group(2) + '\n'
330                 ligne = ''
331         else:
332                 print "The previous line contains a comment, fixing has to be manual."
333
334         return ligne, previous_ligne, False
335
336 def missing_space_before_opening_brace(ligne, previous_ligne = None, warning=None):
337         m = re.match("(.+)(\S){(.*)", ligne)
338         if(m):
339                 print 'group_0', m.group(0)
340                 print 'group_1', m.group(1)
341                 print 'group_2', m.group(2)
342                 print 'group_3', m.group(3)
343                 ligne = m.group(1) + m.group(2) + ' {' + m.group(3) + '\n'
344
345         return ligne, previous_ligne, False
346
347
348 #########################       
349
350
351 def missing_space_before_else(ligne, previous_ligne = None, warning=None):
352         m = re.match("(.+)(\S)else(.*)", ligne)
353         if(m):
354                 print 'group_0', m.group(0)
355                 print 'group_1', m.group(1)
356                 print 'group_2', m.group(2)
357                 print 'group_3', m.group(3)
358                 ligne = m.group(1) + m.group(2) + ' else' + m.group(3) + '\n'
359
360         return ligne, previous_ligne, False
361
362 ### runtime/references ###
363
364 def make_const_reference(ficpath, ligne, previous_ligne = None, warning=None):
365         """ Adding keyword 'const' """
366         print "ficpath = ", ficpath
367         print "ligne = ", ligne
368         print "warning = ", warning
369         m = re.match("(.+)Is this a non-const reference\? If so, make const or use a pointer: (.+)  (.+)", warning)
370         if(m):
371                 print 'group_0', m.group(0)
372                 print 'group_1', m.group(1)
373                 print 'group_2', m.group(2)
374                 print 'group_3', m.group(3)
375                 arg_to_modify = m.group(2)
376                 ligne = ligne.replace(arg_to_modify, "const "+arg_to_modify)
377                 
378                 # Répercution des corrections dans le fichier ".cpp" correspondant si c'est un fichier ".h"
379                 if ficpath.find('.h') > -1:
380                         cpp_file_path = ficpath.replace('.h', '.cpp')
381                         make_const_reference_cpp_file(cpp_file_path, arg_to_modify)
382                         global H_FILE_MAKE_CONST_REFERENCE_MODIFIED
383                         H_FILE_MAKE_CONST_REFERENCE_MODIFIED = True
384         else:
385                 print "ERROR : The following pattern was not found : 'Is this a non-const reference? If so, make const or use a pointer:'"
386
387         return ligne, previous_ligne, False
388
389 def make_const_reference_cpp_file(ficpath, arg_to_modify):
390         if not os.path.isfile(ficpath):
391                 print "WARNING : The file ", ficpath, " doesn't exist, manual fixing is required in methods of the file ", ficpath.replace('.cpp', '.h'), " in which arguments have been declared 'const'"
392                 return
393
394         fic = open(get_src_path(ficpath),'r')
395         liste = fic_readlines(fic)
396         new_liste = []
397
398         for ligne in liste:
399                 # Recherche de l'argument à modifier
400                 if(ligne.find(arg_to_modify) > -1 and ligne.find('const '+arg_to_modify) == -1):
401                         new_liste.append(ligne.replace(arg_to_modify, "const "+arg_to_modify))
402                 else:
403                         new_liste.append(ligne)
404                 
405         newliste=fic_writelines(new_liste)
406         fichier = open(get_src_path(ficpath), "w")
407         fichier.writelines(newliste)
408
409
410
411
412 ##########################
413
414 ### runtime/int ###
415
416 def replace_short_by_int16(ligne, previous_ligne = None, warning=None):
417         ligne = ligne.replace(u'short', u'int16_t')
418
419         return ligne, None, False
420
421 def replace_long_by_int64(ligne, previous_ligne = None, warning=None):
422         ligne = ligne.replace(u'long', u'int64_t')
423
424         return ligne, None, False
425
426 ###################
427
428 ### runtime/explicit ###
429
430 def make_constructor_explicit(ligne, previous_ligne = None, warning=None):
431         m = re.match("(\s*)(.+)", ligne)
432         if(m):
433                 print 'group_0', m.group(0)
434                 print 'group_1', m.group(1)
435                 print 'group_2', m.group(2)
436                 ligne = ligne.replace(m.group(2), u'explicit '+m.group(2))
437
438         return ligne, None, False
439
440 ########################
441
442 ### build/include ###
443
444 def cpp_file_should_include_h_file(ficpath, ficline, warning):
445         fic = open(get_src_path(ficpath),'r')
446         liste = fic_readlines(fic)
447         new_liste = []
448
449         m = re.match("(.+) should include its header file (.+)  (.+)", warning)
450         if(m):
451                 print 'group_0', m.group(0)
452                 print 'group_1', m.group(1)
453                 print 'group_2', m.group(2)
454                 # Nouveau chemin du fichier .h
455                 new_h_file_path = m.group(2)
456
457                 # Nom du fichier .h
458                 h_file_name = os.path.basename(new_h_file_path)
459
460                 # Recherche de la ligne à modifier
461                 for ligne in liste:
462                         m2 = re.match("#include.*"+h_file_name+".*", ligne)
463                         if(m2):
464                                 print "FOUND : ", ligne
465                                 new_liste.append("#include \""+new_h_file_path+"\"\n")
466                         else:
467                                 print "NOT FOUND : ", ligne
468                                 new_liste.append(ligne)
469         else:
470                 print "ERROR : Pattern not found : \"should include its header file\""
471
472         newliste=fic_writelines(new_liste)
473         fichier = open(get_src_path(ficpath), "w")
474         fichier.writelines(newliste)
475         
476 def _h_file_already_included(ligne, previous_ligne = None, warning=None):
477         return "", None, False
478                 
479
480 #####################
481
482 ### whitespace/blank_line ###
483
484 def do_not_leave_blank_line_after_public_protected_private(ficpath, ficline, warning):
485         fic = open(get_src_path(ficpath),'r')
486         liste = fic_readlines(fic)
487         new_liste = []
488
489         flag = False
490         for ligne in liste:
491                 if re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
492                         # Détection d'une ligne public:, protected: ou :private
493                         flag = True
494                 if flag and ligne.isspace():
495                         # Supprimer les lignes vides après public:, protected: et :private
496                         print "Deleting empty line"
497                         new_liste.append("")
498                         continue
499                 if not ligne.isspace() and not re.match(".*public.*:|.*protected.*:|.*private.*:", ligne):
500                         flag = False
501                 new_liste.append(ligne)
502
503         newliste=fic_writelines(new_liste)
504         fichier = open(get_src_path(ficpath), "w")
505         fichier.writelines(newliste)
506
507 def do_not_leave_blank_line_at_the_start_of_code_block(ficpath, ficline, warning):
508         fic = open(get_src_path(ficpath),'r')
509         liste = fic_readlines(fic)
510         new_liste = []
511
512         flag = False
513         for ligne in liste:
514                 if re.match(".*{", ligne):
515                         # Détection d'un début de bloc
516                         flag = True
517                 if flag and ligne.isspace():
518                         # Supprimer les lignes vides après un début de bloc
519                         print "Deleting empty line"
520                         new_liste.append("")
521                         continue
522                 if not ligne.isspace() and not re.match(".*{", ligne):
523                         flag = False
524                 new_liste.append(ligne)
525
526         newliste=fic_writelines(new_liste)
527         fichier = open(get_src_path(ficpath), "w")
528         fichier.writelines(newliste)
529
530 def do_not_leave_blank_line_at_the_end_of_code_block(ficpath, ficline, warning):
531         fic = open(get_src_path(ficpath),'r')
532         liste = fic_readlines(fic)
533         new_liste = []
534
535         nb_blank_lines = 0
536         for ligne in liste:
537                 if re.match(".*}", ligne):
538                         # Détection d'une fin de bloc -> suppression des nb_blank_lines lignes vides précédentes
539                         for i in range(0, nb_blank_lines):
540                                 new_liste.pop()
541                 if ligne.isspace():
542                         nb_blank_lines += 1
543                 else:
544                         nb_blank_lines = 0
545                 new_liste.append(ligne)
546
547         newliste=fic_writelines(new_liste)
548         fichier = open(get_src_path(ficpath), "w")
549         fichier.writelines(newliste)
550
551 def add_blank_line_before_public(ligne, previous_ligne = None, warning=None):
552         ligne = "\n" + ligne
553
554         return ligne, None, False
555
556 def add_blank_line_before_protected(ligne, previous_ligne = None, warning=None):
557         ligne = "\n" + ligne
558
559         return ligne, None, False
560
561 def add_blank_line_before_private(ligne, previous_ligne = None, warning=None):
562         ligne = "\n" + ligne
563
564         return ligne, None, False
565
566 ##############################
567
568 ### build/include_what_you_use ###
569
570 def add_include_what_you_use(ficpath, ficline, warning):
571         """
572         Ajoute le #include suggéré dans le warning
573         """
574
575         fic = open(get_src_path(ficpath), "r")
576         liste = fic_readlines(fic)
577         
578         m = re.match("\s*Add (.+) for (.+)", warning)
579         if(m):
580                 print 'group_0', m.group(0)
581                 print 'group_1', m.group(1)
582                 include = m.group(1)
583
584                 # Recherche la ligne dans laquelle ajouter le #include
585                 # On l'ajoutera après le dernier "#include <..."
586                 num_ligne = 0
587                 num_ligne_include_system = 0
588                 num_ligne_include_local = 0
589                 for ligne in liste:
590                         num_ligne += 1
591                         if ligne.find('#include <') > -1:
592                                 num_ligne_include_system = num_ligne
593                         elif ligne.find('#include "') > -1:
594                                 num_ligne_include_local = num_ligne
595                 
596                 num_ligne_include = max(num_ligne_include_system, num_ligne_include_local)
597                 if num_ligne_include == 0:
598                         print "WARNING : #include not found in file ", ficpath
599                         return
600
601                 new_liste = []
602                 num_ligne = 0
603                 fic2 = open(get_src_path(ficpath), "r")
604                 liste2 = fic_readlines(fic2)
605                 for ligne in liste2:
606                         num_ligne += 1
607                         new_liste.append(ligne)
608                         if num_ligne == num_ligne_include:
609                                 new_liste.append(include+'\n')
610                 
611                 newliste=fic_writelines(new_liste)
612                 fichier = open(get_src_path(ficpath), "w")
613                 fichier.writelines(newliste)
614         else:
615                 print "ERROR : Pattern of include_what_you_use not found"
616                 return
617
618 ##################################
619
620
621 HOOKS_DICT = {
622         extra_space_before_last_semicolon:{'pattern':u'whitespace/semicolon', 'pattern_AND':u'Extra space before last semicolon'},
623         missing_space_after_semicolon:{'pattern':u'whitespace/semicolon', 'pattern_AND':u'Missing space after'},
624         missing_space_around_operator_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around = '},
625         extra_space_for_operator_add:{'pattern':u'whitespace/operators', 'pattern_AND':u'Extra space for operator  ++'},
626         extra_space_for_operator_diff:{'pattern':u'whitespace/operators', 'pattern_AND':u'Extra space for operator !'},
627         missing_space_around_operator_double_chevron:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around << '},
628         missing_space_around_operator_simple_chevron:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around < '},
629         missing_space_around_operator_diff_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around !='},
630         missing_space_around_operator_double_egal:{'pattern':u'whitespace/operators', 'pattern_AND':u'Missing spaces around =='},
631         space_between_comments_and_code:{'pattern':u'whitespace/comments', 'pattern_AND':u'At least two spaces is best between code and comments'},
632         space_between_comments_and_double_slash:{'pattern':u'whitespace/comments', 'pattern_AND':u'Should have a space between // and comment '},
633         legal_copyright:{'pattern':u'legal/copyright'}, # Script à n'executer qu'une fois
634         ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'#ifndef header guard has wrong style, please use'}, 
635 #        no_ifndef_header:{'pattern':u'build/header_guard', 'pattern_AND':u'No #ifndef header guard found'}, 
636         endif_line:{'pattern':u'build/header_guard', 'pattern_AND':u'#endif line should be'},
637         whitespace_end_of_line:{'pattern':u'whitespace/end_of_line', 'pattern_AND':u'Line ends in whitespace'},
638         missing_space_after_comma:{'pattern':u'whitespace/comma'},
639         namespace_should_be_terminated:{'pattern':u'readability/namespace', 'pattern_AND':u'Namespace should be terminated with'},
640         anonymous_namespace_should_be_terminated:{'pattern':u'readability/namespace', 'pattern_AND':u'Anonymous namespace should be terminated with'},
641                 extra_space_after_opening_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Extra space after ('},
642                 extra_space_before_closing_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Extra space before )'},
643                 extra_space_before_opening_paranthesis_in_function_call:{'pattern':u'whitespace/parens', 'pattern':u'Extra space before ( in function call'},
644                 missing_space_before_opening_parenthesis_in_for:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in for('},
645                 missing_space_before_opening_parenthesis_in_if:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in if('},
646                 missing_space_before_opening_parenthesis_in_switch:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in switch('},
647                 missing_space_before_opening_parenthesis_in_while:{'pattern':u'whitespace/parens', 'pattern_AND':u'Missing space before ( in while('},
648                 mismatching_spaces_inside_paranthesis:{'pattern':u'whitespace/parens', 'pattern_AND':u'Mismatching spaces inside ()'},
649                 missing_space_before_public_protected_private:{'pattern':u'whitespace/indent', 'pattern_AND':u' should be indented +1 space inside class'},
650                 
651                 wrong_number_of_spaces_while_indenting:{'pattern':u'whitespace/indent', 'pattern_AND':u'Weird number of spaces at line-start'},
652
653                 no_newline_at_the_end_of_file:{'pattern':u'whitespace/ending_newline'},
654
655                 order_of_storage_class_specifier:{'pattern':u'build/storage_class'},
656
657                 use_spaces_instead_of_tab:{'pattern':u'whitespace/tab'},
658
659                 no_semicolon_after_brace:{'pattern':u'readability/braces', 'pattern_AND':u'You don\'t need a ; after a }'},
660 #               position_of_else:{'pattern':u'readability/braces', 'pattern_AND':u'If an else has a brace on one side'},
661 #               else_should_be_previous_line:{'pattern':u'whitespace/newline', 'pattern_AND':u'An else should appear on the same line as the preceding'},
662                 position_of_opening_brace:{'pattern':u'whitespace/braces', 'pattern_AND':u'{ should almost always be at the end of the previous line'},
663                 missing_space_before_opening_brace:{'pattern':u'whitespace/braces', 'pattern_AND':u'Missing space before {'},
664                 missing_space_before_else:{'pattern':u'whitespace/braces', 'pattern_AND':u'Missing space before else'},
665                 
666                 make_const_reference:{'pattern':u'runtime/references', 'pattern_AND':u'Is this a non-const reference? If so, make const or use a pointer'},
667
668                 make_constructor_explicit:{'pattern':u'runtime/explicit'},
669
670                 cpp_file_should_include_h_file:{'pattern':u'build/include', 'pattern_AND':u'should include its header file'},
671                 _h_file_already_included:{'pattern':u'build/include', 'pattern_AND':u'already included at'},
672
673                 replace_short_by_int16:{'pattern':u'runtime/int', 'pattern_AND':u'Use int16/int64/etc, rather than the C type short'},
674                 replace_long_by_int64:{'pattern':u'runtime/int', 'pattern_AND':u'Use int16/int64/etc, rather than the C type long'},
675
676                 do_not_leave_blank_line_after_public_protected_private:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Do not leave a blank line after'},
677                 do_not_leave_blank_line_at_the_start_of_code_block:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Redundant blank line at the start of a code block should be deleted'},
678                 do_not_leave_blank_line_at_the_end_of_code_block:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'Redundant blank line at the end of a code block should be deleted'},
679                 add_blank_line_before_public:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"public:" should be preceded by a blank line'},
680                 add_blank_line_before_protected:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"protected:" should be preceded by a blank line'},
681                 add_blank_line_before_private:{'pattern':u'whitespace/blank_line', 'pattern_AND':u'"private:" should be preceded by a blank line'},
682
683                 add_include_what_you_use:{'pattern':u'build/include_what_you_use'},
684
685 }
686
687 HOOKS_DELETING_OR_ADDING_LINES = [no_newline_at_the_end_of_file, position_of_opening_brace, _h_file_already_included, 
688 add_blank_line_before_public, add_blank_line_before_protected, add_blank_line_before_private, do_not_leave_blank_line_after_public_protected_private, do_not_leave_blank_line_at_the_start_of_code_block, do_not_leave_blank_line_at_the_end_of_code_block, legal_copyright, add_include_what_you_use]
689 HOOKS_PARSING_THE_WHOLE_FILE = [cpp_file_should_include_h_file, do_not_leave_blank_line_after_public_protected_private,
690  do_not_leave_blank_line_at_the_start_of_code_block, do_not_leave_blank_line_at_the_end_of_code_block, legal_copyright, ifndef_header, add_include_what_you_use] #Hook à éxecuter avant les autres hooks 
691
692 def replace_line_no(path, nol, oldline, newline):
693         """
694         Remplace, la ligne No nol du fichier path (relatif à SRCROOTDIR) par la chaîne newline (un unicode)
695         oldline sert uniquement pour vérifier que tout est ok
696         """
697         print "replace_line_no : ", oldline, " by ", newline
698         # récupérer le contenu du fichier
699         fic = open(get_src_path(path), "r")
700         liste = fic.readlines()
701         fic.close()
702         # test de corruption
703         if liste[nol-1].decode(ENCODING) != oldline :
704                 raise Exception(u"Le fichier source %s semble être corrompu" %path)
705         # remplacement de la ligne
706         liste[nol-1] = newline.encode(ENCODING)
707         # recréation du fichier corrigé
708         fic = open(get_src_path(path), "w")     
709         fic.writelines(liste)
710         fic.close()     
711
712 def replace_fic_copyright(ficpath, warning=None):
713         """
714         Remplace le fichier sans la ligne copyright par le fichier avec la ligne copyright
715         """
716         
717         fic = open(get_src_path(ficpath), "r")
718         liste=fic_readlines(fic)
719         fic.close()
720         new_liste = []
721         if liste[0].find(u'/ Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n')== -1:                       
722                 newliste=[u'// Copyright (C) 2014-20xx CEA/DEN, EDF R&D\n\n']+liste     
723                 newliste=fic_writelines(newliste)
724                 fic = open(get_src_path(ficpath), "w")
725                 fic.writelines(newliste)
726                 fic.close()
727
728
729 def replace_fic_ifndef(ficpath, ficline, warning, mode):
730         """
731         Remplace dans le fichier, toutes les erreurs sur le style des #define et #ifndef à partir du warning
732         """
733         fic = open(get_src_path(ficpath),'r')
734         liste = fic_readlines(fic)
735         new_liste = []
736
737         if mode == "no_guard_found":
738                 m = re.match("(.*)No #ifndef header guard found, suggested CPP variable is: (.+)  (.+)", warning)
739         else:
740                 m = re.match("(.*)ifndef header guard has wrong style, please use: (.+)  (.+)", warning)
741
742         if(m):
743                 print 'group_0', m.group(0)
744                 print 'group_1', m.group(1)
745                 print 'group_2', m.group(2)
746
747                 # Header à changer
748                 header_guard=m.group(2)
749
750                 # Recherche de la ligne à modifier
751                 i = 0
752                 trouve = False
753                 for ligne in liste:
754                         i += 1
755                         if i == ficline:
756                                 if ligne.find(u'#ifndef') >= 0:
757                                         new_liste.append("#ifndef "+header_guard+"\n")
758                                         trouve = True
759                                 else:
760                                         print "ERROR : Pattern #ifndef not found in line ", ficline
761                                         return
762                         else:
763                                 if trouve == True:
764                                         if ligne.find(u'#define') >= 0:
765                                                 new_liste.append("#define "+header_guard+"\n")
766                                                 trouve = False
767                                         else:
768                                                 print "WARNING : Pattern #define not found in the line following the pattern #ifndef, we abandon."
769                                                 return
770                                 else:
771                                         new_liste.append(ligne)
772         else:
773                 print "ERROR : Pattern not found : \"#ifndef header guard has wrong style, please use\""
774
775         newliste=fic_writelines(new_liste)
776         fichier = open(get_src_path(ficpath), "w")
777         fichier.writelines(newliste)
778                         
779
780 def get_hook(warning, fichier):
781         """
782         Fait le matching entre un warning et le hook permettant de le traiter.
783         Les critères pour sélectionner un ou l'autre des hook sont consignés dans un dict associé (dans HOOKS_DICT) à chaque hook disponible.
784         Le format de chaque dict de critère est le suivant :
785         {
786                 "pattern": <motif principal devant se trouver dans le texte du warning>,
787                 "pattern_AND": <motif secondaire devant se trouver également dans le texte du warning>,
788                 "pattern_NOT": <motif secondaire ne devant pas se trouver dans le texte du warning>,
789                 "ext": <extension du fichier considéré>       
790         }
791         Seul le premier hook trouvé est renvoyé.
792         Les arguments sont les suivants :
793         * warning : le texte unicode du warning
794         * fichier : le chemin vers le fichier concerné
795         """
796         def test_it(condition, data, warning, fichier):
797                 if condition in ["pattern", "pattern_AND"] :
798                         if data in warning:
799                                 return True
800                 elif condition in ["PATTERN_NOT"]:
801                         if data not in warning:
802                                 return True
803                 elif condition in ["ext"]:
804                         if data not in os.path.splitext(fichier)[1]:
805                                 return True
806                 return False
807         
808         for key, val in HOOKS_DICT.items(): # boucle sur les hooks existants
809                 test = None
810                 for condition, data in val.items():
811                         if test is False:
812                                 # si une condition n'est pas réalisée => c'est pas le bon hook
813                                 continue
814                         test = test_it(condition, data, warning, fichier)
815                 if test is True:
816                         return key
817         return
818         
819 def main_routine(cpplint_output_file):
820         logfile = open(cpplint_output_file,"r")
821         generateur_w = create_warning_generator(logfile)
822         last_ficpath_with_modified_nb_lines = ""
823         for ficpath, ficline, warning in generateur_w:
824                 oldline = get_line_no(ficpath, ficline)
825                 if ficline > 0:
826                         previous_oldline = get_line_no(ficpath, ficline-1)
827                 else:
828                         previous_oldline = None
829                 print "===\nNew warning:"
830                 print "\tFile = "+ficpath
831                 print "\tlast_ficpath_with_modified_nb_lines = "+last_ficpath_with_modified_nb_lines
832                 print "\tNo ligne =" , ficline
833                 if VERBOSE_FLAG == "True":
834                         print "\tWarning ='"+warning+"'"
835                         print "\tOld text of current line = '"+oldline+"'"
836                         if previous_oldline:
837                                 print "\tOld text of previous line = '"+previous_oldline+"'"
838                         if ficpath == last_ficpath_with_modified_nb_lines:
839                                 print "File ", ficpath, "already modified. Waiting next cpplint run to process it."
840                                 continue
841                 hook = get_hook(warning, ficpath)
842                 print "hook = ", hook
843                 if hook is None:
844                         print u"No hook found"
845                         continue
846
847                 if VERBOSE_FLAG == "True":
848                         print "\t=> Processing with hook", hook
849
850                 if hook in HOOKS_DELETING_OR_ADDING_LINES:
851                         last_ficpath_with_modified_nb_lines = ficpath
852                         
853                 if hook in HOOKS_PARSING_THE_WHOLE_FILE:
854                         hook(ficpath, ficline, warning)
855                         print "Done"
856                         continue
857                                 
858                 # Cas particulier pour le hook make_const_reference : il faut faire un traitement sur le fichier .cpp associé au fichier .h concerné par le hook
859                 if hook in [make_const_reference]:
860                         if ficpath.find('.h') > -1:
861                                 newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
862                         else:
863                                 if H_FILE_MAKE_CONST_REFERENCE_MODIFIED:
864                                         continue
865                                 else:
866                                         newline, previous_newline, huchk = hook(ficpath, oldline, previous_oldline, warning)
867                 else:
868                         newline, previous_newline, huchk = hook(oldline, previous_oldline, warning)
869
870                 if VERBOSE_FLAG == "True":
871                         print "\tNew text = '"+newline+"'"
872                 if huchk:
873                         if previous_newline:
874                                 print "Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(previous_oldline, previous_newline)
875                                 reponse = raw_input()
876                                 if reponse in ['O', 'o']:
877                                         replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline) 
878                                         print "Replacement done."               
879                                 else :
880                                         print "Replacement aborted."
881
882                                 print "Replace line : \n'%s'\n with line \n'%s'\n O/N ? :"%(oldline, newline)
883                                 reponse = raw_input()
884                                 if reponse in ['O', 'o']:
885                                         replace_line_no(ficpath, ficline, oldline, newline)     
886                                 print "Replacement done."               
887                         else :
888                                 print "Replacement aborted."
889
890
891                 else :
892                         if previous_newline:
893                                 replace_line_no(ficpath, ficline-1, previous_oldline, previous_newline)
894                         replace_line_no(ficpath, ficline, oldline, newline)
895                 print "Done"
896         logfile.close()
897                 
898 if __name__ == '__main__':
899         H_FILE_MAKE_CONST_REFERENCE_MODIFIED = False
900
901         parser = argparse.ArgumentParser()
902         parser.add_argument("--cpplint_output_file", type=str, help="Fichier de rapport cpplint à lire en entrée")
903         args = parser.parse_args()
904
905         if not args.cpplint_output_file:
906                 parser.print_help()
907         else:
908                 main_routine(args.cpplint_output_file)