You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
757 lines
20 KiB
757 lines
20 KiB
/**
|
|
* @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;
|
|
|
|
LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, curr col %zu, text %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), currCol, pc->Text());
|
|
return(currCol > 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());
|
|
|
|
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)
|
|
{
|
|
LOG_FMT(LSPLIT, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LSPLIT, "%s(%d): Bailed! orig line is %zu, orig col is %zu, Text() '%s'\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, " start->GetFlags() ");
|
|
log_pcf_flags(LSPLIT, start->GetFlags());
|
|
LOG_FMT(LSPLIT, " start->GetParentType() %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);
|
|
}
|
|
LOG_FMT(LSPLIT, "%s(%d): before ls_code_width\n", __func__, __LINE__);
|
|
|
|
if (options::ls_code_width())
|
|
{
|
|
log_rule_B("ls_code_width");
|
|
}
|
|
// Check to see if we are in a for statement
|
|
else if (start->TestFlags(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->TestFlags(PCF_IN_FCN_DEF)
|
|
|| start->TestFlags(PCF_IN_FCN_CALL)
|
|
|| start->GetParentType() == CT_FUNC_PROTO) // Issue #1169
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If this is in a template, split on commas, Issue #1170
|
|
*/
|
|
else if (start->TestFlags(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
|
|
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());
|
|
}
|
|
|
|
if (pc->IsNullChunk())
|
|
{
|
|
pc = start;
|
|
|
|
// Don't break before a close, comma, or colon
|
|
if ( start->Is(CT_PAREN_CLOSE)
|
|
|| start->Is(CT_PAREN_OPEN)
|
|
|| start->Is(CT_FPAREN_CLOSE)
|
|
|| start->Is(CT_FPAREN_OPEN)
|
|
|| start->Is(CT_SPAREN_CLOSE)
|
|
|| start->Is(CT_SPAREN_OPEN)
|
|
|| start->Is(CT_ANGLE_CLOSE)
|
|
|| start->Is(CT_BRACE_CLOSE)
|
|
|| start->Is(CT_COMMA)
|
|
|| start->IsSemicolon()
|
|
|| 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->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
|