summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp798
1 files changed, 798 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp
new file mode 100644
index 00000000..66b5f4ff
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp
@@ -0,0 +1,798 @@
+/**
+ * @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 SplitEntry
+{
+ Chunk *pc;
+ size_t pri;
+
+ SplitEntry()
+ : pc(Chunk::NullChunkPtr)
+ , pri(0) {}
+};
+
+
+struct TokenPriority
+{
+ 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(SplitEntry &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 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
+ size_t currCol = pc->GetColumn() + pc->Len() - 1;
+ bool past_width = currCol > options::code_width();
+
+ LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, curr col %zu, text '%s', past width %s\n",
+ __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), currCol, pc->Text(),
+ past_width ? "YES" : "NO");
+ return(past_width);
+}
+
+
+static void split_before_chunk(Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d): Text() '%s'\n", __func__, __LINE__, pc->Text());
+
+ Chunk *prev = pc->GetPrev();
+
+ if ( !pc->IsNewline()
+ && !prev->IsNewline())
+ {
+ newline_add_before(pc);
+ // Mark chunk as continuation line, so indentation can be
+ // correctly set over multiple passes
+ pc->SetFlagBits(PCF_CONT_LINE);
+
+ // Mark open and close parens as continuation line chunks.
+ // This will prevent an additional level and frame to be
+ // added to the current frame stack (issue 3105).
+ if ( prev->Is(CT_PAREN_OPEN)
+ || prev->Is(CT_LPAREN_OPEN)
+ || prev->Is(CT_SPAREN_OPEN)
+ || prev->Is(CT_FPAREN_OPEN)
+ || prev->Is(CT_SQUARE_OPEN)
+ || prev->Is(CT_ANGLE_OPEN))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): set PCF_LINE_CONT for prev text '%s', orig line is %zu, orig col is %zu\n",
+ __func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol());
+
+ prev->SetFlagBits(PCF_CONT_LINE);
+ Chunk *closing_paren = prev->GetClosingParen();
+
+ if (closing_paren->IsNotNullChunk())
+ {
+ closing_paren->SetFlagBits(PCF_CONT_LINE);
+ }
+ }
+ // 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->GetBraceLevel() * options::indent_columns() +
+ abs(options::indent_continue()) + 1);
+ cpd.changes++;
+ }
+} // split_before_chunk
+
+
+static TokenPriority 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, 9 },
+ { CT_STRING, 10 },
+ { CT_FOR_COLON, 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 },
+};
+
+
+void do_code_width()
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LSPLIT, "%s(%d)\n", __func__, __LINE__);
+
+ // If indent_continue is negative, we want to look for long lines splits,
+ // so raise CT_FPAREN_OPEN priority to get better results.
+ if (options::indent_continue() < 0)
+ {
+ for (TokenPriority &token : pri_table)
+ {
+ if (token.tok == CT_FPAREN_OPEN)
+ {
+ token.pri = 8; // Before assignment priority
+ break;
+ }
+ }
+ }
+
+ for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext())
+ {
+ if ( !pc->IsCommentOrNewline()
+ && pc->IsNot(CT_SPACE)
+ && is_past_width(pc))
+ {
+ if ( pc->Is(CT_VBRACE_CLOSE) // don't break if a vbrace close
+ && pc->IsLastChunkOnLine()) // is the last chunk on its line
+ {
+ continue;
+ }
+ bool split_OK = split_line(pc);
+
+ if (split_OK)
+ {
+ // After a line split it is necessary to reindent the text before considering
+ // further splits. This avoid splits out of position which would produce an
+ // awkward result in some cases when a line needs more that one split.
+ // After the split, skip over the remainder of the line.
+ Chunk *nextNl = pc->GetNextNl();
+ LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, text '%s' splitted\n",
+ __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
+ pc = nextNl;
+ }
+ else
+ {
+ LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, text '%s' not splitted\n",
+ __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
+ break;
+ }
+ }
+ }
+} // do_code_width
+
+
+static size_t get_split_pri(E_Token tok)
+{
+ for (TokenPriority token : pri_table)
+ {
+ if (token.tok == tok)
+ {
+ return(token.pri);
+ }
+ }
+
+ return(100); // Bigger than any valid priority
+}
+
+
+static void try_split_here(SplitEntry &ent, Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+
+ size_t pc_pri = get_split_pri(pc->GetType());
+ LOG_FMT(LSPLIT, "%s(%d): text '%s', orig col %zu pc_pri %zu\n",
+ __func__, __LINE__, pc->Text(), pc->GetOrigCol(), pc_pri);
+
+ if (pc_pri == 0)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): pc_pri is 0, return\n", __func__, __LINE__);
+ return;
+ }
+ // Can't split after a newline
+ Chunk *prev = pc->GetPrev();
+
+ if ( prev->IsNullChunk()
+ || ( prev->IsNewline()
+ && pc->IsNot(CT_STRING)))
+ {
+ if (prev->IsNotNullChunk())
+ {
+ LOG_FMT(LSPLIT, "%s(%d): can't split after a newline, orig line is %zu, return\n",
+ __func__, __LINE__, prev->GetOrigLine());
+ }
+ return;
+ }
+
+ // Can't split a function without arguments
+ if (pc->Is(CT_FPAREN_OPEN))
+ {
+ Chunk *next = pc->GetNext();
+
+ if (next->Is(CT_FPAREN_CLOSE))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): can't split a function without arguments, return\n", __func__, __LINE__);
+ return;
+ }
+ }
+
+ // Only split concatenated strings
+ if (pc->Is(CT_STRING))
+ {
+ Chunk *next = pc->GetNext();
+
+ if (next->IsNot(CT_STRING))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): only split concatenated strings, return\n", __func__, __LINE__);
+ return;
+ }
+ }
+
+ // keep common groupings unless ls_code_width
+ if ( !options::ls_code_width()
+ && pc_pri >= 22)
+ {
+ LOG_FMT(LSPLIT, "%s(%d): keep common groupings unless ls_code_width, return\n", __func__, __LINE__);
+ return;
+ }
+
+ // don't break after last term of a qualified type
+ if (pc_pri == 25)
+ {
+ Chunk *next = pc->GetNext();
+
+ if ( next->IsNot(CT_WORD)
+ && (get_split_pri(next->GetType()) != 25))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): don't break after last term of a qualified type, return\n", __func__, __LINE__);
+ return;
+ }
+ }
+
+ if ( ent.pc->IsNullChunk()
+ || pc_pri < ent.pri
+ || ( pc_pri == ent.pri
+ && pc->IsNot(CT_FPAREN_OPEN)
+ && pc->GetLevel() < ent.pc->GetLevel()))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): found possible split\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 %zu, orig col %zu, type %s\n",
+ __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetOrigCol(), get_token_name(start->GetType()));
+ LOG_FMT(LSPLIT, " flags ");
+ log_pcf_flags(LSPLIT, start->GetFlags());
+ LOG_FMT(LSPLIT, " parent type %s, (PCF_IN_FCN_DEF %s), (PCF_IN_FCN_CALL %s)\n",
+ get_token_name(start->GetParentType()),
+ start->TestFlags((PCF_IN_FCN_DEF)) ? "TRUE" : "FALSE",
+ start->TestFlags((PCF_IN_FCN_CALL)) ? "TRUE" : "FALSE");
+
+ // break at maximum line length if ls_code_width is true
+ // Issue #2432
+ if (start->TestFlags(PCF_ONE_LINER))
+ {
+ LOG_FMT(LSPLIT, "%s(%d): ** ONE LINER SPLIT **\n", __func__, __LINE__);
+ undo_one_liner(start);
+ newlines_cleanup_braces(false);
+ // Issue #1352
+ cpd.changes++;
+ return(false);
+ }
+
+ if (options::ls_code_width())
+ {
+ log_rule_B("ls_code_width");
+ }
+ else if (start->TestFlags(PCF_IN_FOR))
+ {
+ // Check to see if we are in a for statement
+ 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__);
+ }
+ else if ( start->TestFlags(PCF_IN_FCN_DEF)
+ || start->TestFlags(PCF_IN_FCN_CALL)
+ || start->GetParentType() == CT_FUNC_PROTO) // Issue #1169
+ {
+ /*
+ * If this is in a function call or prototype, split on commas or right
+ * after the open parenthesis
+ */
+ LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n");
+
+ if (options::ls_func_split_full())
+ {
+ log_rule_B("ls_func_split_full");
+
+ split_fcn_params_full(start);
+
+ if (!is_past_width(start))
+ {
+ return(true);
+ }
+ }
+ }
+ else if (start->TestFlags(PCF_IN_TEMPLATE))
+ {
+ /*
+ * If this is in a template, split on commas, Issue #1170
+ */
+ LOG_FMT(LSPLIT, " ** TEMPLATE SPLIT **\n");
+ split_template(start);
+ return(true);
+ }
+ // Try to find the best spot to split the line
+ LOG_FMT(LSPLIT, "%s(%d): try to find a split point\n", __func__, __LINE__);
+ SplitEntry ent;
+ ent.pc = Chunk::NullChunkPtr;
+ ent.pri = CT_UNKNOWN;
+
+ Chunk *pc = start->GetPrev();
+ Chunk *prev;
+
+ while ( pc->IsNotNullChunk()
+ && !pc->IsNewline())
+ {
+ LOG_FMT(LSPLIT, "%s(%d): text '%s', orig line is %zu, orig col is %zu\n",
+ __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol());
+
+ if (pc->IsNot(CT_SPACE))
+ {
+ try_split_here(ent, pc);
+
+ // break at maximum line length
+ if ( ent.pc->IsNotNullChunk()
+ && options::ls_code_width())
+ {
+ log_rule_B("ls_code_width");
+ LOG_FMT(LSPLIT, "%s(%d): found split\n", __func__, __LINE__);
+ break;
+ }
+ }
+ pc = pc->GetPrev();
+ }
+
+ if (ent.pc->IsNullChunk())
+ {
+ LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded NO SOLUTION for orig line %zu at '%s' [%s]\n",
+ __func__, __LINE__, start->GetOrigLine(), start->Text(), get_token_name(start->GetType()));
+ }
+ 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->GetType()), ent.pc->GetOrigLine());
+ LOG_FMT(LSPLIT, "%s(%d): ent at '%s', orig col is %zu\n",
+ __func__, __LINE__, ent.pc->Text(), ent.pc->GetOrigCol());
+ }
+
+ // Break before the token instead of after it according to the pos_xxx rules
+ if (ent.pc->IsNullChunk())
+ {
+ pc = Chunk::NullChunkPtr;
+ }
+ 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 ( ( ent.pc->Is(CT_SHIFT)
+ && (options::pos_shift() & TP_LEAD))
+ || ( ( ent.pc->Is(CT_ARITH)
+ || ent.pc->Is(CT_CARET))
+ && (options::pos_arith() & TP_LEAD))
+ || ( ent.pc->Is(CT_ASSIGN)
+ && (options::pos_assign() & TP_LEAD))
+ || ( ent.pc->Is(CT_COMPARE)
+ && (options::pos_compare() & TP_LEAD))
+ || ( ( ent.pc->Is(CT_COND_COLON)
+ || ent.pc->Is(CT_QUESTION))
+ && (options::pos_conditional() & TP_LEAD))
+ || ( ent.pc->Is(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->GetOrigCol());
+ }
+ bool move_forward = false;
+
+ if (pc->IsNullChunk())
+ {
+ pc = start;
+ Chunk *next = pc->GetNext();
+
+ // On comma, close parenthesis/bracket/braces or semicolon, empty
+ // parenthesis/brackets/braces pairs, skip after them since they
+ // are small chunks and the split looks much better.
+ if ( pc->Is(CT_COMMA)
+ || pc->IsSemicolon()
+ || pc->IsParenClose()
+ || pc->IsBraceClose()
+ || pc->Is(CT_ANGLE_CLOSE)
+ || pc->Is(CT_SQUARE_CLOSE)
+ || ( pc->IsParenOpen()
+ && next->IsParenClose())
+ || ( pc->IsBraceOpen()
+ && next->IsBraceClose())
+ || ( pc->Is(CT_SQUARE_OPEN)
+ && next->Is(CT_SQUARE_CLOSE))
+ || pc->Len() == 0)
+ {
+ LOG_FMT(LSPLIT, "Move forward past the chuck");
+ move_forward = true;
+ }
+ }
+ // Add a newline before 'pc', if possible.
+ // If 'pc' is the first chunk in the line, split after it since it is
+ // already past the allowed code width. If the next chunk is a comma, close
+ // parenthesis/bracket/braces or semicolon, skip after them since they
+ // are small chunks and the split looks much better. Also skip over
+ // empty parenthesis/brackets/braces pairs.
+ prev = pc->GetPrev();
+
+ if ( prev->IsNullChunk()
+ || pc->IsNewline()
+ || prev->IsNewline()
+ || move_forward)
+ {
+ pc = pc->GetNext();
+ Chunk *next = pc->GetNext();
+
+ while ( pc->Is(CT_COMMA)
+ || pc->IsSemicolon()
+ || pc->IsParenClose()
+ || pc->IsBraceClose()
+ || pc->Is(CT_ANGLE_CLOSE)
+ || pc->Is(CT_SQUARE_CLOSE)
+ || ( pc->IsParenOpen()
+ && next->IsParenClose())
+ || ( pc->IsBraceOpen()
+ && next->IsBraceClose())
+ || ( pc->Is(CT_SQUARE_OPEN)
+ && next->Is(CT_SQUARE_CLOSE)))
+ {
+ pc = next;
+ next = pc->GetNext();
+ }
+ }
+ prev = pc->GetPrev();
+
+ if ( prev->IsNotNullChunk()
+ && !pc->IsNewline()
+ && !prev->IsNewline())
+ {
+ //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->GetType()),
+ // slen, start->Text(), get_token_name(start->GetType()));
+ LOG_FMT(LSPLIT, "%s(%d): Text() '%s', type %s, started on token '%s', type %s\n",
+ __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()),
+ start->Text(), get_token_name(start->GetType()));
+
+ 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 = Chunk::NullChunkPtr;
+ size_t nl_cnt = 0;
+
+ LOG_FMT(LSPLIT, "%s: starting on %s, line %zu\n",
+ __func__, start->Text(), start->GetOrigLine());
+
+ // Find the open paren so we know the level and count newlines
+ Chunk *pc = start;
+
+ while ((pc = pc->GetPrev())->IsNotNullChunk())
+ {
+ if (pc->Is(CT_SPAREN_OPEN))
+ {
+ open_paren = pc;
+ break;
+ }
+
+ if (pc->GetNlCount() > 0)
+ {
+ nl_cnt += pc->GetNlCount();
+ }
+ }
+
+ if (open_paren->IsNullChunk())
+ {
+ LOG_FMT(LSPLIT, "No open paren\n");
+ return;
+ }
+ // see if we started on the semicolon
+ int count = 0;
+ Chunk *st[2];
+
+ pc = start;
+
+ if ( pc->Is(CT_SEMICOLON)
+ && pc->GetParentType() == CT_FOR)
+ {
+ st[count++] = pc;
+ }
+
+ // first scan backwards for the semicolons
+ while ( (count < static_cast<int>(max_cnt))
+ && ((pc = pc->GetPrev())->IsNotNullChunk())
+ && pc->IsNotNullChunk()
+ && pc->TestFlags(PCF_IN_SPAREN))
+ {
+ if ( pc->Is(CT_SEMICOLON)
+ && pc->GetParentType() == CT_FOR)
+ {
+ st[count++] = pc;
+ }
+ }
+ // And now scan forward
+ pc = start;
+
+ while ( (count < static_cast<int>(max_cnt))
+ && ((pc = pc->GetNext())->IsNotNullChunk())
+ && pc->TestFlags(PCF_IN_SPAREN))
+ {
+ if ( pc->Is(CT_SEMICOLON)
+ && pc->GetParentType() == 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 parentheses level
+ pc = open_paren;
+
+ while ((pc = pc->GetNext()) != start)
+ {
+ if ( pc->Is(CT_COMMA)
+ && (pc->GetLevel() == (open_paren->GetLevel() + 1)))
+ {
+ split_before_chunk(pc->GetNext());
+
+ if (!is_past_width(pc))
+ {
+ return;
+ }
+ }
+ }
+ // Still past width, check for a assignments at parentheses level
+ pc = open_paren;
+
+ while ((pc = pc->GetNext()) != start)
+ {
+ if ( pc->Is(CT_ASSIGN)
+ && (pc->GetLevel() == (open_paren->GetLevel() + 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): start at '%s'\n", __func__, __LINE__, start->Text());
+
+ // Find the opening function parenthesis
+ Chunk *fpo = start;
+
+ LOG_FMT(LSPLIT, " %s(%d): search for opening function parenthesis\n", __func__, __LINE__);
+
+ while ((fpo = fpo->GetPrev())->IsNotNullChunk())
+ {
+ LOG_FMT(LSPLIT, " %s(%d): %s, orig col is %zu, level is %zu\n",
+ __func__, __LINE__, fpo->Text(), fpo->GetOrigCol(), fpo->GetLevel());
+
+ if ( fpo->Is(CT_FPAREN_OPEN)
+ && (fpo->GetLevel() == start->GetLevel() - 1))
+ {
+ LOG_FMT(LSPLIT, " %s(%d): found open paren\n", __func__, __LINE__);
+ break; // opening parenthesis found. Issue #1020
+ }
+ }
+ // Now break after every comma
+ Chunk *pc = fpo->GetNextNcNnl();
+
+ while (pc->IsNotNullChunk())
+ {
+ if (pc->GetLevel() <= fpo->GetLevel())
+ {
+ break;
+ }
+
+ if ( (pc->GetLevel() == (fpo->GetLevel() + 1))
+ && pc->Is(CT_COMMA))
+ {
+ split_before_chunk(pc->GetNext());
+ }
+ pc = pc->GetNextNcNnl();
+ }
+}
+
+
+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 ( prev->IsNewline()
+ || prev->Is(CT_COMMA))
+ {
+ break;
+ }
+ }
+
+ if ( prev->IsNotNullChunk()
+ && !prev->IsNewline())
+ {
+ LOG_FMT(LSPLIT, " %s(%d):", __func__, __LINE__);
+ LOG_FMT(LSPLIT, " -- ended on %s --\n", get_token_name(prev->GetType()));
+ 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