1 /**
2  * @file align_func_params.cpp
3  *
4  * @author  Guy Maurel
5  * split from align.cpp
6  * @author  Ben Gardner
7  * @license GPL v2+
8  */
9 
10 #include "align_func_params.h"
11 
12 #include "align_stack.h"
13 #include "log_rules.h"
14 
15 #include <algorithm>                           // to get max
16 
17 constexpr static auto LCURRENT = LALIGN;
18 
19 using namespace uncrustify;
20 
21 
align_func_param(chunk_t * start)22 chunk_t *align_func_param(chunk_t *start)
23 {
24    LOG_FUNC_ENTRY();
25 
26    LOG_FMT(LAS, "AlignStack::%s(%d): Candidate is '%s': orig_line is %zu, column is %zu, type is %s, level is %zu\n",
27            __func__, __LINE__, start->text(), start->orig_line, start->column,
28            get_token_name(start->type), start->level);
29    // Defaults, if the align_func_params = true
30    size_t myspan   = 2;
31    size_t mythresh = 0;
32    size_t mygap    = 0;
33 
34    // Override, if the align_func_params_span > 0
35    log_rule_B("align_func_params_span");
36 
37    if (options::align_func_params_span() > 0)
38    {
39       myspan = options::align_func_params_span();
40       log_rule_B("align_func_params_thresh");
41       mythresh = options::align_func_params_thresh();
42       log_rule_B("align_func_params_gap");
43       mygap = options::align_func_params_gap();
44    }
45    const size_t HOW_MANY_AS = 16;                         // Issue #2921
46    AlignStack   many_as[HOW_MANY_AS + 1];
47 
48    size_t       max_level_is = 0;
49 
50    log_rule_B("align_var_def_star_style");
51    log_rule_B("align_var_def_amp_style");
52 
53    for (size_t idx = 0; idx <= HOW_MANY_AS; idx++)
54    {
55       many_as[idx].Start(myspan, mythresh);
56       many_as[idx].m_gap        = mygap;
57       many_as[idx].m_star_style = static_cast<AlignStack::StarStyle>(options::align_var_def_star_style());
58       many_as[idx].m_amp_style  = static_cast<AlignStack::StarStyle>(options::align_var_def_amp_style());
59    }
60 
61    size_t  comma_count = 0;
62    size_t  chunk_count = 0;
63    chunk_t *pc         = start;
64 
65    while ((pc = chunk_get_next(pc)) != nullptr)
66    {
67       chunk_count++;
68       LOG_FMT(LFLPAREN, "%s(%d): orig_line is %zu, orig_col is %zu, text() is '%s', type is %s\n",
69               __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text(),
70               get_token_name(pc->type));
71 
72       if (chunk_is_token(pc, CT_FUNC_VAR))                    // Issue #2278
73       {
74          // look after 'protect parenthesis'
75          chunk_t *after = chunk_get_next_nc(pc);
76 
77          if (chunk_is_token(after, CT_PAREN_CLOSE))
78          {
79             chunk_t *before = chunk_get_prev_type(after, CT_PAREN_OPEN, after->level);
80 
81             if (before != nullptr)
82             {
83                // these are 'protect parenthesis'
84                // change the types and the level
85                set_chunk_type(before, CT_PPAREN_OPEN);
86                set_chunk_type(after, CT_PPAREN_CLOSE);
87                pc->level = before->level;
88                chunk_t *tmp = chunk_get_prev_nc(pc);
89 
90                if (chunk_is_token(tmp, CT_PTR_TYPE))
91                {
92                   tmp->level = before->level;
93                }
94             }
95          }
96       }
97 
98       if (chunk_is_newline(pc))
99       {
100          comma_count = 0;
101          chunk_count = 0;
102          many_as[pc->level].NewLines(pc->nl_count);
103       }
104       else if (pc->level <= start->level)
105       {
106          break;
107       }
108       else if (pc->flags.test(PCF_VAR_DEF))
109       {
110          if (chunk_count > 1)
111          {
112             if (pc->level > HOW_MANY_AS)
113             {
114                fprintf(stderr, "%s(%d): Not enought memory for Stack\n",
115                        __func__, __LINE__);
116                fprintf(stderr, "%s(%d): the current maximum is %zu\n",
117                        __func__, __LINE__, HOW_MANY_AS);
118                log_flush(true);
119                exit(EX_SOFTWARE);
120             }
121             max_level_is = max(max_level_is, pc->level);
122             many_as[pc->level].Add(pc);
123          }
124       }
125       else if (comma_count > 0)
126       {
127          if (!chunk_is_comment(pc))
128          {
129             comma_count = 2;
130             break;
131          }
132       }
133       else if (chunk_is_token(pc, CT_COMMA))
134       {
135          if (pc->flags.test(PCF_IN_TEMPLATE))            // Issue #2757
136          {
137             LOG_FMT(LFLPAREN, "%s(%d): comma is in template\n",
138                     __func__, __LINE__);
139          }
140          else
141          {
142             chunk_t *tmp_prev = chunk_get_prev_nc(pc);
143 
144             if (!chunk_is_newline(tmp_prev))  // don't count leading commas
145             {
146                comma_count++;
147                LOG_FMT(LFLPAREN, "%s(%d): comma_count is %zu\n",
148                        __func__, __LINE__, comma_count);
149             }
150          }
151       }
152    }
153 
154    if (comma_count <= 1)
155    {
156       for (size_t idx = 1; idx <= max_level_is; idx++)
157       {
158          many_as[idx].End();
159       }
160    }
161    return(pc);
162 } // align_func_param
163 
164 
align_func_params(void)165 void align_func_params(void)
166 {
167    LOG_FUNC_ENTRY();
168    chunk_t *pc = chunk_get_head();
169 
170    while ((pc = chunk_get_next(pc)) != nullptr)
171    {
172       LOG_FMT(LFLPAREN, "%s(%d): orig_line is %zu, orig_col is %zu, text() is '%s', parent_type is %s, parent_type is %s\n",
173               __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text(),
174               get_token_name(pc->type), get_token_name(pc->parent_type));
175 
176       if (  chunk_is_not_token(pc, CT_FPAREN_OPEN)
177          || (  get_chunk_parent_type(pc) != CT_FUNC_PROTO
178             && get_chunk_parent_type(pc) != CT_FUNC_DEF
179             && get_chunk_parent_type(pc) != CT_FUNC_CLASS_PROTO
180             && get_chunk_parent_type(pc) != CT_FUNC_CLASS_DEF
181             && get_chunk_parent_type(pc) != CT_TYPEDEF))
182       {
183          continue;
184       }
185       // We are on a open parenthesis of a prototype
186       pc = align_func_param(pc);
187    }
188 } // void align_func_params
189