summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/width.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/width.cpp')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/width.cpp923
1 files changed, 923 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/width.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/width.cpp
new file mode 100644
index 00000000..a3dbeab4
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/width.cpp
@@ -0,0 +1,923 @@
+/**
+ * @file width.cpp
+ * Limits line width.
+ *
+ * @author Ben Gardner
+ * @license GPL v2+
+ */
+
+#include "width.h"
+
+#include "indent.h"
+#include "newlines.h"
+#include "prototypes.h"
+
+
+constexpr static auto LCURRENT = LSPLIT;
+
+using namespace uncrustify;
+
+
+/**
+ * abbreviations used:
+ * - fparen = function parenthesis
+ */
+
+struct cw_entry
+{
+ Chunk *pc;
+ size_t pri;
+};
+
+
+struct token_pri
+{
+ E_Token tok;
+ size_t pri;
+};
+
+
+static inline bool is_past_width(Chunk *pc);
+
+
+//! Split right after the chunk
+static void split_before_chunk(Chunk *pc);
+
+
+static size_t get_split_pri(E_Token tok);
+
+
+/**
+ * Checks to see if pc is a better spot to split.
+ * This should only be called going BACKWARDS (ie prev)
+ * A lower level wins
+ *
+ * Splitting Preference:
+ * - semicolon
+ * - comma
+ * - boolean op
+ * - comparison
+ * - arithmetic op
+ * - assignment
+ * - concatenated strings
+ * - ? :
+ * - function open paren not followed by close paren
+ */
+static void try_split_here(cw_entry &ent, Chunk *pc);
+
+
+/**
+ * Scan backwards to find the most appropriate spot to split the line
+ * and insert a newline.
+ *
+ * See if this needs special function handling.
+ * Scan backwards and find the best token for the split.
+ *
+ * @param start The first chunk that exceeded the limit
+ */
+static bool split_line(Chunk *pc);
+
+
+/**
+ * Figures out where to split a function def/proto/call
+ *
+ * For function prototypes and definition. Also function calls where
+ * level == brace_level:
+ * - find the open function parenthesis
+ * + if it doesn't have a newline right after it
+ * * see if all parameters will fit individually after the paren
+ * * if not, throw a newline after the open paren & return
+ * - scan backwards to the open fparen or comma
+ * + if there isn't a newline after that item, add one & return
+ * + otherwise, add a newline before the start token
+ *
+ * @param start the offending token
+ * @return the token that should have a newline
+ * inserted before it
+ */
+static void split_fcn_params(Chunk *start);
+
+
+/**
+ * Figures out where to split a template
+ *
+ *
+ * @param start the offending token
+ */
+static void split_template(Chunk *start);
+
+
+/**
+ * Splits the parameters at every comma that is at the fparen level.
+ *
+ * @param start the offending token
+ */
+static void split_fcn_params_full(Chunk *start);
+
+
+/**
+ * A for statement is too long.
+ * Step backwards and forwards to find the semicolons
+ * Try splitting at the semicolons first.
+ * If that doesn't work, then look for a comma at paren level.
+ * If that doesn't work, then look for an assignment at paren level.
+ * If that doesn't work, then give up.
+ */
+static void split_for_stmt(Chunk *start);
+
+
+static inline bool is_past_width(Chunk *pc)
+{
+ // allow char to sit at last column by subtracting 1
+ LOG_FMT(LSPLIT, "%s(%d): orig_line is %zu, orig_col is %zu, for %s\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->Text());
+ log_rule_B("code_width");
+ return((pc->column + pc->Len() - 1) > options::code_width());
+}
+
+
+static void split_before_chunk(Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d): Text() '%s'\n", __func__, __LINE__, pc->Text());
+
+ if ( !chunk_is_newline(pc)
+ && !chunk_is_newline(pc->GetPrev()))
+ {
+ newline_add_before(pc);
+ // reindent needs to include the indent_continue value and was off by one
+ log_rule_B("indent_columns");
+ log_rule_B("indent_continue");
+ reindent_line(pc, pc->brace_level * options::indent_columns() +
+ abs(options::indent_continue()) + 1);
+ cpd.changes++;
+ }
+}
+
+
+void do_code_width(void)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d)\n", __func__, __LINE__);
+
+ for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext())
+ {
+ if ( !chunk_is_newline(pc)
+ && !pc->IsComment()
+ && chunk_is_not_token(pc, CT_SPACE)
+ && is_past_width(pc))
+ {
+ if ( chunk_is_token(pc, CT_VBRACE_CLOSE) // don't break if a vbrace close
+ && chunk_is_last_on_line(pc)) // is the last chunk on its line
+ {
+ continue;
+ }
+ bool split_OK = split_line(pc);
+
+ if (split_OK)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): orig_line is %zu, orig_col is %zu, Text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->Text());
+ }
+ else
+ {
+ LOG_FMT(LSPLIT, "%s(%d): Bailed! orig_line is %zu, orig_col is %zu, Text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->Text());
+ break;
+ }
+ }
+ }
+}
+
+
+static const token_pri pri_table[] =
+{
+ { CT_SEMICOLON, 1 },
+ { CT_COMMA, 2 },
+ { CT_BOOL, 3 },
+ { CT_COMPARE, 4 },
+ { CT_SHIFT, 5 },
+ { CT_ARITH, 6 },
+ { CT_CARET, 7 },
+ { CT_ASSIGN, 8 },
+ { CT_STRING, 9 },
+ { CT_FOR_COLON, 10 },
+ //{ CT_DC_MEMBER, 11 },
+ //{ CT_MEMBER, 11 },
+ { CT_QUESTION, 20 }, // allow break in ? : for ls_code_width
+ { CT_COND_COLON, 20 },
+ { CT_FPAREN_OPEN, 21 }, // break after function open paren not followed by close paren
+ { CT_QUALIFIER, 25 },
+ { CT_CLASS, 25 },
+ { CT_STRUCT, 25 },
+ { CT_TYPE, 25 },
+ { CT_TYPENAME, 25 },
+ { CT_VOLATILE, 25 },
+};
+
+
+static size_t get_split_pri(E_Token tok)
+{
+ for (auto token : pri_table)
+ {
+ if (token.tok == tok)
+ {
+ return(token.pri);
+ }
+ }
+
+ return(0);
+}
+
+
+static void try_split_here(cw_entry &ent, Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+
+ LOG_FMT(LSPLIT, "%s(%d): at %s, orig_col=%zu\n", __func__, __LINE__, pc->Text(), pc->orig_col);
+ size_t pc_pri = get_split_pri(pc->type);
+
+ LOG_FMT(LSPLIT, "%s(%d): pc_pri is %zu\n", __func__, __LINE__, pc_pri);
+
+ if (pc_pri == 0)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): pc_pri is 0, return\n", __func__, __LINE__);
+ return;
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+ // Can't split after a newline
+ Chunk *prev = pc->GetPrev();
+
+ if ( prev == nullptr
+ || ( chunk_is_newline(prev)
+ && chunk_is_not_token(pc, CT_STRING)))
+ {
+ if (prev != nullptr)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): Can't split after a newline, orig_line is %zu, return\n",
+ __func__, __LINE__, prev->orig_line);
+ }
+ return;
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+
+ // Can't split a function without arguments
+ if (chunk_is_token(pc, CT_FPAREN_OPEN))
+ {
+ Chunk *next = pc->GetNext();
+
+ if (chunk_is_token(next, CT_FPAREN_CLOSE))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): Can't split a function without arguments, return\n", __func__, __LINE__);
+ return;
+ }
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+
+ // Only split concatenated strings
+ if (chunk_is_token(pc, CT_STRING))
+ {
+ Chunk *next = pc->GetNext();
+
+ if (chunk_is_not_token(next, CT_STRING))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): Only split concatenated strings, return\n", __func__, __LINE__);
+ return;
+ }
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+
+ // keep common groupings unless ls_code_width
+ log_rule_B("ls_code_width");
+
+ if ( !options::ls_code_width()
+ && pc_pri >= 20)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): keep common groupings unless ls_code_width, return\n", __func__, __LINE__);
+ return;
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+
+ // don't break after last term of a qualified type
+ if (pc_pri == 25)
+ {
+ Chunk *next = pc->GetNext();
+
+ if ( chunk_is_not_token(next, CT_WORD)
+ && (get_split_pri(next->type) != 25))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): don't break after last term of a qualified type, return\n", __func__, __LINE__);
+ return;
+ }
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+ // Check levels first
+ bool change = false;
+
+ if ( ent.pc == nullptr
+ || pc->level < ent.pc->level)
+ {
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+ change = true;
+ }
+ else
+ {
+ if (pc_pri < ent.pri)
+ {
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+ change = true;
+ }
+ }
+ LOG_FMT(LSPLIT, "%s(%d): change is %s\n", __func__, __LINE__, change ? "TRUE" : "FALSE");
+
+ if (change)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): do the change\n", __func__, __LINE__);
+ ent.pc = pc;
+ ent.pri = pc_pri;
+ }
+} // try_split_here
+
+
+static bool split_line(Chunk *start)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d): start->Text() '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, start->Text(), start->orig_line, start->orig_col, get_token_name(start->type));
+ LOG_FMT(LSPLIT, " start->flags ");
+ log_pcf_flags(LSPLIT, start->flags);
+ LOG_FMT(LSPLIT, " start->parent_type %s, (PCF_IN_FCN_DEF is %s), (PCF_IN_FCN_CALL is %s)\n",
+ get_token_name(get_chunk_parent_type(start)),
+ start->flags.test((PCF_IN_FCN_DEF)) ? "TRUE" : "FALSE",
+ start->flags.test((PCF_IN_FCN_CALL)) ? "TRUE" : "FALSE");
+
+ // break at maximum line length if ls_code_width is true
+ // Issue #2432
+ if (start->flags.test(PCF_ONE_LINER))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): ** ONCE LINER SPLIT **\n", __func__, __LINE__);
+ undo_one_liner(start);
+ newlines_cleanup_braces(false);
+ // Issue #1352
+ cpd.changes++;
+ return(false);
+ }
+ LOG_FMT(LSPLIT, "%s(%d): before ls_code_width\n", __func__, __LINE__);
+
+ log_rule_B("ls_code_width");
+
+ if (options::ls_code_width())
+ {
+ }
+ // Check to see if we are in a for statement
+ else if (start->flags.test(PCF_IN_FOR))
+ {
+ LOG_FMT(LSPLIT, " ** FOR SPLIT **\n");
+ split_for_stmt(start);
+
+ if (!is_past_width(start))
+ {
+ return(true);
+ }
+ LOG_FMT(LSPLIT, "%s(%d): for split didn't work\n", __func__, __LINE__);
+ }
+
+ /*
+ * If this is in a function call or prototype, split on commas or right
+ * after the open parenthesis
+ */
+ else if ( start->flags.test(PCF_IN_FCN_DEF)
+ || get_chunk_parent_type(start) == CT_FUNC_PROTO // Issue #1169
+ || ( (start->level == (start->brace_level + 1))
+ && start->flags.test(PCF_IN_FCN_CALL)))
+ {
+ LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n");
+
+ log_rule_B("ls_func_split_full");
+
+ if (options::ls_func_split_full())
+ {
+ split_fcn_params_full(start);
+
+ if (!is_past_width(start))
+ {
+ return(true);
+ }
+ }
+ split_fcn_params(start);
+ return(true);
+ }
+
+ /*
+ * If this is in a template, split on commas, Issue #1170
+ */
+ else if (start->flags.test(PCF_IN_TEMPLATE))
+ {
+ LOG_FMT(LSPLIT, " ** TEMPLATE SPLIT **\n");
+ split_template(start);
+ return(true);
+ }
+ LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__);
+ // Try to find the best spot to split the line
+ cw_entry ent;
+
+ memset(&ent, 0, sizeof(ent));
+ Chunk *pc = start;
+ Chunk *prev;
+
+ while ( ((pc = pc->GetPrev()) != nullptr)
+ && pc->IsNotNullChunk()
+ && !chunk_is_newline(pc))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): at %s, orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, pc->Text(), pc->orig_line, pc->orig_col);
+
+ if (chunk_is_not_token(pc, CT_SPACE))
+ {
+ try_split_here(ent, pc);
+
+ // break at maximum line length
+ log_rule_B("ls_code_width");
+
+ if ( ent.pc != nullptr
+ && (options::ls_code_width()))
+ {
+ break;
+ }
+ }
+ }
+
+ if (ent.pc == nullptr)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded NO SOLUTION for orig_line %zu at '%s' [%s]\n",
+ __func__, __LINE__, start->orig_line, start->Text(), get_token_name(start->type));
+ }
+ else
+ {
+ LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded '%s' [%s] on orig_line %zu\n",
+ __func__, __LINE__, ent.pc->Text(), get_token_name(ent.pc->type), ent.pc->orig_line);
+ LOG_FMT(LSPLIT, "%s(%d): ent at '%s', orig_col is %zu\n",
+ __func__, __LINE__, ent.pc->Text(), ent.pc->orig_col);
+ }
+
+ // Break before the token instead of after it according to the pos_xxx rules
+ if (ent.pc == nullptr)
+ {
+ pc = nullptr;
+ }
+ else
+ {
+ log_rule_B("pos_arith");
+ log_rule_B("pos_assign");
+ log_rule_B("pos_compare");
+ log_rule_B("pos_conditional");
+ log_rule_B("pos_shift");
+ log_rule_B("pos_bool");
+
+ if ( ( chunk_is_token(ent.pc, CT_SHIFT)
+ && (options::pos_shift() & TP_LEAD))
+ || ( ( chunk_is_token(ent.pc, CT_ARITH)
+ || chunk_is_token(ent.pc, CT_CARET))
+ && (options::pos_arith() & TP_LEAD))
+ || ( chunk_is_token(ent.pc, CT_ASSIGN)
+ && (options::pos_assign() & TP_LEAD))
+ || ( chunk_is_token(ent.pc, CT_COMPARE)
+ && (options::pos_compare() & TP_LEAD))
+ || ( ( chunk_is_token(ent.pc, CT_COND_COLON)
+ || chunk_is_token(ent.pc, CT_QUESTION))
+ && (options::pos_conditional() & TP_LEAD))
+ || ( chunk_is_token(ent.pc, CT_BOOL)
+ && (options::pos_bool() & TP_LEAD)))
+ {
+ pc = ent.pc;
+ }
+ else
+ {
+ pc = ent.pc->GetNext();
+ }
+ LOG_FMT(LSPLIT, "%s(%d): at '%s', orig_col is %zu\n",
+ __func__, __LINE__, pc->Text(), pc->orig_col);
+ }
+
+ if ( pc == nullptr
+ || pc->IsNullChunk())
+ {
+ pc = start;
+
+ // Don't break before a close, comma, or colon
+ if ( chunk_is_token(start, CT_PAREN_CLOSE)
+ || chunk_is_token(start, CT_PAREN_OPEN)
+ || chunk_is_token(start, CT_FPAREN_CLOSE)
+ || chunk_is_token(start, CT_FPAREN_OPEN)
+ || chunk_is_token(start, CT_SPAREN_CLOSE)
+ || chunk_is_token(start, CT_SPAREN_OPEN)
+ || chunk_is_token(start, CT_ANGLE_CLOSE)
+ || chunk_is_token(start, CT_BRACE_CLOSE)
+ || chunk_is_token(start, CT_COMMA)
+ || chunk_is_token(start, CT_SEMICOLON)
+ || chunk_is_token(start, CT_VSEMICOLON)
+ || start->Len() == 0)
+ {
+ LOG_FMT(LSPLIT, " ** NO GO **\n");
+
+ // TODO: Add in logic to handle 'hard' limits by backing up a token
+ return(true);
+ }
+ }
+ // add a newline before pc
+ prev = pc->GetPrev();
+
+ if ( prev != nullptr
+ && prev->IsNotNullChunk()
+ && !chunk_is_newline(pc)
+ && !chunk_is_newline(prev))
+ {
+ //int plen = (pc->Len() < 5) ? pc->Len() : 5;
+ //int slen = (start->Len() < 5) ? start->Len() : 5;
+ //LOG_FMT(LSPLIT, " '%.*s' [%s], started on token '%.*s' [%s]\n",
+ // plen, pc->Text(), get_token_name(pc->type),
+ // slen, start->Text(), get_token_name(start->type));
+ LOG_FMT(LSPLIT, "%s(%d): Text() '%s', type %s, started on token '%s', type %s\n",
+ __func__, __LINE__, pc->Text(), get_token_name(pc->type),
+ start->Text(), get_token_name(start->type));
+
+ split_before_chunk(pc);
+ }
+ return(true);
+} // split_line
+
+
+/*
+ * The for statement split algorithm works as follows:
+ * 1. Step backwards and forwards to find the semicolons
+ * 2. Try splitting at the semicolons first.
+ * 3. If that doesn't work, then look for a comma at paren level.
+ * 4. If that doesn't work, then look for an assignment at paren level.
+ * 5. If that doesn't work, then give up.
+ */
+static void split_for_stmt(Chunk *start)
+{
+ LOG_FUNC_ENTRY();
+ // how many semicolons (1 or 2) do we need to find
+ log_rule_B("ls_for_split_full");
+ size_t max_cnt = options::ls_for_split_full() ? 2 : 1;
+ Chunk *open_paren = nullptr;
+ size_t nl_cnt = 0;
+
+ LOG_FMT(LSPLIT, "%s: starting on %s, line %zu\n",
+ __func__, start->Text(), start->orig_line);
+
+ // Find the open paren so we know the level and count newlines
+ Chunk *pc = start;
+
+ while ( ((pc = pc->GetPrev()) != nullptr)
+ && pc->IsNotNullChunk())
+ {
+ if (chunk_is_token(pc, CT_SPAREN_OPEN))
+ {
+ open_paren = pc;
+ break;
+ }
+
+ if (pc->nl_count > 0)
+ {
+ nl_cnt += pc->nl_count;
+ }
+ }
+
+ if (open_paren == nullptr)
+ {
+ LOG_FMT(LSPLIT, "No open paren\n");
+ return;
+ }
+ // see if we started on the semicolon
+ int count = 0;
+ Chunk *st[2];
+
+ pc = start;
+
+ if ( chunk_is_token(pc, CT_SEMICOLON)
+ && get_chunk_parent_type(pc) == CT_FOR)
+ {
+ st[count++] = pc;
+ }
+
+ // first scan backwards for the semicolons
+ while ( (count < static_cast<int>(max_cnt))
+ && ((pc = pc->GetPrev()) != nullptr)
+ && pc->IsNotNullChunk()
+ && pc->flags.test(PCF_IN_SPAREN))
+ {
+ if ( chunk_is_token(pc, CT_SEMICOLON)
+ && get_chunk_parent_type(pc) == CT_FOR)
+ {
+ st[count++] = pc;
+ }
+ }
+ // And now scan forward
+ pc = start;
+
+ while ( (count < static_cast<int>(max_cnt))
+ && ((pc = pc->GetNext())->IsNotNullChunk())
+ && pc->flags.test(PCF_IN_SPAREN))
+ {
+ if ( chunk_is_token(pc, CT_SEMICOLON)
+ && get_chunk_parent_type(pc) == CT_FOR)
+ {
+ st[count++] = pc;
+ }
+ }
+
+ while (--count >= 0)
+ {
+ // TODO: st[0] may be uninitialized here
+ LOG_FMT(LSPLIT, "%s(%d): split before %s\n", __func__, __LINE__, st[count]->Text());
+ split_before_chunk(st[count]->GetNext());
+ }
+
+ if ( !is_past_width(start)
+ || nl_cnt > 0)
+ {
+ return;
+ }
+ // Still past width, check for commas at parenthese level
+ pc = open_paren;
+
+ while ((pc = pc->GetNext()) != start)
+ {
+ if ( chunk_is_token(pc, CT_COMMA)
+ && (pc->level == (open_paren->level + 1)))
+ {
+ split_before_chunk(pc->GetNext());
+
+ if (!is_past_width(pc))
+ {
+ return;
+ }
+ }
+ }
+ // Still past width, check for a assignments at parenthese level
+ pc = open_paren;
+
+ while ((pc = pc->GetNext()) != start)
+ {
+ if ( chunk_is_token(pc, CT_ASSIGN)
+ && (pc->level == (open_paren->level + 1)))
+ {
+ split_before_chunk(pc->GetNext());
+
+ if (!is_past_width(pc))
+ {
+ return;
+ }
+ }
+ }
+ // Oh, well. We tried.
+} // split_for_stmt
+
+
+static void split_fcn_params_full(Chunk *start)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d): %s\n", __func__, __LINE__, start->Text());
+
+ // Find the opening function parenthesis
+ Chunk *fpo = start;
+
+ LOG_FMT(LSPLIT, " %s(%d): Find the opening function parenthesis\n", __func__, __LINE__);
+
+ while ( (fpo = fpo->GetPrev()) != nullptr
+ && fpo->IsNotNullChunk())
+ {
+ LOG_FMT(LSPLIT, "%s(%d): %s, orig_col is %zu, level is %zu\n",
+ __func__, __LINE__, fpo->Text(), fpo->orig_col, fpo->level);
+
+ if ( chunk_is_token(fpo, CT_FPAREN_OPEN)
+ && (fpo->level == start->level - 1))
+ {
+ break; // opening parenthesis found. Issue #1020
+ }
+ }
+ // Now break after every comma
+ Chunk *pc = fpo->GetNextNcNnl();
+
+ while (pc->IsNotNullChunk())
+ {
+ if (pc->level <= fpo->level)
+ {
+ break;
+ }
+
+ if ( (pc->level == (fpo->level + 1))
+ && chunk_is_token(pc, CT_COMMA))
+ {
+ split_before_chunk(pc->GetNext());
+ }
+ pc = pc->GetNextNcNnl();
+ }
+}
+
+
+static void split_fcn_params(Chunk *start)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d): start->Text() is '%s', orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, start->Text(), start->orig_line, start->orig_col);
+ Chunk *fpo = start;
+
+ if (!chunk_is_token(start, CT_FPAREN_OPEN))
+ {
+ // Find the opening function parenthesis
+ LOG_FMT(LSPLIT, "%s(%d): Find the opening function parenthesis\n", __func__, __LINE__);
+
+ while ( ((fpo = fpo->GetPrev()) != nullptr)
+ && fpo->IsNotNullChunk()
+ && chunk_is_not_token(fpo, CT_FPAREN_OPEN))
+ {
+ // do nothing
+ LOG_FMT(LSPLIT, "%s(%d): '%s', orig_col is %zu, level is %zu\n",
+ __func__, __LINE__, fpo->Text(), fpo->orig_col, fpo->level);
+ }
+ }
+ Chunk *pc = fpo->GetNextNcNnl();
+ size_t min_col = pc->column;
+
+ log_rule_B("code_width");
+ LOG_FMT(LSPLIT, " mincol is %zu, max_width is %zu\n",
+ min_col, options::code_width() - min_col);
+
+ int cur_width = 0;
+ int last_col = -1;
+
+ LOG_FMT(LSPLIT, "%s(%d):look forward until CT_COMMA or CT_FPAREN_CLOSE\n", __func__, __LINE__);
+
+ while (pc->IsNotNullChunk())
+ {
+ LOG_FMT(LSPLIT, "%s(%d): pc->Text() '%s', type is %s\n",
+ __func__, __LINE__, pc->Text(), get_token_name(pc->type));
+
+ if (chunk_is_newline(pc))
+ {
+ cur_width = 0;
+ last_col = -1;
+ }
+ else
+ {
+ if (last_col < 0)
+ {
+ last_col = pc->column;
+ LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
+ __func__, __LINE__, last_col);
+ }
+ cur_width += (pc->column - last_col) + pc->Len();
+ last_col = pc->column + pc->Len();
+
+ LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
+ __func__, __LINE__, last_col);
+
+ if ( chunk_is_token(pc, CT_COMMA)
+ || chunk_is_token(pc, CT_FPAREN_CLOSE))
+ {
+ if (cur_width == 0)
+ {
+ fprintf(stderr, "%s(%d): cur_width is ZERO, cannot be decremented, at line %zu, column %zu\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col);
+ log_flush(true);
+ exit(EX_SOFTWARE);
+ }
+ cur_width--;
+ LOG_FMT(LSPLIT, "%s(%d): cur_width is %d\n",
+ __func__, __LINE__, cur_width);
+
+ log_rule_B("code_width");
+
+ if ( ((last_col - 1) > static_cast<int>(options::code_width()))
+ || chunk_is_token(pc, CT_FPAREN_CLOSE))
+ {
+ break;
+ }
+ }
+ }
+ pc = pc->GetNext();
+ }
+ // back up until the prev is a comma
+ Chunk *prev = pc;
+
+ LOG_FMT(LSPLIT, "%s(%d): back up until the prev is a comma, begin is '%s', level is %zu\n",
+ __func__, __LINE__, prev->Text(), prev->level);
+
+ while ((prev = prev->GetPrev())->IsNotNullChunk())
+ {
+ LOG_FMT(LSPLIT, "%s(%d): prev->Text() is '%s', prev->orig_line is %zu, prev->orig_col is %zu\n",
+ __func__, __LINE__, prev->Text(), prev->orig_line, prev->orig_col);
+ LOG_FMT(LSPLIT, "%s(%d): prev->level is %zu, prev '%s', prev->type is %s\n",
+ __func__, __LINE__, prev->level, prev->Text(), get_token_name(prev->type));
+
+ if ( chunk_is_newline(prev)
+ || chunk_is_token(prev, CT_COMMA))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): found at %zu\n",
+ __func__, __LINE__, prev->orig_col);
+ break;
+ }
+ LOG_FMT(LSPLIT, "%s(%d): last_col is %d, prev->Len() is %zu\n",
+ __func__, __LINE__, last_col, prev->Len());
+ last_col -= prev->Len();
+ LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
+ __func__, __LINE__, last_col);
+
+ if (chunk_is_token(prev, CT_FPAREN_OPEN))
+ {
+ pc = prev->GetNext();
+
+ log_rule_B("indent_paren_nl");
+
+ if (!options::indent_paren_nl())
+ {
+ log_rule_B("indent_columns");
+ min_col = pc->brace_level * options::indent_columns() + 1;
+ LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n",
+ __func__, __LINE__, min_col);
+
+ log_rule_B("indent_continue");
+
+ if (options::indent_continue() == 0)
+ {
+ log_rule_B("indent_columns");
+ min_col += options::indent_columns();
+ }
+ else
+ {
+ min_col += abs(options::indent_continue());
+ }
+ LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n",
+ __func__, __LINE__, min_col);
+ }
+
+ // Don't split "()"
+ if (pc->type != E_Token(prev->type + 1))
+ {
+ break;
+ }
+ }
+ }
+
+ if ( prev->IsNotNullChunk()
+ && !chunk_is_newline(prev))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): -- ended on %s --\n",
+ __func__, __LINE__, get_token_name(prev->type));
+ LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n",
+ __func__, __LINE__, min_col);
+ pc = prev->GetNext();
+ newline_add_before(pc);
+ reindent_line(pc, min_col);
+ cpd.changes++;
+ }
+} // split_fcn_params
+
+
+static void split_template(Chunk *start)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, " %s(%d): start %s\n", __func__, __LINE__, start->Text());
+ LOG_FMT(LSPLIT, " %s(%d): back up until the prev is a comma\n", __func__, __LINE__);
+
+ // back up until the prev is a comma
+ Chunk *prev = start;
+
+ while ((prev = prev->GetPrev())->IsNotNullChunk())
+ {
+ LOG_FMT(LSPLIT, " %s(%d): prev '%s'\n", __func__, __LINE__, prev->Text());
+
+ if ( chunk_is_newline(prev)
+ || chunk_is_token(prev, CT_COMMA))
+ {
+ break;
+ }
+ }
+
+ if ( prev != nullptr
+ && !chunk_is_newline(prev))
+ {
+ LOG_FMT(LSPLIT, " %s(%d):", __func__, __LINE__);
+ LOG_FMT(LSPLIT, " -- ended on %s --\n", get_token_name(prev->type));
+ Chunk *pc = prev->GetNext();
+ newline_add_before(pc);
+ size_t min_col = 1;
+
+ log_rule_B("indent_continue");
+
+ if (options::indent_continue() == 0)
+ {
+ log_rule_B("indent_columns");
+ min_col += options::indent_columns();
+ }
+ else
+ {
+ min_col += abs(options::indent_continue());
+ }
+ reindent_line(pc, min_col);
+ cpd.changes++;
+ }
+} // split_templatefcn_params