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