1 /**
2  * @file braces.cpp
3  * Adds or removes braces.
4  *
5  * @author  Ben Gardner
6  * @license GPL v2+
7  */
8 
9 #include "braces.h"
10 
11 #include "calculate_closing_brace_position.h"
12 #include "combine_tools.h"
13 #include "newlines.h"
14 #include "prototypes.h"
15 
16 constexpr static auto LCURRENT = LBR;
17 
18 using namespace uncrustify;
19 
20 using std::vector;
21 
22 
23 //! Converts a single brace into a virtual brace
24 static void convert_brace(chunk_t *br);
25 
26 
27 //! Converts a single virtual brace into a real brace
28 static void convert_vbrace(chunk_t *br);
29 
30 
31 static void convert_vbrace_to_brace(void);
32 
33 
34 //! Go backwards to honor brace newline removal limits
35 static void examine_braces(void);
36 
37 
38 /**
39  * Step forward and count the number of semi colons at the current level.
40  * Abort if more than 1 or if we enter a preprocessor
41  */
42 static void examine_brace(chunk_t *bopen);
43 
44 
45 static void move_case_break(void);
46 
47 
48 static void mod_case_brace(void);
49 
50 
51 static void mod_full_brace_if_chain(void);
52 
53 
54 /**
55  * Checks to see if the braces can be removed.
56  *  - less than a certain length
57  *  - doesn't mess up if/else stuff
58  */
59 static bool can_remove_braces(chunk_t *bopen);
60 
61 
62 /**
63  * Checks to see if the virtual braces should be converted to real braces.
64  *  - over a certain length
65  *
66  * @param vbopen  Virtual Brace Open chunk
67  *
68  * @return true (convert to real braces) or false (leave alone)
69  */
70 static bool should_add_braces(chunk_t *vbopen);
71 
72 
73 /**
74  * Collect the text into txt that contains the full tag name.
75  * Mainly for collecting namespace 'a.b.c' or function 'foo::bar()' names.
76  */
77 static void append_tag_name(unc_text &txt, chunk_t *pc);
78 
79 
80 //! Remove the case brace, if allowable.
81 static chunk_t *mod_case_brace_remove(chunk_t *br_open);
82 
83 
84 //! Add the case brace, if allowable.
85 static chunk_t *mod_case_brace_add(chunk_t *cl_colon);
86 
87 
88 /**
89  * Traverse the if chain and see if all can be removed
90  *
91  * @param br_start  chunk pointing to opening brace of if clause
92  */
93 static void process_if_chain(chunk_t *br_start);
94 
95 
96 /**
97  * Check if parenthesis pair that comes before a brace spans multiple lines
98  *
99  *
100  * @param brace  the brace chunk whose predecessing parenthesis will be checked
101  *
102  * @pre   the brace chunk cannot be a nullptr,
103  *        it needs to be of type CT_BRACE_OPEN or CT_BRACE_CLOSE,
104  *        its parent type needs to be one of this types:
105  *            CT_IF, CT_ELSEIF, CT_FOR, CT_USING_STMT, CT_WHILE,
106  *            CT_FUNC_CLASS_DEF, CT_FUNC_DEF
107  *
108  * @return  false: if preconditions are not met,
109  *                 if an error occurs while  counting the newline between the
110  *                 parenthesis or
111  *                 when no newlines are found between the parenthesis
112  */
paren_multiline_before_brace(chunk_t * brace)113 static bool paren_multiline_before_brace(chunk_t *brace)
114 {
115    if (  brace == nullptr
116       || (  chunk_is_not_token(brace, CT_BRACE_OPEN)
117          && chunk_is_not_token(brace, CT_BRACE_CLOSE))
118       || (  get_chunk_parent_type(brace) != CT_IF
119          && get_chunk_parent_type(brace) != CT_ELSEIF
120          && get_chunk_parent_type(brace) != CT_FOR
121          && get_chunk_parent_type(brace) != CT_USING_STMT
122          && get_chunk_parent_type(brace) != CT_WHILE
123          && get_chunk_parent_type(brace) != CT_FUNC_CLASS_DEF
124          && get_chunk_parent_type(brace) != CT_FUNC_DEF))
125    {
126       return(false);
127    }
128    const auto paren_t = CT_SPAREN_CLOSE;
129 
130    // find parenthesis pair of the if/for/while/...
131    auto paren_close = chunk_get_prev_type(brace, paren_t, brace->level, scope_e::ALL);
132    auto paren_open  = chunk_skip_to_match_rev(paren_close, scope_e::ALL);
133 
134    if (  paren_close == nullptr
135       || paren_open == nullptr
136       || paren_close == brace
137       || paren_open == paren_close)
138    {
139       return(false);
140    }
141    // determine number of lines in the parenthesis pair spans
142    auto       nl_count = size_t{};
143    const auto ret_flag = newlines_between(paren_open, paren_close, nl_count);
144 
145    if (!ret_flag)
146    {
147       LOG_FMT(LERR, "%s(%d): newlines_between error\n", __func__, __LINE__);
148       return(false);
149    }
150    // nl_count = 0 -> 1 line
151    return(nl_count > 0);
152 }
153 
154 
do_braces(void)155 void do_braces(void)
156 {
157    LOG_FUNC_ENTRY();
158    // Mark one-liners
159    // Issue #2232 put this at the beginning
160    chunk_t *pc = chunk_get_head();
161 
162    while ((pc = chunk_get_next_ncnnl(pc)) != nullptr)
163    {
164       if (  chunk_is_not_token(pc, CT_BRACE_OPEN)
165          && chunk_is_not_token(pc, CT_VBRACE_OPEN))
166       {
167          continue;
168       }
169       chunk_t         *br_open = pc;
170       const c_token_t brc_type = c_token_t(pc->type + 1); // corresponds to closing type
171       // Detect empty bodies
172       chunk_t         *tmp = chunk_get_next_ncnnl(pc);
173 
174       if (chunk_is_token(tmp, brc_type))
175       {
176          chunk_flags_set(br_open, PCF_EMPTY_BODY);
177          chunk_flags_set(tmp, PCF_EMPTY_BODY);
178       }
179       // Scan for the brace close or a newline
180       tmp = br_open;
181 
182       while ((tmp = chunk_get_next_nc(tmp)) != nullptr)
183       {
184          if (chunk_is_newline(tmp))
185          {
186             break;
187          }
188 
189          if (  chunk_is_token(tmp, brc_type)
190             && br_open->level == tmp->level)
191          {
192             flag_series(br_open, tmp, PCF_ONE_LINER);
193             break;
194          }
195       }
196    }
197    log_rule_B("mod_full_brace_if_chain");
198    log_rule_B("mod_full_brace_if_chain_only");
199 
200    if (  options::mod_full_brace_if_chain()
201       || options::mod_full_brace_if_chain_only())
202    {
203       mod_full_brace_if_chain();
204    }
205    log_rule_B("mod_full_brace_if");
206    log_rule_B("mod_full_brace_do");
207    log_rule_B("mod_full_brace_for");
208    log_rule_B("mod_full_brace_using");
209    log_rule_B("mod_full_brace_while");
210 
211    if ((options::mod_full_brace_if() |
212         options::mod_full_brace_do() |
213         options::mod_full_brace_for() |
214         options::mod_full_brace_using() |
215         options::mod_full_brace_while()) & IARF_REMOVE)
216    {
217       examine_braces();
218    }
219    // convert vbraces if needed
220    log_rule_B("mod_full_brace_if");
221    log_rule_B("mod_full_brace_do");
222    log_rule_B("mod_full_brace_for");
223    log_rule_B("mod_full_brace_function");
224    log_rule_B("mod_full_brace_using");
225    log_rule_B("mod_full_brace_while");
226 
227    if ((options::mod_full_brace_if() |
228         options::mod_full_brace_do() |
229         options::mod_full_brace_for() |
230         options::mod_full_brace_function() |
231         options::mod_full_brace_using() |
232         options::mod_full_brace_while()) & IARF_ADD)
233    {
234       convert_vbrace_to_brace();
235    }
236    log_rule_B("mod_case_brace");
237 
238    if (options::mod_case_brace() != IARF_IGNORE)
239    {
240       mod_case_brace();
241    }
242    log_rule_B("mod_move_case_break");
243 
244    if (options::mod_move_case_break())
245    {
246       move_case_break();
247    }
248 } // do_braces
249 
250 
examine_braces(void)251 static void examine_braces(void)
252 {
253    LOG_FUNC_ENTRY();
254 
255    log_rule_B("mod_full_brace_nl_block_rem_mlcond");
256    const auto multiline_block = options::mod_full_brace_nl_block_rem_mlcond();
257 
258    log_rule_B("mod_full_brace_if");
259    log_rule_B("mod_full_brace_do");
260    log_rule_B("mod_full_brace_for");
261    log_rule_B("mod_full_brace_using");
262    log_rule_B("mod_full_brace_while");
263 
264    for (auto pc = chunk_get_tail(); pc != nullptr;)
265    {
266       auto prev = chunk_get_prev_type(pc, CT_BRACE_OPEN, -1);
267 
268       if (  chunk_is_token(pc, CT_BRACE_OPEN)
269          && !pc->flags.test(PCF_IN_PREPROC)
270          && (  (  (  get_chunk_parent_type(pc) == CT_IF
271                   || get_chunk_parent_type(pc) == CT_ELSE
272                   || get_chunk_parent_type(pc) == CT_ELSEIF)
273                && options::mod_full_brace_if() == IARF_REMOVE)
274             || (  get_chunk_parent_type(pc) == CT_DO
275                && options::mod_full_brace_do() == IARF_REMOVE)
276             || (  get_chunk_parent_type(pc) == CT_FOR
277                && options::mod_full_brace_for() == IARF_REMOVE)
278             || (  get_chunk_parent_type(pc) == CT_USING_STMT
279                && options::mod_full_brace_using() == IARF_REMOVE)
280             || (  get_chunk_parent_type(pc) == CT_WHILE
281                && options::mod_full_brace_while() == IARF_REMOVE)))
282       {
283          if (  multiline_block
284             && paren_multiline_before_brace(pc))
285          {
286             pc = prev;
287             continue;
288          }
289          examine_brace(pc);
290       }
291       pc = prev;
292    }
293 } // examine_braces
294 
295 
should_add_braces(chunk_t * vbopen)296 static bool should_add_braces(chunk_t *vbopen)
297 {
298    LOG_FUNC_ENTRY();
299    log_rule_B("mod_full_brace_nl");
300    const size_t nl_max = options::mod_full_brace_nl();
301 
302    if (nl_max == 0)
303    {
304       return(false);
305    }
306    LOG_FMT(LBRDEL, "%s(%d): start on %zu:\n",
307            __func__, __LINE__, vbopen->orig_line);
308 
309    size_t  nl_count = 0;
310 
311    chunk_t *pc = nullptr;
312 
313    for (pc = chunk_get_next_nc(vbopen, scope_e::PREPROC);
314         (pc != nullptr && pc->level > vbopen->level);
315         pc = chunk_get_next_nc(pc, scope_e::PREPROC))
316    {
317       if (chunk_is_newline(pc))
318       {
319          nl_count += pc->nl_count;
320       }
321    }
322 
323    if (  pc != nullptr
324       && nl_count > nl_max
325       && vbopen->pp_level == pc->pp_level)
326    {
327       LOG_FMT(LBRDEL, "%s(%d): exceeded %zu newlines\n",
328               __func__, __LINE__, nl_max);
329       return(true);
330    }
331    return(false);
332 }
333 
334 
can_remove_braces(chunk_t * bopen)335 static bool can_remove_braces(chunk_t *bopen)
336 {
337    LOG_FUNC_ENTRY();
338    LOG_FMT(LBRDEL, "%s(%d): start on line %zu:\n",
339            __func__, __LINE__, bopen->orig_line);
340 
341    // Cannot remove braces inside a preprocessor
342    if (bopen->flags.test(PCF_IN_PREPROC))
343    {
344       return(false);
345    }
346    chunk_t *pc = chunk_get_next_ncnnl(bopen, scope_e::PREPROC);
347 
348    if (chunk_is_token(pc, CT_BRACE_CLOSE))
349    {
350       // Can't remove empty statement
351       return(false);
352    }
353    const size_t level = bopen->level + 1;
354 
355    log_rule_B("mod_full_brace_nl");
356    const size_t nl_max = options::mod_full_brace_nl();
357    chunk_t      *prev  = nullptr;
358 
359    size_t       semi_count = 0;
360    bool         hit_semi   = false;
361    size_t       nl_count   = 0;
362    size_t       if_count   = 0;
363    int          br_count   = 0;
364 
365    pc = chunk_get_next_nc(bopen, scope_e::ALL);
366    LOG_FMT(LBRDEL, "%s(%d):  - begin with token '%s', orig_line is %zu, orig_col is %zu\n",
367            __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
368 
369    while (  pc != nullptr
370          && pc->level >= level)
371    {
372       LOG_FMT(LBRDEL, "%s(%d): test token '%s', orig_line is %zu, orig_col is %zu\n",
373               __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
374 
375       if (pc->flags.test(PCF_IN_PREPROC))
376       {
377          // Cannot remove braces that contain a preprocessor
378          return(false);
379       }
380 
381       if (chunk_is_newline(pc))
382       {
383          nl_count += pc->nl_count;
384 
385          if (  nl_max > 0
386             && nl_count > nl_max)
387          {
388             LOG_FMT(LBRDEL, "%s(%d):  exceeded %zu newlines\n",
389                     __func__, __LINE__, nl_max);
390             return(false);
391          }
392       }
393       else
394       {
395          if (chunk_is_token(pc, CT_BRACE_OPEN))
396          {
397             br_count++;
398          }
399          else if (chunk_is_token(pc, CT_BRACE_CLOSE))
400          {
401             if (br_count == 0)
402             {
403                fprintf(stderr, "%s(%d): br_count is ZERO, cannot be decremented, at line %zu, column %zu\n",
404                        __func__, __LINE__, pc->orig_line, pc->orig_col);
405                log_flush(true);
406                exit(EX_SOFTWARE);
407             }
408             br_count--;
409 
410             if (pc->level == level)
411             {
412                // mean a statement in a braces { stmt; }
413                // as a statement with a semicolon { stmt; };
414                ++semi_count;
415                hit_semi = true;
416             }
417          }
418          else if (  (  chunk_is_token(pc, CT_IF)
419                     || chunk_is_token(pc, CT_ELSEIF))
420                  && br_count == 0)
421          {
422             if_count++;
423          }
424 
425          if (pc->level == level)
426          {
427             if (  semi_count > 0
428                && hit_semi)
429             {
430                // should have bailed due to close brace level drop
431                LOG_FMT(LBRDEL, "%s(%d):  no close brace\n", __func__, __LINE__);
432                return(false);
433             }
434             LOG_FMT(LBRDEL, "%s(%d): text() '%s', orig_line is %zu, semi_count is %zu\n",
435                     __func__, __LINE__, pc->text(), pc->orig_line, semi_count);
436 
437             if (chunk_is_token(pc, CT_ELSE))
438             {
439                LOG_FMT(LBRDEL, "%s(%d):  bailed on '%s' on line %zu\n",
440                        __func__, __LINE__, pc->text(), pc->orig_line);
441                return(false);
442             }
443 
444             if (  chunk_is_semicolon(pc)
445                || chunk_is_token(pc, CT_IF)
446                || chunk_is_token(pc, CT_ELSEIF)
447                || chunk_is_token(pc, CT_FOR)
448                || chunk_is_token(pc, CT_DO)
449                || chunk_is_token(pc, CT_WHILE)
450                || chunk_is_token(pc, CT_USING_STMT)
451                || (  chunk_is_token(pc, CT_BRACE_OPEN)
452                   && chunk_is_token(prev, CT_FPAREN_CLOSE)))
453             {
454                hit_semi |= chunk_is_semicolon(pc);
455 
456                if (++semi_count > 1)
457                {
458                   LOG_FMT(LBRDEL, "%s(%d):  bailed on %zu because of '%s' on line %zu\n",
459                           __func__, __LINE__, bopen->orig_line, pc->text(), pc->orig_line);
460                   return(false);
461                }
462             }
463          }
464       }
465       prev = pc;
466       pc   = chunk_get_next_nc(pc);
467    }
468 
469    if (pc == nullptr)
470    {
471       LOG_FMT(LBRDEL, "%s(%d):  pc is nullptr\n", __func__, __LINE__);
472       return(false);
473    }
474 
475    if (  chunk_is_token(pc, CT_BRACE_CLOSE)
476       && get_chunk_parent_type(pc) == CT_IF)
477    {
478       chunk_t *next     = chunk_get_next_ncnnl(pc, scope_e::PREPROC);
479       chunk_t *tmp_prev = chunk_get_prev_ncnnl(pc, scope_e::PREPROC);
480 
481       if (  chunk_is_token(next, CT_ELSE)
482          && (  chunk_is_token(tmp_prev, CT_BRACE_CLOSE)
483             || chunk_is_token(tmp_prev, CT_VBRACE_CLOSE))
484          && get_chunk_parent_type(tmp_prev) == CT_IF)
485       {
486          LOG_FMT(LBRDEL, "%s(%d):  - bailed on '%s'[%s] on line %zu due to 'if' and 'else' sequence\n",
487                  __func__, __LINE__, get_token_name(pc->type), get_token_name(get_chunk_parent_type(pc)),
488                  pc->orig_line);
489          return(false);
490       }
491    }
492    LOG_FMT(LBRDEL, "%s(%d):  - end on '%s' on line %zu. if_count is %zu semi_count is %zu\n",
493            __func__, __LINE__, get_token_name(pc->type), pc->orig_line, if_count, semi_count);
494 
495    return(  chunk_is_token(pc, CT_BRACE_CLOSE)
496          && pc->pp_level == bopen->pp_level);
497 } // can_remove_braces
498 
499 
examine_brace(chunk_t * bopen)500 static void examine_brace(chunk_t *bopen)
501 {
502    LOG_FUNC_ENTRY();
503    LOG_FMT(LBRDEL, "%s(%d): start on orig_line %zu, bopen->level is %zu\n",
504            __func__, __LINE__, bopen->orig_line, bopen->level);
505 
506    const size_t level = bopen->level + 1;
507 
508    log_rule_B("mod_full_brace_nl");
509    const size_t nl_max = options::mod_full_brace_nl();
510 
511    chunk_t      *prev      = nullptr;
512    size_t       semi_count = 0;
513    bool         hit_semi   = false;
514    size_t       nl_count   = 0;
515    size_t       if_count   = 0;
516    int          br_count   = 0;
517 
518    chunk_t      *pc = chunk_get_next_nc(bopen);
519 
520    while (  pc != nullptr
521          && pc->level >= level)
522    {
523       if (chunk_is_token(pc, CT_NEWLINE))
524       {
525          LOG_FMT(LBRDEL, "%s(%d): orig_line is %zu, orig_col is %zu, <Newline>\n",
526                  __func__, __LINE__, pc->orig_line, pc->orig_col);
527       }
528       else
529       {
530          LOG_FMT(LBRDEL, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s'\n",
531                  __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
532       }
533 
534       if (pc->flags.test(PCF_IN_PREPROC))
535       {
536          // Cannot remove braces that contain a preprocessor
537          LOG_FMT(LBRDEL, "%s(%d):  PREPROC\n", __func__, __LINE__);
538          return;
539       }
540 
541       if (chunk_is_newline(pc))
542       {
543          nl_count += pc->nl_count;
544 
545          if (  nl_max > 0
546             && nl_count > nl_max)
547          {
548             LOG_FMT(LBRDEL, "%s(%d):  exceeded %zu newlines\n",
549                     __func__, __LINE__, nl_max);
550             return;
551          }
552       }
553       else
554       {
555          LOG_FMT(LBRDEL, "%s(%d): for pc->text() '%s', pc->level is %zu,  bopen->level is %zu\n",
556                  __func__, __LINE__, pc->text(), pc->level, bopen->level);
557 
558          if (  chunk_is_token(pc, CT_BRACE_OPEN)
559             && pc->level == bopen->level)
560          {
561             br_count++;
562             LOG_FMT(LBRDEL, "%s(%d): br_count is now %d, pc->level is %zu,  bopen->level is %zu\n",
563                     __func__, __LINE__, br_count, pc->level, bopen->level);
564          }
565          else if (  chunk_is_token(pc, CT_BRACE_CLOSE)
566                  && pc->level == bopen->level)
567          {
568             if (br_count == 0)
569             {
570                fprintf(stderr, "%s(%d): br_count is ZERO, cannot be decremented, at line %zu, column %zu\n",
571                        __func__, __LINE__, pc->orig_line, pc->orig_col);
572                log_flush(true);
573                exit(EX_SOFTWARE);
574             }
575             br_count--;
576             LOG_FMT(LBRDEL, "%s(%d): br_count is now %d, pc->level is %zu,  bopen->level is %zu\n",
577                     __func__, __LINE__, br_count, pc->level, bopen->level);
578 
579             if (br_count == 0)
580             {
581                chunk_t *next = chunk_get_next_ncnnl(pc, scope_e::PREPROC);
582 
583                if (  next == nullptr
584                   || chunk_is_not_token(next, CT_BRACE_CLOSE))
585                {
586                   LOG_FMT(LBRDEL, "%s(%d):  junk after close brace\n", __func__, __LINE__);
587                   return;
588                }
589             }
590          }
591          else if (  (  chunk_is_token(pc, CT_IF)
592                     || chunk_is_token(pc, CT_ELSEIF))
593                  && br_count == 0)
594          {
595             if_count++;
596          }
597          LOG_FMT(LBRDEL, "%s(%d): pc->level is %zu, level is %zu\n",
598                  __func__, __LINE__, pc->level, level);
599 
600          if (pc->level == level)
601          {
602             if (  semi_count > 0
603                && hit_semi)
604             {
605                // should have bailed due to close brace level drop
606                LOG_FMT(LBRDEL, "%s(%d):  no close brace\n", __func__, __LINE__);
607                return;
608             }
609             LOG_FMT(LBRDEL, "%s(%d): text() '%s', orig_line is %zu, semi_count is %zu\n",
610                     __func__, __LINE__, pc->text(), pc->orig_line, semi_count);
611 
612             if (chunk_is_token(pc, CT_ELSE))
613             {
614                LOG_FMT(LBRDEL, "%s(%d):  bailed on '%s' on line %zu\n",
615                        __func__, __LINE__, pc->text(), pc->orig_line);
616                return;
617             }
618 
619             if (prev != nullptr)
620             {
621                LOG_FMT(LBRDEL, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s', prev->text '%s', prev->type %s\n",
622                        __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text(), prev->text(), get_token_name(prev->type));
623             }
624             else
625             {
626                LOG_FMT(LBRDEL, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s', prev is nullptr\n",
627                        __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
628             }
629             LOG_FMT(LBRDEL, "%s(%d): for pc->text() '%s', pc->level is %zu,  bopen->level is %zu\n",
630                     __func__, __LINE__, pc->text(), pc->level, bopen->level);
631 
632             if (  chunk_is_semicolon(pc)
633                || chunk_is_token(pc, CT_IF)
634                || chunk_is_token(pc, CT_ELSEIF)
635                || chunk_is_token(pc, CT_FOR)
636                || chunk_is_token(pc, CT_DO)
637                || chunk_is_token(pc, CT_WHILE)
638                || chunk_is_token(pc, CT_SWITCH)
639                || chunk_is_token(pc, CT_USING_STMT)
640                || (  chunk_is_token(pc, CT_BRACE_OPEN)
641                   && pc->level == bopen->level)) // Issue #1758
642             {
643                LOG_FMT(LBRDEL, "%s(%d): pc->text() '%s', orig_line is %zu, orig_col is %zu, level is %zu\n",
644                        __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col, pc->level);
645                hit_semi |= chunk_is_semicolon(pc);
646                semi_count++;
647                LOG_FMT(LBRDEL, "%s(%d): semi_count is %zu\n",
648                        __func__, __LINE__, semi_count);
649 
650                if (semi_count > 1)
651                {
652                   LOG_FMT(LBRDEL, "%s(%d):  bailed on %zu because of '%s' on line %zu\n",
653                           __func__, __LINE__, bopen->orig_line, pc->text(), pc->orig_line);
654                   return;
655                }
656             }
657          }
658       }
659       prev = pc;
660       pc   = chunk_get_next(pc);                  // Issue #1907
661    }
662 
663    if (pc == nullptr)
664    {
665       LOG_FMT(LBRDEL, "%s(%d): pc is nullptr\n", __func__, __LINE__);
666       return;
667    }
668    LOG_FMT(LBRDEL, "%s(%d):  - end on '%s' on line %zu. if_count is %zu, semi_count is %zu\n",
669            __func__, __LINE__, get_token_name(pc->type), pc->orig_line, if_count, semi_count);
670 
671    if (chunk_is_token(pc, CT_BRACE_CLOSE))
672    {
673       chunk_t *next = chunk_get_next_ncnnl(pc);
674 
675       if (next != nullptr)
676       {
677          while (chunk_is_token(next, CT_VBRACE_CLOSE))
678          {
679             next = chunk_get_next_ncnnl(next);
680          }
681 
682          if (next != nullptr)
683          {
684             LOG_FMT(LBRDEL, "%s(%d): orig_line is %zu, orig_col is %zu, next is '%s'\n",
685                     __func__, __LINE__, next->orig_line, next->orig_col, get_token_name(next->type));
686          }
687 
688          if (  if_count > 0
689             && (  chunk_is_token(next, CT_ELSE)
690                || chunk_is_token(next, CT_ELSEIF)))
691          {
692             LOG_FMT(LBRDEL, "%s(%d):  bailed on because 'else' is next and %zu ifs\n",
693                     __func__, __LINE__, if_count);
694             return;
695          }
696       }
697       LOG_FMT(LBRDEL, "%s(%d): semi_count is %zu\n",
698               __func__, __LINE__, semi_count);
699 
700       if (semi_count > 0)
701       {
702          LOG_FMT(LBRDEL, "%s(%d): bopen->parent_type is %s\n",
703                  __func__, __LINE__, get_token_name(get_chunk_parent_type(bopen)));
704 
705          if (get_chunk_parent_type(bopen) == CT_ELSE)
706          {
707             chunk_t *tmp_next = chunk_get_next_ncnnl(bopen);
708 
709             if (chunk_is_token(tmp_next, CT_IF))
710             {
711                chunk_t *tmp_prev = chunk_get_prev_ncnnl(bopen);
712                LOG_FMT(LBRDEL, "%s(%d):  else-if removing braces on line %zu and %zu\n",
713                        __func__, __LINE__, bopen->orig_line, pc->orig_line);
714 
715                chunk_del(bopen);
716                chunk_del(pc);
717                newline_del_between(tmp_prev, tmp_next);
718 
719                log_rule_B("nl_else_if");
720 
721                if (options::nl_else_if() & IARF_ADD)
722                {
723                   newline_add_between(tmp_prev, tmp_next);
724                }
725                return;
726             }
727          }
728          // we have a pair of braces with only 1 statement inside
729          LOG_FMT(LBRDEL, "%s(%d): we have a pair of braces with only 1 statement inside\n",
730                  __func__, __LINE__);
731          LOG_FMT(LBRDEL, "%s(%d): removing braces on line %zu and %zu\n",
732                  __func__, __LINE__, bopen->orig_line, pc->orig_line);
733          convert_brace(bopen);
734          convert_brace(pc);
735       }
736       else
737       {
738          LOG_FMT(LBRDEL, "%s(%d):  empty statement\n", __func__, __LINE__);
739       }
740    }
741    else
742    {
743       LOG_FMT(LBRDEL, "%s(%d):  not a close brace? - '%s'\n",
744               __func__, __LINE__, pc->text());
745    }
746 } // examine_brace
747 
748 
convert_brace(chunk_t * br)749 static void convert_brace(chunk_t *br)
750 {
751    LOG_FUNC_ENTRY();
752 
753    if (  br == nullptr
754       || br->flags.test(PCF_KEEP_BRACE))
755    {
756       return;
757    }
758    chunk_t *tmp;
759 
760    if (chunk_is_token(br, CT_BRACE_OPEN))
761    {
762       set_chunk_type(br, CT_VBRACE_OPEN);
763       br->str.clear();
764       tmp = chunk_get_prev(br);
765 
766       if (tmp == nullptr)
767       {
768          return;
769       }
770    }
771    else if (chunk_is_token(br, CT_BRACE_CLOSE))
772    {
773       set_chunk_type(br, CT_VBRACE_CLOSE);
774       br->str.clear();
775       tmp = chunk_get_next(br);
776 
777       if (tmp == nullptr)
778       {
779          return;
780       }
781    }
782    else
783    {
784       return;
785    }
786 
787    if (chunk_is_newline(tmp))
788    {
789       if (tmp->nl_count > 1)
790       {
791          if (!br->flags.test(PCF_ONE_LINER)) // Issue #2232
792          {
793             if (tmp->nl_count == 0)
794             {
795                fprintf(stderr, "%s(%d): tmp->nl_count is ZERO, cannot be decremented, at line %zu, column %zu\n",
796                        __func__, __LINE__, tmp->orig_line, tmp->orig_col);
797                log_flush(true);
798                exit(EX_SOFTWARE);
799             }
800             tmp->nl_count--;
801             LOG_FMT(LBRDEL, "%s(%d): tmp->nl_count is %zu\n",
802                     __func__, __LINE__, tmp->nl_count);
803          }
804       }
805       else
806       {
807          // Issue #2219
808          // look for opening brace
809          chunk_t *brace = nullptr;
810 
811          if (chunk_is_token(br, CT_VBRACE_OPEN))
812          {
813             brace = tmp;
814          }
815          else if (chunk_is_token(br, CT_VBRACE_CLOSE))
816          {
817             brace = chunk_skip_to_match_rev(br);
818 
819             if (brace == nullptr)
820             {
821                brace = chunk_get_prev_type(br, CT_BRACE_OPEN, br->level);
822             }
823          }
824 
825          if (  chunk_is_token(br, CT_VBRACE_OPEN)
826             || (  chunk_is_token(br, CT_VBRACE_CLOSE)
827                && brace->orig_line < tmp->orig_line))
828          {
829             if (chunk_safe_to_del_nl(tmp))
830             {
831                chunk_del(tmp);
832             }
833          }
834       }
835    }
836 } // convert_brace
837 
838 
convert_vbrace(chunk_t * vbr)839 static void convert_vbrace(chunk_t *vbr)
840 {
841    LOG_FUNC_ENTRY();
842 
843    if (vbr == nullptr)
844    {
845       return;
846    }
847 
848    if (chunk_is_token(vbr, CT_VBRACE_OPEN))
849    {
850       set_chunk_type(vbr, CT_BRACE_OPEN);
851       vbr->str = "{";
852 
853       /*
854        * If the next chunk is a preprocessor, then move the open brace after the
855        * preprocessor.
856        */
857       chunk_t *tmp = chunk_get_next(vbr);
858 
859       if (chunk_is_token(tmp, CT_PREPROC))
860       {
861          tmp = chunk_get_next(vbr, scope_e::PREPROC);
862          chunk_move_after(vbr, tmp);
863          newline_add_after(vbr);
864       }
865    }
866    else if (chunk_is_token(vbr, CT_VBRACE_CLOSE))
867    {
868       set_chunk_type(vbr, CT_BRACE_CLOSE);
869       vbr->str = "}";
870 
871       /*
872        * If the next chunk is a comment, followed by a newline, then
873        * move the brace after the newline and add another newline after
874        * the close brace.
875        */
876       chunk_t *tmp = chunk_get_next(vbr);
877 
878       if (chunk_is_comment(tmp))
879       {
880          tmp = chunk_get_next(tmp);
881 
882          if (chunk_is_newline(tmp))
883          {
884             chunk_move_after(vbr, tmp);
885             newline_add_after(vbr);
886          }
887       }
888    }
889 } // convert_vbrace
890 
891 
convert_vbrace_to_brace(void)892 static void convert_vbrace_to_brace(void)
893 {
894    LOG_FUNC_ENTRY();
895 
896    // Find every vbrace open
897    log_rule_B("mod_full_brace_if");
898    log_rule_B("mod_full_brace_if_chain");
899    log_rule_B("mod_full_brace_for");
900    log_rule_B("mod_full_brace_do");
901    log_rule_B("mod_full_brace_while");
902    log_rule_B("mod_full_brace_using");
903    log_rule_B("mod_full_brace_function");
904 
905    for (chunk_t *pc = chunk_get_head(); pc != nullptr; pc = chunk_get_next_ncnnl(pc))
906    {
907       if (chunk_is_not_token(pc, CT_VBRACE_OPEN))
908       {
909          continue;
910       }
911       auto const in_preproc = pc->flags.test(PCF_IN_PREPROC);
912 
913       if (  (  (  get_chunk_parent_type(pc) == CT_IF
914                || get_chunk_parent_type(pc) == CT_ELSE
915                || get_chunk_parent_type(pc) == CT_ELSEIF)
916             && (options::mod_full_brace_if() & IARF_ADD)
917             && !options::mod_full_brace_if_chain())
918          || (  get_chunk_parent_type(pc) == CT_FOR
919             && (options::mod_full_brace_for() & IARF_ADD))
920          || (  get_chunk_parent_type(pc) == CT_DO
921             && (options::mod_full_brace_do() & IARF_ADD))
922          || (  get_chunk_parent_type(pc) == CT_WHILE
923             && (options::mod_full_brace_while() & IARF_ADD))
924          || (  get_chunk_parent_type(pc) == CT_USING_STMT
925             && (options::mod_full_brace_using() & IARF_ADD))
926          || (  get_chunk_parent_type(pc) == CT_FUNC_DEF
927             && (options::mod_full_brace_function() & IARF_ADD)))
928       {
929          // Find the matching vbrace close
930          chunk_t *vbc = nullptr;
931          chunk_t *tmp = pc;
932 
933          while ((tmp = chunk_get_next(tmp)) != nullptr)
934          {
935             if (  in_preproc
936                && !tmp->flags.test(PCF_IN_PREPROC))
937             {
938                // Can't leave a preprocessor
939                break;
940             }
941 
942             if (  pc->brace_level == tmp->brace_level
943                && chunk_is_token(tmp, CT_VBRACE_CLOSE)
944                && get_chunk_parent_type(pc) == get_chunk_parent_type(tmp)
945                && ((tmp->flags & PCF_IN_PREPROC) == (pc->flags & PCF_IN_PREPROC)))
946             {
947                vbc = tmp;
948                break;
949             }
950          }
951 
952          if (vbc == nullptr)
953          {
954             continue;
955          }
956          // if we found a corresponding virtual closing brace
957          convert_vbrace(pc);   // convert both the opening
958          convert_vbrace(vbc);  // and closing brace
959       }
960    }
961 } // convert_vbrace_to_brace
962 
963 
insert_comment_after(chunk_t * ref,c_token_t cmt_type,const unc_text & cmt_text)964 chunk_t *insert_comment_after(chunk_t *ref, c_token_t cmt_type,
965                               const unc_text &cmt_text)
966 {
967    LOG_FUNC_ENTRY();
968 
969    chunk_t new_cmt = *ref;
970 
971    new_cmt.prev  = nullptr;
972    new_cmt.next  = nullptr;
973    new_cmt.flags = (ref->flags & PCF_COPY_FLAGS);
974    set_chunk_type(&new_cmt, cmt_type);
975    new_cmt.str.clear();
976 
977    if (cmt_type == CT_COMMENT_CPP)
978    {
979       new_cmt.str.append("// ");
980       new_cmt.str.append(cmt_text);
981    }
982    else
983    {
984       if (chunk_is_token(ref, CT_PP_ELSE))
985       {  // make test c/ 02501 stable
986          new_cmt.str.append(" ");
987       }
988       new_cmt.str.append("/* ");
989       new_cmt.str.append(cmt_text);
990       new_cmt.str.append(" */");
991    }
992    // TODO: expand comment type to cover other comment styles?
993 
994    new_cmt.column   = ref->column + ref->len() + 1;
995    new_cmt.orig_col = new_cmt.column;
996 
997    return(chunk_add_after(&new_cmt, ref));
998 }
999 
1000 
append_tag_name(unc_text & txt,chunk_t * pc)1001 static void append_tag_name(unc_text &txt, chunk_t *pc)
1002 {
1003    LOG_FUNC_ENTRY();
1004    chunk_t *tmp = pc;
1005 
1006    LOG_FMT(LMCB, "%s(%d): txt is '%s'\n",
1007            __func__, __LINE__, txt.c_str());
1008 
1009    // step backwards over all a::b stuff
1010    while ((tmp = chunk_get_prev_ncnnl(tmp)) != nullptr)
1011    {
1012       if (  chunk_is_not_token(tmp, CT_DC_MEMBER)
1013          && chunk_is_not_token(tmp, CT_MEMBER))
1014       {
1015          break;
1016       }
1017       tmp = chunk_get_prev_ncnnl(tmp);
1018       pc  = tmp;
1019 
1020       if (!chunk_is_word(tmp))
1021       {
1022          break;
1023       }
1024    }
1025    txt += pc->str;
1026    LOG_FMT(LMCB, "%s(%d): txt is '%s'\n",
1027            __func__, __LINE__, txt.c_str());
1028 
1029    while ((pc = chunk_get_next_ncnnl(pc)) != nullptr)
1030    {
1031       if (  chunk_is_not_token(pc, CT_DC_MEMBER)
1032          && chunk_is_not_token(pc, CT_MEMBER))
1033       {
1034          break;
1035       }
1036       txt += pc->str;
1037       LOG_FMT(LMCB, "%s(%d): txt is '%s'\n",
1038               __func__, __LINE__, txt.c_str());
1039       pc = chunk_get_next_ncnnl(pc);
1040 
1041       if (pc != nullptr)
1042       {
1043          txt += pc->str;
1044          LOG_FMT(LMCB, "%s(%d): txt is '%s'\n",
1045                  __func__, __LINE__, txt.c_str());
1046       }
1047    }
1048 } // append_tag_name
1049 
1050 
add_long_closebrace_comment(void)1051 void add_long_closebrace_comment(void)
1052 {
1053    LOG_FUNC_ENTRY();
1054    chunk_t *fcn_pc = nullptr;
1055    chunk_t *sw_pc  = nullptr;
1056    chunk_t *ns_pc  = nullptr;
1057    chunk_t *cl_pc  = nullptr;
1058 
1059    for (chunk_t *pc = chunk_get_head(); pc != nullptr; pc = chunk_get_next_ncnnl(pc))
1060    {
1061       if (  chunk_is_token(pc, CT_FUNC_DEF)
1062          || chunk_is_token(pc, CT_OC_MSG_DECL))
1063       {
1064          fcn_pc = pc;
1065       }
1066       else if (chunk_is_token(pc, CT_SWITCH))
1067       {
1068          // pointless, since it always has the text "switch"
1069          sw_pc = pc;
1070       }
1071       else if (chunk_is_token(pc, CT_NAMESPACE))
1072       {
1073          ns_pc = pc;
1074       }
1075       else if (chunk_is_token(pc, CT_CLASS))
1076       {
1077          cl_pc = pc;
1078       }
1079 
1080       if (  chunk_is_not_token(pc, CT_BRACE_OPEN)
1081          || pc->flags.test(PCF_IN_PREPROC))
1082       {
1083          continue;
1084       }
1085       chunk_t *br_open = pc;
1086       size_t  nl_count = 0;
1087 
1088       chunk_t *tmp = pc;
1089 
1090       while ((tmp = chunk_get_next(tmp, scope_e::PREPROC)) != nullptr)
1091       {
1092          if (chunk_is_newline(tmp))
1093          {
1094             nl_count += tmp->nl_count;
1095             continue;
1096          }
1097 
1098          // handle only matching closing braces, skip other chunks
1099          if (  tmp->level != br_open->level
1100             || chunk_is_not_token(tmp, CT_BRACE_CLOSE))
1101          {
1102             continue;
1103          }
1104          chunk_t *br_close = tmp;
1105 
1106          tmp = chunk_get_next(tmp);
1107 
1108          // check for a possible end semicolon
1109          if (chunk_is_token(tmp, CT_SEMICOLON))
1110          {
1111             // set br_close to the semi token,
1112             // as br_close is used to add the coment after it
1113             br_close = tmp;
1114             tmp      = chunk_get_next(tmp);
1115          }
1116 
1117          // make sure a newline follows in order to not overwrite an already
1118          // existring comment
1119          if (  tmp != nullptr
1120             && !chunk_is_newline(tmp))
1121          {
1122             break;
1123          }
1124          size_t   nl_min  = 0;
1125          chunk_t  *tag_pc = nullptr;
1126          unc_text xstr;
1127 
1128          if (  get_chunk_parent_type(br_open) == CT_FUNC_DEF
1129             || get_chunk_parent_type(br_open) == CT_OC_MSG_DECL)
1130          {
1131             log_rule_B("mod_add_long_function_closebrace_comment");
1132             nl_min = options::mod_add_long_function_closebrace_comment();
1133             tag_pc = fcn_pc;
1134 
1135             if (tag_pc != nullptr)
1136             {
1137                append_tag_name(xstr, tag_pc);
1138                LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1139                        __func__, __LINE__, xstr.c_str());
1140             }
1141          }
1142          else if (  get_chunk_parent_type(br_open) == CT_SWITCH
1143                  && sw_pc != nullptr)
1144          {
1145             log_rule_B("mod_add_long_switch_closebrace_comment");
1146             nl_min = options::mod_add_long_switch_closebrace_comment();
1147             tag_pc = sw_pc;
1148             xstr   = sw_pc->str;
1149             LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1150                     __func__, __LINE__, xstr.c_str());
1151          }
1152          else if (  get_chunk_parent_type(br_open) == CT_NAMESPACE
1153                  && ns_pc != nullptr)
1154          {
1155             log_rule_B("mod_add_long_namespace_closebrace_comment");
1156             nl_min = options::mod_add_long_namespace_closebrace_comment();
1157             tag_pc = ns_pc;
1158             xstr   = tag_pc->str;    // add 'namespace' to the string
1159             LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1160                     __func__, __LINE__, xstr.c_str());
1161 
1162             // next chunk, normally is going to be the namespace name
1163             // append it with a space to generate "namespace xyz"
1164             chunk_t *tmp_next = chunk_get_next_ncnnl(tag_pc);
1165 
1166             if (chunk_is_not_token(tmp_next, CT_BRACE_OPEN)) // anonymous namespace -> ignore
1167             {
1168                xstr.append(" ");
1169                LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1170                        __func__, __LINE__, xstr.c_str());
1171                append_tag_name(xstr, tmp_next);
1172                LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1173                        __func__, __LINE__, xstr.c_str());
1174             }
1175          }
1176          else if (  get_chunk_parent_type(br_open) == CT_CLASS
1177                  && cl_pc != nullptr
1178                  && (  !language_is_set(LANG_CPP)               // proceed if not C++
1179                     || chunk_is_token(br_close, CT_SEMICOLON))) // else a C++ class needs to end with a semicolon
1180          {
1181             log_rule_B("mod_add_long_class_closebrace_comment");
1182             nl_min = options::mod_add_long_class_closebrace_comment();
1183             tag_pc = cl_pc;
1184             xstr   = tag_pc->str;
1185             LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1186                     __func__, __LINE__, xstr.c_str());
1187 
1188             chunk_t *tmp_next = chunk_get_next(cl_pc);
1189 
1190             if (tag_pc != nullptr)
1191             {
1192                xstr.append(" ");
1193                LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1194                        __func__, __LINE__, xstr.c_str());
1195                append_tag_name(xstr, tmp_next);
1196                LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1197                        __func__, __LINE__, xstr.c_str());
1198             }
1199          }
1200 
1201          if (  nl_min > 0
1202             && nl_count >= nl_min
1203             && tag_pc != nullptr)
1204          {
1205             // use the comment style that fits to the selected language
1206             const c_token_t style = language_is_set(LANG_CPP | LANG_CS)
1207                                     ? CT_COMMENT_CPP : CT_COMMENT;
1208 
1209             // Add a comment after the close brace
1210             LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n",
1211                     __func__, __LINE__, xstr.c_str());
1212             insert_comment_after(br_close, style, xstr);
1213          }
1214          break;
1215       }
1216    }
1217 } // add_long_closebrace_comment
1218 
1219 
move_case_break(void)1220 static void move_case_break(void)
1221 {
1222    LOG_FUNC_ENTRY();
1223    chunk_t *prev = nullptr;
1224 
1225    for (chunk_t *pc = chunk_get_head(); pc != nullptr; pc = chunk_get_next_ncnnl(pc))
1226    {
1227       if (  chunk_is_token(pc, CT_BREAK)
1228          && chunk_is_token(prev, CT_BRACE_CLOSE)
1229          && get_chunk_parent_type(prev) == CT_CASE
1230          && chunk_is_newline(chunk_get_prev(pc))
1231          && chunk_is_newline(chunk_get_prev(prev)))
1232       {
1233          chunk_swap_lines(prev, pc);
1234       }
1235       prev = pc;
1236    }
1237 }
1238 
1239 
mod_case_brace_remove(chunk_t * br_open)1240 static chunk_t *mod_case_brace_remove(chunk_t *br_open)
1241 {
1242    LOG_FUNC_ENTRY();
1243    LOG_FMT(LMCB, "%s(%d): line %zu",
1244            __func__, __LINE__, br_open->orig_line);
1245 
1246    // Find the matching brace close
1247    chunk_t *next     = chunk_get_next_ncnnl(br_open, scope_e::PREPROC);
1248    chunk_t *br_close = chunk_get_next_type(br_open, CT_BRACE_CLOSE, br_open->level, scope_e::PREPROC);
1249 
1250    if (br_close == nullptr)
1251    {
1252       LOG_FMT(LMCB, "%s(%d):  - no close\n", __func__, __LINE__);
1253       return(next);
1254    }
1255    // Make sure 'break', 'return', 'goto', 'case' or '}' is after the close brace
1256    chunk_t *pc = chunk_get_next_ncnnl(br_close, scope_e::PREPROC);
1257 
1258    if (  pc == nullptr
1259       || (  chunk_is_not_token(pc, CT_BREAK)
1260          && chunk_is_not_token(pc, CT_RETURN)
1261          && chunk_is_not_token(pc, CT_CASE)
1262          && chunk_is_not_token(pc, CT_GOTO)
1263          && chunk_is_not_token(pc, CT_BRACE_CLOSE)))
1264    {
1265       LOG_FMT(LMCB, "%s(%d):  - after '%s'\n",
1266               __func__, __LINE__, (pc == nullptr) ? "<null>" : get_token_name(pc->type));
1267       return(next);
1268    }
1269 
1270    // scan to make sure there are no definitions at brace level between braces
1271    for (chunk_t *tmp_pc = br_open;
1272         tmp_pc != br_close;
1273         tmp_pc = chunk_get_next_ncnnl(tmp_pc, scope_e::PREPROC))
1274    {
1275       if (  tmp_pc->level == (br_open->level + 1)
1276          && tmp_pc->flags.test(PCF_VAR_DEF))
1277       {
1278          LOG_FMT(LMCB, "%s(%d):  - vardef on line %zu: '%s'\n",
1279                  __func__, __LINE__, tmp_pc->orig_line, pc->text());
1280          return(next);
1281       }
1282    }
1283 
1284    LOG_FMT(LMCB, "%s(%d):  - removing braces on lines %zu and %zu\n",
1285            __func__, __LINE__, br_open->orig_line, br_close->orig_line);
1286 
1287    for (chunk_t *tmp_pc = br_open;
1288         tmp_pc != br_close;
1289         tmp_pc = chunk_get_next_ncnnl(tmp_pc, scope_e::PREPROC))
1290    {
1291       if (tmp_pc->brace_level == 0)
1292       {
1293          fprintf(stderr, "%s(%d): tmp_pc->brace_level is ZERO, cannot be decremented, at line %zu, column %zu\n",
1294                  __func__, __LINE__, tmp_pc->orig_line, tmp_pc->orig_col);
1295          log_flush(true);
1296          exit(EX_SOFTWARE);
1297       }
1298       tmp_pc->brace_level--;
1299 
1300       if (tmp_pc->level == 0)
1301       {
1302          fprintf(stderr, "%s(%d): tmp_pc->level is ZERO, cannot be decremented, at line %zu, column %zu\n",
1303                  __func__, __LINE__, tmp_pc->orig_line, tmp_pc->orig_col);
1304          log_flush(true);
1305          exit(EX_SOFTWARE);
1306       }
1307       tmp_pc->level--;
1308    }
1309 
1310    next = chunk_get_prev(br_open, scope_e::PREPROC);
1311 
1312    chunk_del(br_open);
1313    chunk_del(br_close);
1314 
1315    return(chunk_get_next(next, scope_e::PREPROC));
1316 } // mod_case_brace_remove
1317 
1318 
mod_case_brace_add(chunk_t * cl_colon)1319 static chunk_t *mod_case_brace_add(chunk_t *cl_colon)
1320 {
1321    LOG_FUNC_ENTRY();
1322    LOG_FMT(LMCB, "%s(%d): orig_line %zu, orig_col is %zu\n",
1323            __func__, __LINE__, cl_colon->orig_line, cl_colon->orig_col);
1324 
1325    chunk_t *pc   = cl_colon;
1326    chunk_t *last = nullptr;
1327    // look for the case token to the colon
1328    chunk_t *cas_ = chunk_get_prev_type(cl_colon, CT_CASE, cl_colon->level);
1329    // look for the parent
1330    chunk_t *swit = cas_->parent;
1331    // look for the opening brace of the switch
1332    chunk_t *open = chunk_get_next_type(swit, CT_BRACE_OPEN, swit->level);
1333    // look for the closing brace of the switch
1334    chunk_t *clos = chunk_skip_to_match(open);
1335 
1336    // find the end of the case-block
1337    while ((pc = chunk_get_next_ncnnl(pc, scope_e::PREPROC)) != nullptr)
1338    {
1339       LOG_FMT(LMCB, "%s(%d): text() is '%s', orig_line %zu, orig_col is %zu, pp_level is %zu\n",
1340               __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col, pc->pp_level);
1341 
1342       if (pc->level == cl_colon->level)
1343       {
1344          if (chunk_is_token(pc, CT_CASE))
1345          {
1346             LOG_FMT(LMCB, "%s(%d): text() is '%s', orig_line %zu, orig_col is %zu\n",
1347                     __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
1348             last = calculate_closing_brace_position(cl_colon, pc);
1349             break;
1350          }
1351       }
1352       else if (pc->level == cl_colon->level - 1)
1353       {
1354          if (pc == clos)
1355          {
1356             LOG_FMT(LMCB, "%s(%d): text() is '%s', orig_line %zu, orig_col is %zu\n",
1357                     __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
1358             // end of switch is reached
1359             last = calculate_closing_brace_position(cl_colon, pc);
1360             LOG_FMT(LMCB, "%s(%d): last->text() is '%s', orig_line %zu, orig_col is %zu\n",
1361                     __func__, __LINE__, last->text(), last->orig_line, last->orig_col);
1362             break;
1363          }
1364       }
1365    }
1366 
1367    if (last == nullptr)
1368    {
1369       LOG_FMT(LMCB, "%s(%d):  - last is nullptr\n", __func__, __LINE__);
1370       chunk_t *next = chunk_get_next_ncnnl(cl_colon, scope_e::PREPROC);
1371       return(next);
1372    }
1373    LOG_FMT(LMCB, "%s(%d): last->text() is '%s', orig_line %zu, orig_col is %zu\n",
1374            __func__, __LINE__, last->text(), last->orig_line, last->orig_col);
1375    LOG_FMT(LMCB, "%s(%d): adding braces after '%s' on line %zu\n",
1376            __func__, __LINE__, cl_colon->text(), cl_colon->orig_line);
1377 
1378    chunk_t chunk;
1379 
1380    set_chunk_type(&chunk, CT_BRACE_OPEN);
1381    set_chunk_parent(&chunk, CT_CASE);
1382    chunk.orig_line   = cl_colon->orig_line;
1383    chunk.orig_col    = cl_colon->orig_col;
1384    chunk.level       = cl_colon->level;
1385    chunk.pp_level    = cl_colon->pp_level;
1386    chunk.brace_level = cl_colon->brace_level;
1387    chunk.flags       = pc->flags & PCF_COPY_FLAGS;
1388    chunk.str         = "{";
1389    chunk_t *br_open = chunk_add_after(&chunk, cl_colon);
1390 
1391    set_chunk_type(&chunk, CT_BRACE_CLOSE);
1392    chunk.orig_line = last->orig_line;
1393    chunk.orig_col  = last->orig_col;
1394    chunk.str       = "}";
1395    chunk_t *br_close = chunk_add_after(&chunk, last);
1396 
1397    for (pc = chunk_get_next(br_open, scope_e::PREPROC);
1398         pc != br_close;
1399         pc = chunk_get_next(pc, scope_e::PREPROC))
1400    {
1401       pc->level++;
1402       pc->brace_level++;
1403    }
1404 
1405    return(br_open);
1406 } // mod_case_brace_add
1407 
1408 
mod_case_brace(void)1409 static void mod_case_brace(void)
1410 {
1411    LOG_FUNC_ENTRY();
1412 
1413    chunk_t *pc = chunk_get_head();
1414 
1415    // Make sure to start outside of a preprocessor line (see issue #3366)
1416    if (chunk_is_preproc(pc))
1417    {
1418       pc = chunk_get_next_ncnnlnp(pc);
1419    }
1420 
1421    while (pc != nullptr)
1422    {
1423       chunk_t *next = chunk_get_next_ncnnl(pc, scope_e::PREPROC);
1424 
1425       if (next == nullptr)
1426       {
1427          return;
1428       }
1429       log_rule_B("mod_case_brace");
1430 
1431       if (  options::mod_case_brace() == IARF_REMOVE
1432          && chunk_is_token(pc, CT_BRACE_OPEN)
1433          && get_chunk_parent_type(pc) == CT_CASE)
1434       {
1435          log_rule_B("mod_case_brace - add");
1436          pc = mod_case_brace_remove(pc);
1437       }
1438       else if (  (options::mod_case_brace() & IARF_ADD)
1439               && chunk_is_token(pc, CT_CASE_COLON)
1440               && chunk_is_not_token(next, CT_BRACE_OPEN)
1441               && chunk_is_not_token(next, CT_BRACE_CLOSE)
1442               && chunk_is_not_token(next, CT_CASE))
1443       {
1444          log_rule_B("mod_case_brace - remove");
1445          pc = mod_case_brace_add(pc);
1446       }
1447       else
1448       {
1449          pc = chunk_get_next_ncnnl(pc, scope_e::PREPROC);
1450       }
1451    }
1452 } // mod_case_brace
1453 
1454 
process_if_chain(chunk_t * br_start)1455 static void process_if_chain(chunk_t *br_start)
1456 {
1457    LOG_FUNC_ENTRY();
1458    LOG_FMT(LBRCH, "%s(%d): if starts on line %zu, orig_col is %zu.\n",
1459            __func__, __LINE__, br_start->orig_line, br_start->orig_col);
1460 
1461    vector<chunk_t *> braces;
1462 
1463    braces.reserve(16);
1464 
1465    bool    must_have_braces = false;
1466 
1467    chunk_t *pc = br_start;
1468 
1469    while (pc != nullptr)
1470    {
1471       LOG_FMT(LBRCH, "%s(%d): pc->text() is '%s', orig_line is %zu, orig_col is %zu.\n",
1472               __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
1473 
1474       if (chunk_is_token(pc, CT_BRACE_OPEN))
1475       {
1476          const bool tmp = can_remove_braces(pc);
1477          LOG_FMT(LBRCH, "%s(%d): braces.size() is %zu, line is %zu, - can%s remove %s\n",
1478                  __func__, __LINE__, braces.size(), pc->orig_line, tmp ? "" : "not",
1479                  get_token_name(pc->type));
1480 
1481          if (!tmp)
1482          {
1483             must_have_braces = true;
1484          }
1485       }
1486       else
1487       {
1488          const bool tmp = should_add_braces(pc);
1489 
1490          if (tmp)
1491          {
1492             must_have_braces = true;
1493          }
1494          LOG_FMT(LBRCH, "%s(%d): braces.size() is %zu, line is %zu, - %s %s\n",
1495                  __func__, __LINE__, braces.size(), pc->orig_line, tmp ? "should add" : "ignore",
1496                  get_token_name(pc->type));
1497       }
1498       braces.push_back(pc);
1499       chunk_t *br_close = chunk_skip_to_match(pc, scope_e::PREPROC);
1500 
1501       if (br_close == nullptr)
1502       {
1503          break;
1504       }
1505       braces.push_back(br_close);
1506 
1507       pc = chunk_get_next_ncnnl(br_close, scope_e::PREPROC);
1508 
1509       if (  pc == nullptr
1510          || chunk_is_not_token(pc, CT_ELSE))
1511       {
1512          break;
1513       }
1514       log_rule_B("mod_full_brace_if_chain_only");
1515 
1516       if (options::mod_full_brace_if_chain_only())
1517       {
1518          // There is an 'else' - we want full braces.
1519          must_have_braces = true;
1520       }
1521       pc = chunk_get_next_ncnnl(pc, scope_e::PREPROC);
1522 
1523       if (chunk_is_token(pc, CT_ELSEIF))
1524       {
1525          while (  chunk_is_not_token(pc, CT_VBRACE_OPEN)
1526                && chunk_is_not_token(pc, CT_BRACE_OPEN))
1527          {
1528             pc = chunk_get_next_ncnnl(pc, scope_e::PREPROC);
1529          }
1530       }
1531 
1532       if (pc == nullptr)
1533       {
1534          break;
1535       }
1536 
1537       if (  chunk_is_not_token(pc, CT_BRACE_OPEN)
1538          && chunk_is_not_token(pc, CT_VBRACE_OPEN))
1539       {
1540          break;
1541       }
1542    }
1543 
1544    if (must_have_braces)
1545    {
1546       LOG_FMT(LBRCH, "%s(%d): add braces on lines[%zu]:",
1547               __func__, __LINE__, braces.size());
1548 
1549       const auto ite = braces.rend();
1550 
1551       for (auto itc = braces.rbegin(); itc != ite; ++itc)
1552       {
1553          const auto brace = *itc;
1554 
1555          chunk_flags_set(brace, PCF_KEEP_BRACE);
1556 
1557          if (  chunk_is_token(brace, CT_VBRACE_OPEN)
1558             || chunk_is_token(brace, CT_VBRACE_CLOSE))
1559          {
1560             LOG_FMT(LBRCH, "%s(%d):  %zu",
1561                     __func__, __LINE__, brace->orig_line);
1562             convert_vbrace(brace);
1563          }
1564          else
1565          {
1566             LOG_FMT(LBRCH, "%s(%d):  {%zu}",
1567                     __func__, __LINE__, brace->orig_line);
1568          }
1569       }
1570 
1571       LOG_FMT(LBRCH, "\n");
1572    }
1573    else if (options::mod_full_brace_if_chain())
1574    {
1575       log_rule_B("mod_full_brace_if_chain");
1576       LOG_FMT(LBRCH, "%s(%d): remove braces on lines[%zu]:\n",
1577               __func__, __LINE__, braces.size());
1578 
1579       /*
1580        * This might run because either
1581        * mod_full_brace_if_chain or mod_full_brace_if_chain_only
1582        * is used.
1583        * We only want to remove braces if the first one is active.
1584        */
1585       log_rule_B("mod_full_brace_nl_block_rem_mlcond");
1586       const auto multiline_block = options::mod_full_brace_nl_block_rem_mlcond();
1587 
1588       LOG_FMT(LBRCH, "%s(%d): remove braces on lines:\n", __func__, __LINE__);
1589 
1590       // Issue #2229
1591       const auto ite = braces.end();
1592 
1593       for (auto itc = braces.begin(); itc != ite; ++itc)
1594       {
1595          const auto brace = *itc;
1596 
1597          if (  (  chunk_is_token(brace, CT_BRACE_OPEN)
1598                || chunk_is_token(brace, CT_BRACE_CLOSE))
1599             && (get_chunk_parent_type(brace) != CT_BRACED_INIT_LIST)
1600             && (multiline_block ? !paren_multiline_before_brace(brace) : true))
1601          {
1602             LOG_FMT(LBRCH, "%s(%d): brace->orig_line is %zu, brace->orig_col is %zu\n",
1603                     __func__, __LINE__, brace->orig_line, brace->orig_col);
1604             convert_brace(brace);
1605          }
1606          else
1607          {
1608             LOG_FMT(LBRCH, "%s(%d): brace->orig_line is %zu, brace->orig_col is %zu\n",
1609                     __func__, __LINE__, brace->orig_line, brace->orig_col);
1610          }
1611       }
1612    }
1613 } // process_if_chain
1614 
1615 
mod_full_brace_if_chain(void)1616 static void mod_full_brace_if_chain(void)
1617 {
1618    LOG_FUNC_ENTRY();
1619 
1620    for (chunk_t *pc = chunk_get_head(); pc != nullptr; pc = chunk_get_next(pc))
1621    {
1622       if (  (  chunk_is_token(pc, CT_BRACE_OPEN)
1623             || chunk_is_token(pc, CT_VBRACE_OPEN))
1624          && get_chunk_parent_type(pc) == CT_IF)
1625       {
1626          process_if_chain(pc);
1627       }
1628    }
1629 }
1630