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.
4793 lines
179 KiB
4793 lines
179 KiB
/**
|
|
* @file indent.cpp
|
|
* Does all the indenting stuff.
|
|
*
|
|
* @author Ben Gardner
|
|
* @author Guy Maurel October 2015- 2021
|
|
* @license GPL v2+
|
|
*/
|
|
|
|
#include "indent.h"
|
|
|
|
#include "align.h"
|
|
#include "options.h"
|
|
#include "options_for_QT.h"
|
|
#include "parsing_frame_stack.h"
|
|
#include "prototypes.h"
|
|
#include "quick_align_again.h"
|
|
#include "space.h"
|
|
#include <cstdint>
|
|
|
|
#ifdef WIN32
|
|
#include <algorithm> // to get max
|
|
#endif // ifdef WIN32
|
|
|
|
#ifdef IGNORE // WinBase.h
|
|
#undef IGNORE
|
|
#endif
|
|
|
|
|
|
constexpr static auto LCURRENT = LINDENT;
|
|
|
|
using namespace std;
|
|
using namespace uncrustify;
|
|
|
|
|
|
/**
|
|
* General indenting approach:
|
|
* Indenting levels are put into a stack.
|
|
*
|
|
* The stack entries contain:
|
|
* - opening type
|
|
* - brace column
|
|
* - continuation column
|
|
*
|
|
* Items that start a new stack item:
|
|
* - preprocessor (new parse frame)
|
|
* - Brace Open (Virtual brace also)
|
|
* - Paren, Square, Angle open
|
|
* - Assignments
|
|
* - C++ '<<' operator (ie, cout << "blah")
|
|
* - case
|
|
* - class colon
|
|
* - return
|
|
* - types
|
|
* - any other continued statement
|
|
*
|
|
* Note that the column of items marked 'PCF_WAS_ALIGNED' is not changed.
|
|
*
|
|
* For an open brace:
|
|
* - indent increases by indent_columns
|
|
* - if part of if/else/do/while/switch/etc, an extra indent may be applied
|
|
* - if in a paren, then cont-col is set to column + 1, ie "({ some code })"
|
|
*
|
|
* Open paren/square/angle:
|
|
* cont-col is set to the column of the item after the open paren, unless
|
|
* followed by a newline, then it is set to (brace-col + indent_columns).
|
|
* Examples:
|
|
* a_really_long_function_name(
|
|
* param1, param2);
|
|
* a_really_long_function_name(param1,
|
|
* param2);
|
|
*
|
|
* Assignments:
|
|
* Assignments are continued aligned with the first item after the assignment,
|
|
* unless the assign is followed by a newline.
|
|
* Examples:
|
|
* some.variable = asdf + asdf +
|
|
* asdf;
|
|
* some.variable =
|
|
* asdf + asdf + asdf;
|
|
*
|
|
* C++ << operator:
|
|
* Handled the same as assignment.
|
|
* Examples:
|
|
* cout << "this is test number: "
|
|
* << test_number;
|
|
*
|
|
* case:
|
|
* Started with case or default.
|
|
* Terminated with close brace at level or another case or default.
|
|
* Special indenting according to various rules.
|
|
* - indent of case label
|
|
* - indent of case body
|
|
* - how to handle optional braces
|
|
* Examples:
|
|
* {
|
|
* case x: {
|
|
* a++;
|
|
* break;
|
|
* }
|
|
* case y:
|
|
* b--;
|
|
* break;
|
|
* default:
|
|
* c++;
|
|
* break;
|
|
* }
|
|
*
|
|
* Class colon:
|
|
* Indent continuation by indent_columns:
|
|
* class my_class :
|
|
* baseclass1,
|
|
* baseclass2
|
|
* {
|
|
*
|
|
* Return: same as assignments
|
|
* If the return statement is not fully paren'd, then the indent continues at
|
|
* the column of the item after the return. If it is paren'd, then the paren
|
|
* rules apply.
|
|
* return somevalue +
|
|
* othervalue;
|
|
*
|
|
* Type: pretty much the same as assignments
|
|
* Examples:
|
|
* int foo,
|
|
* bar,
|
|
* baz;
|
|
*
|
|
* Any other continued item:
|
|
* There shouldn't be anything not covered by the above cases, but any other
|
|
* continued item is indented by indent_columns:
|
|
* Example:
|
|
* somereallycrazylongname.with[lotsoflongstuff].
|
|
* thatreallyannoysme.whenIhavetomaintain[thecode] = 3;
|
|
*/
|
|
|
|
/**
|
|
* REVISIT: This needs to be re-checked, maybe cleaned up
|
|
*
|
|
* Indents comments in a (hopefully) smart manner.
|
|
*
|
|
* There are two type of comments that get indented:
|
|
* - stand alone (ie, no tokens on the line before the comment)
|
|
* - trailing comments (last token on the line apart from a linefeed)
|
|
* + note that a stand-alone comment is a special case of a trailing
|
|
*
|
|
* The stand alone comments will get indented in one of three ways:
|
|
* - column 1:
|
|
* + There is an empty line before the comment AND the indent level is 0
|
|
* + The comment was originally in column 1
|
|
*
|
|
* - Same column as trailing comment on previous line (ie, aligned)
|
|
* + if originally within TBD (3) columns of the previous comment
|
|
*
|
|
* - syntax indent level
|
|
* + doesn't fit in the previous categories
|
|
*
|
|
* Options modify this behavior:
|
|
* - keep original column (don't move the comment, if possible)
|
|
* - keep relative column (move out the same amount as first item on line)
|
|
* - fix trailing comment in column TBD
|
|
*
|
|
* @param pc The comment, which is the first item on a line
|
|
* @param col The column if this is to be put at indent level
|
|
*/
|
|
static void indent_comment(Chunk *pc, size_t col);
|
|
|
|
|
|
static size_t token_indent(E_Token type);
|
|
|
|
|
|
static size_t calc_indent_continue(const ParsingFrame &frm, size_t pse_tos);
|
|
|
|
/**
|
|
* Get candidate chunk first on line to which OC blocks can be indented against.
|
|
*/
|
|
static Chunk *candidate_chunk_first_on_line(Chunk *pc);
|
|
|
|
/**
|
|
* We are on a '{' that has parent = OC_BLOCK_EXPR
|
|
* find the column of the param tag
|
|
*/
|
|
static Chunk *oc_msg_block_indent(Chunk *pc, bool from_brace, bool from_caret, bool from_colon, bool from_keyword);
|
|
|
|
|
|
/**
|
|
* returns true if forward or reverse scan reveals only single newlines or comments
|
|
* stops when hits code
|
|
* false if next thing hit is a closing brace, also if 2 newlines in a row
|
|
*/
|
|
static bool single_line_comment_indent_rule_applies(Chunk *start, bool forward);
|
|
|
|
/**
|
|
* returns true if semicolon on the same level ends any assign operations
|
|
* false if next thing hit is not the end of an assign operation
|
|
*/
|
|
static bool is_end_of_assignment(Chunk *pc, const ParsingFrame &frm);
|
|
|
|
|
|
void indent_to_column(Chunk *pc, size_t column)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
if (column < pc->GetColumn())
|
|
{
|
|
column = pc->GetColumn();
|
|
}
|
|
reindent_line(pc, column);
|
|
}
|
|
|
|
|
|
enum class align_mode_e : unsigned int
|
|
{
|
|
SHIFT, //! shift relative to the current column
|
|
KEEP_ABS, //! try to keep the original absolute column
|
|
KEEP_REL, //! try to keep the original gap
|
|
};
|
|
|
|
|
|
enum class indent_mode_e : int
|
|
{
|
|
INDENT = 0, //! indent by one level
|
|
ALIGN = 1, //! align under the open brace/parenthesis
|
|
IGNORE = -1, //! preserve original indentation
|
|
};
|
|
|
|
|
|
void align_to_column(Chunk *pc, size_t column)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
if ( pc->IsNullChunk()
|
|
|| column == pc->GetColumn())
|
|
{
|
|
return;
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s => column is %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->Text(),
|
|
get_token_name(pc->GetType()), column);
|
|
|
|
const int col_delta = column - pc->GetColumn();
|
|
size_t min_col = column;
|
|
|
|
pc->SetColumn(column);
|
|
|
|
do
|
|
{
|
|
auto *next = pc->GetNext();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
const size_t min_delta = space_col_align(pc, next);
|
|
min_col += min_delta;
|
|
|
|
const auto *prev = pc;
|
|
pc = next;
|
|
|
|
auto almod = align_mode_e::SHIFT;
|
|
|
|
if ( pc->IsComment()
|
|
&& pc->GetParentType() != CT_COMMENT_EMBED)
|
|
{
|
|
log_rule_B("indent_relative_single_line_comments");
|
|
almod = ( pc->IsSingleLineComment()
|
|
&& options::indent_relative_single_line_comments())
|
|
? align_mode_e::KEEP_REL : align_mode_e::KEEP_ABS;
|
|
}
|
|
|
|
if (almod == align_mode_e::KEEP_ABS)
|
|
{
|
|
// Keep same absolute column
|
|
pc->SetColumn(max(pc->GetOrigCol(), min_col));
|
|
}
|
|
else if (almod == align_mode_e::KEEP_REL)
|
|
{
|
|
// Keep same relative column
|
|
size_t orig_delta = pc->GetOrigPrevSp() + prev->Len();
|
|
orig_delta = max<size_t>(orig_delta, min_delta); // keeps orig_delta positive
|
|
|
|
pc->SetColumn(prev->GetColumn() + orig_delta);
|
|
}
|
|
else // SHIFT
|
|
{
|
|
// Shift by the same amount, keep above negative values
|
|
pc->SetColumn(( col_delta >= 0
|
|
|| (size_t)(abs(col_delta)) < pc->GetColumn())
|
|
? pc->GetColumn() + col_delta : 0);
|
|
pc->SetColumn(max(pc->GetColumn(), min_col));
|
|
}
|
|
LOG_FMT(LINDLINED, "%s(%d): %s set column of '%s', type is %s, orig line is %zu, to col %zu (orig col was %zu)\n",
|
|
__func__, __LINE__,
|
|
(almod == align_mode_e::KEEP_ABS) ? "abs" :
|
|
(almod == align_mode_e::KEEP_REL) ? "rel" : "sft",
|
|
pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetColumn(), pc->GetOrigCol());
|
|
} while ( pc->IsNotNullChunk()
|
|
&& pc->GetNlCount() == 0);
|
|
} // align_to_column
|
|
|
|
|
|
void reindent_line(Chunk *pc, size_t column)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
char copy[1000];
|
|
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, on '%s' [%s/%s] => %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy),
|
|
get_token_name(pc->GetType()), get_token_name(pc->GetParentType()),
|
|
column);
|
|
log_func_stack_inline(LINDLINE);
|
|
|
|
if (column == pc->GetColumn())
|
|
{
|
|
return;
|
|
}
|
|
int col_delta = column - pc->GetColumn();
|
|
size_t min_col = column;
|
|
|
|
pc->SetColumn(column);
|
|
|
|
do
|
|
{
|
|
if (QT_SIGNAL_SLOT_found)
|
|
{
|
|
// fix the bug #654
|
|
// connect(&mapper, SIGNAL(mapped(QString &)), this, SLOT(onSomeEvent(QString &)));
|
|
// look for end of SIGNAL/SLOT block
|
|
if (!pc->TestFlags(PCF_IN_QT_MACRO))
|
|
{
|
|
LOG_FMT(LINDLINE, "FLAGS is NOT set: PCF_IN_QT_MACRO\n");
|
|
restore_options_for_QT();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// look for begin of SIGNAL/SLOT block
|
|
if (pc->TestFlags(PCF_IN_QT_MACRO))
|
|
{
|
|
LOG_FMT(LINDLINE, "FLAGS is set: PCF_IN_QT_MACRO\n");
|
|
save_set_options_for_QT(pc->GetLevel());
|
|
}
|
|
}
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pc->GetNlCount())
|
|
{
|
|
min_col = 0;
|
|
col_delta = 0;
|
|
}
|
|
min_col += space_col_align(pc, next);
|
|
pc = next;
|
|
|
|
const bool is_comment = pc->IsComment();
|
|
log_rule_B("indent_relative_single_line_comments");
|
|
const bool keep = ( is_comment
|
|
&& pc->IsSingleLineComment()
|
|
&& options::indent_relative_single_line_comments());
|
|
|
|
if ( is_comment
|
|
&& pc->GetParentType() != CT_COMMENT_EMBED
|
|
&& !keep)
|
|
{
|
|
pc->SetColumn(max(pc->GetOrigCol(), min_col));
|
|
LOG_FMT(LINDLINE, "%s(%d): set comment on line %zu to col %zu (orig %zu)\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->GetOrigCol());
|
|
}
|
|
else
|
|
{
|
|
pc->SetColumn(max(pc->GetColumn() + col_delta, min_col));
|
|
|
|
LOG_FMT(LINDLINED, "%s(%d): set column of ", __func__, __LINE__);
|
|
|
|
if (pc->Is(CT_NEWLINE))
|
|
{
|
|
LOG_FMT(LINDLINED, "<Newline>");
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LINDLINED, "'%s'", pc->Text());
|
|
}
|
|
LOG_FMT(LINDLINED, " to %zu (orig %zu/%zu)\n", pc->GetColumn(), pc->GetOrigLine(), pc->GetOrigCol());
|
|
}
|
|
} while ( pc->IsNotNullChunk()
|
|
&& pc->GetNlCount() == 0);
|
|
} // reindent_line
|
|
|
|
|
|
static size_t token_indent(E_Token type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case CT_IF:
|
|
case CT_DO:
|
|
return(3);
|
|
|
|
case CT_FOR:
|
|
case CT_ELSE: // wacky, but that's what is wanted
|
|
return(4);
|
|
|
|
case CT_WHILE:
|
|
case CT_USING_STMT:
|
|
return(6);
|
|
|
|
case CT_SWITCH:
|
|
return(7);
|
|
|
|
case CT_ELSEIF:
|
|
return(8);
|
|
|
|
case CT_SYNCHRONIZED:
|
|
return(13);
|
|
|
|
default:
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
#define indent_column_set(X) \
|
|
do { \
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, indent_column changed from %zu to %zu\n", \
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, (size_t)X); \
|
|
indent_column = (X); \
|
|
} while (false)
|
|
|
|
|
|
static size_t get_indent_first_continue(Chunk *pc)
|
|
{
|
|
log_rule_B("indent_ignore_first_continue");
|
|
Chunk *continuation = pc->GetNextType(CT_NEWLINE, pc->GetLevel());
|
|
|
|
if (continuation->IsNotNullChunk())
|
|
{
|
|
continuation = continuation->GetNext();
|
|
|
|
if (continuation->IsNotNullChunk())
|
|
{
|
|
return(continuation->GetOrigCol());
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
static size_t calc_indent_continue(const ParsingFrame &frm, size_t pse_tos)
|
|
{
|
|
log_rule_B("indent_continue");
|
|
const int ic = options::indent_continue();
|
|
|
|
if ( ic < 0
|
|
&& frm.at(pse_tos).GetIndentContinue())
|
|
{
|
|
return(frm.at(pse_tos).GetIndent());
|
|
}
|
|
return(frm.at(pse_tos).GetIndent() + abs(ic));
|
|
}
|
|
|
|
|
|
static size_t calc_indent_continue(const ParsingFrame &frm)
|
|
{
|
|
return(calc_indent_continue(frm, frm.size() - 1));
|
|
}
|
|
|
|
|
|
static Chunk *candidate_chunk_first_on_line(Chunk *pc)
|
|
{
|
|
Chunk *first = pc->GetFirstChunkOnLine();
|
|
|
|
log_rule_B("indent_inside_ternary_operator");
|
|
|
|
if ( options::indent_inside_ternary_operator()
|
|
&& ( first->Is(CT_QUESTION)
|
|
|| first->Is(CT_COND_COLON)))
|
|
{
|
|
return(first->GetNextNcNnl());
|
|
}
|
|
else
|
|
{
|
|
return(first);
|
|
}
|
|
}
|
|
|
|
|
|
static Chunk *oc_msg_block_indent(Chunk *pc, bool from_brace,
|
|
bool from_caret, bool from_colon,
|
|
bool from_keyword)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
Chunk *tmp = pc->GetPrevNc();
|
|
|
|
if (from_brace)
|
|
{
|
|
return(pc);
|
|
}
|
|
|
|
// Skip to open paren in ':^TYPE *(ARGS) {'
|
|
if (tmp->IsParenClose())
|
|
{
|
|
tmp = tmp->GetOpeningParen()->GetPrevNc();
|
|
}
|
|
|
|
// // Check for star in ':^TYPE *(ARGS) {'. Issue 2477
|
|
if (tmp->Is(CT_PTR_TYPE))
|
|
{
|
|
tmp = tmp->GetPrevNc();
|
|
}
|
|
|
|
// Check for type in ':^TYPE *(ARGS) {'. Issue 2482
|
|
if (tmp->Is(CT_TYPE))
|
|
{
|
|
tmp = tmp->GetPrevNc();
|
|
}
|
|
// Check for caret in ':^TYPE *(ARGS) {'
|
|
// Store the caret position
|
|
Chunk *caret_tmp = Chunk::NullChunkPtr;
|
|
|
|
if ( tmp->IsNotNullChunk()
|
|
&& tmp->GetType() == CT_OC_BLOCK_CARET)
|
|
{
|
|
caret_tmp = tmp;
|
|
}
|
|
else
|
|
{
|
|
caret_tmp = tmp->GetPrevType(CT_OC_BLOCK_CARET);
|
|
tmp = caret_tmp;
|
|
}
|
|
|
|
// If we still cannot find caret then return first chunk on the line
|
|
if ( tmp->IsNullChunk()
|
|
|| tmp->IsNot(CT_OC_BLOCK_CARET))
|
|
{
|
|
return(candidate_chunk_first_on_line(pc));
|
|
}
|
|
|
|
if (from_caret)
|
|
{
|
|
return(tmp);
|
|
}
|
|
tmp = tmp->GetPrevNc();
|
|
|
|
// Check for colon in ':^TYPE *(ARGS) {'
|
|
if (from_colon)
|
|
{
|
|
if ( tmp->IsNullChunk()
|
|
|| tmp->IsNot(CT_OC_COLON))
|
|
{
|
|
return(candidate_chunk_first_on_line(pc));
|
|
}
|
|
else
|
|
{
|
|
return(tmp);
|
|
}
|
|
}
|
|
tmp = tmp->GetPrevNc();
|
|
|
|
if (from_keyword)
|
|
{
|
|
if ( tmp->IsNullChunk()
|
|
|| ( tmp->IsNot(CT_OC_MSG_NAME)
|
|
&& tmp->IsNot(CT_OC_MSG_FUNC)))
|
|
{
|
|
return(candidate_chunk_first_on_line(pc));
|
|
}
|
|
else
|
|
{
|
|
return(tmp);
|
|
}
|
|
}
|
|
// In almost all the cases, its better to return the first chunk on the line than not indenting at all.
|
|
tmp = candidate_chunk_first_on_line(pc);
|
|
return(tmp);
|
|
} // oc_msg_block_indent
|
|
|
|
|
|
#define log_indent() \
|
|
do { _log_indent(__func__, __LINE__, frm); \
|
|
} while (false)
|
|
|
|
|
|
static void _log_indent(const char *func, const uint32_t line, const ParsingFrame &frm)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, ...indent is %zu\n",
|
|
func, line, frm.size() - 1, frm.top().GetIndent());
|
|
}
|
|
|
|
|
|
#define log_prev_indent() \
|
|
do { _log_prev_indent(__func__, __LINE__, frm); \
|
|
} while (false)
|
|
|
|
|
|
static void _log_prev_indent(const char *func, const uint32_t line, const ParsingFrame &frm)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, prev....indent is %zu\n",
|
|
func, line, frm.size() - 1, frm.prev().GetIndent());
|
|
}
|
|
|
|
|
|
#define log_indent_tmp() \
|
|
do { _log_indent_tmp(__func__, __LINE__, frm); \
|
|
} while (false)
|
|
|
|
|
|
static void _log_indent_tmp(const char *func, const uint32_t line, const ParsingFrame &frm)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, ...indent_tmp is %zu\n",
|
|
func, line, frm.size() - 1, frm.top().GetIndentTmp());
|
|
}
|
|
|
|
|
|
static void quick_indent_again()
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext())
|
|
{
|
|
if (pc->GetIndentData().ref == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
Chunk *tmp = pc->GetPrev();
|
|
|
|
if (!tmp->IsNewline())
|
|
{
|
|
continue;
|
|
}
|
|
const size_t col = pc->GetIndentData().ref->GetColumn() + pc->GetIndentData().delta;
|
|
indent_to_column(pc, col);
|
|
|
|
LOG_FMT(LINDENTAG, "%s(%d): [%zu] indent [%s] to %zu based on [%s] @ %zu:%zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->Text(), col,
|
|
pc->GetIndentData().ref->Text(), pc->GetIndentData().ref->GetOrigLine(),
|
|
pc->GetIndentData().ref->GetColumn());
|
|
}
|
|
}
|
|
|
|
|
|
void indent_text()
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
bool did_newline = true;
|
|
size_t vardefcol = 0;
|
|
|
|
log_rule_B("indent_columns");
|
|
const size_t indent_size = options::indent_columns();
|
|
size_t indent_column = 0;
|
|
int xml_indent = 0;
|
|
size_t sql_col = 0;
|
|
size_t sql_orig_col = 0;
|
|
bool in_func_def = false;
|
|
|
|
|
|
ParsingFrameStack frames;
|
|
ParsingFrame frm;
|
|
|
|
|
|
Chunk *pc = Chunk::GetHead();
|
|
bool classFound = false; // Issue #672
|
|
|
|
while (pc->IsNotNullChunk())
|
|
{
|
|
LOG_CHUNK(LINDLINE, pc);
|
|
|
|
// Mark continuation lines if absolute indentation is requested
|
|
if ( options::indent_continue() < 0
|
|
&& ( pc->Is(CT_PAREN_OPEN)
|
|
|| pc->Is(CT_LPAREN_OPEN)
|
|
|| pc->Is(CT_SPAREN_OPEN)
|
|
|| pc->Is(CT_FPAREN_OPEN)
|
|
|| pc->Is(CT_RPAREN_OPEN)
|
|
|| pc->Is(CT_SQUARE_OPEN)
|
|
|| pc->Is(CT_ANGLE_OPEN)))
|
|
{
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if (next->IsNewline())
|
|
{
|
|
while (next->IsNewline())
|
|
{
|
|
next = next->GetNext();
|
|
}
|
|
|
|
if ( next->IsNotNullChunk()
|
|
&& !next->IsPreproc())
|
|
{
|
|
// Mark chunk as continuation line, so indentation can be
|
|
// correctly set over multiple passes
|
|
next->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).
|
|
LOG_FMT(LSPLIT, "%s(%d): set PCF_LINE_CONT for pc text '%s', orig line is %zu, orig col is %zu\n",
|
|
__func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol());
|
|
|
|
pc->SetFlagBits(PCF_CONT_LINE);
|
|
Chunk *closing_paren = pc->GetClosingParen();
|
|
|
|
if (closing_paren->IsNotNullChunk())
|
|
{
|
|
closing_paren->SetFlagBits(PCF_CONT_LINE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// forces string literal to column-1 [Fix for 1246]
|
|
log_rule_B("indent_col1_multi_string_literal");
|
|
|
|
if ( (pc->GetType() == CT_STRING_MULTI)
|
|
&& !(cpd.lang_flags & LANG_OC) // Issue #1795
|
|
&& options::indent_col1_multi_string_literal())
|
|
{
|
|
string str = pc->Text();
|
|
|
|
if ( (str[0] == '@')
|
|
&& (pc->GetPrev()->GetType() == CT_NEWLINE))
|
|
{
|
|
indent_column_set(1);
|
|
reindent_line(pc, indent_column);
|
|
pc = pc->GetNext();
|
|
did_newline = false;
|
|
}
|
|
}
|
|
|
|
if (pc->Is(CT_NEWLINE))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, <Newline>\n",
|
|
__func__, __LINE__, pc->GetOrigLine());
|
|
}
|
|
else if (pc->Is(CT_NL_CONT))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, CT_NL_CONT\n",
|
|
__func__, __LINE__, pc->GetOrigLine());
|
|
}
|
|
else
|
|
{
|
|
char copy[1000];
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, column is %zu, for '%s'\n ",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn(), pc->ElidedText(copy));
|
|
log_pcf_flags(LINDLINE, pc->GetFlags());
|
|
}
|
|
log_rule_B("use_options_overriding_for_qt_macros");
|
|
|
|
if ( options::use_options_overriding_for_qt_macros()
|
|
&& ( strcmp(pc->Text(), "SIGNAL") == 0
|
|
|| strcmp(pc->Text(), "SLOT") == 0))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line=%zu: type %s SIGNAL/SLOT found\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetType()));
|
|
}
|
|
// Handle preprocessor transitions
|
|
log_rule_B("indent_brace_parent");
|
|
const size_t parent_token_indent = (options::indent_brace_parent())
|
|
? token_indent(pc->GetParentType()) : 0;
|
|
|
|
// Handle "force indentation of function definition to start in column 1"
|
|
log_rule_B("indent_func_def_force_col1");
|
|
|
|
if (options::indent_func_def_force_col1())
|
|
{
|
|
if (!in_func_def)
|
|
{
|
|
Chunk *next = pc->GetNextNcNnl();
|
|
|
|
if ( pc->GetParentType() == CT_FUNC_DEF
|
|
|| ( pc->Is(CT_COMMENT)
|
|
&& next->IsNotNullChunk()
|
|
&& next->GetParentType() == CT_FUNC_DEF))
|
|
{
|
|
in_func_def = true;
|
|
frm.push(pc, __func__, __LINE__);
|
|
frm.top().SetIndentTmp(1);
|
|
frm.top().SetIndent(1);
|
|
frm.top().SetIndentTab(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Chunk *prev = pc->GetPrev();
|
|
|
|
if ( prev->Is(CT_BRACE_CLOSE)
|
|
&& prev->GetParentType() == CT_FUNC_DEF)
|
|
{
|
|
in_func_def = false;
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
}
|
|
}
|
|
// Clean up after a #define, etc
|
|
const bool in_preproc = pc->TestFlags(PCF_IN_PREPROC);
|
|
|
|
if (!in_preproc)
|
|
{
|
|
while ( !frm.empty()
|
|
&& frm.top().GetInPreproc())
|
|
{
|
|
const E_Token type = frm.top().GetOpenToken();
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
|
|
/*
|
|
* If we just removed an #endregion, then check to see if a
|
|
* PP_REGION_INDENT entry is right below it
|
|
*/
|
|
if ( type == CT_PP_ENDREGION
|
|
&& frm.top().GetOpenToken() == CT_PP_REGION_INDENT)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
}
|
|
}
|
|
else if (pc->Is(CT_PREPROC)) // #
|
|
{
|
|
// Close out PP_IF_INDENT before playing with the parse frames
|
|
if ( frm.top().GetOpenToken() == CT_PP_IF_INDENT
|
|
&& ( pc->GetParentType() == CT_PP_ENDIF
|
|
|| pc->GetParentType() == CT_PP_ELSE))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
ParsingFrame frmbkup = frm;
|
|
frames.check(frm, cpd.pp_level, pc);
|
|
|
|
// Indent the body of a #region here
|
|
log_rule_B("pp_region_indent_code");
|
|
|
|
if ( options::pp_region_indent_code()
|
|
&& pc->GetParentType() == CT_PP_REGION)
|
|
{
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
// Hack to get the logs to look right
|
|
next->SetType(CT_PP_REGION_INDENT);
|
|
frm.push(next, __func__, __LINE__);
|
|
next->SetType(CT_PP_REGION);
|
|
|
|
// Indent one level
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.prev().GetIndentTab() + indent_size);
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetInPreproc(false);
|
|
log_indent_tmp();
|
|
}
|
|
// If option set, remove indent inside switch statement
|
|
log_rule_B("indent_switch_pp");
|
|
|
|
if ( frm.top().GetOpenToken() == CT_CASE
|
|
&& !options::indent_switch_pp())
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
LOG_FMT(LINDPC, "%s(%d): frm.top().indent is %zu, indent_size is %zu\n",
|
|
__func__, __LINE__, frm.top().GetIndent(), indent_size);
|
|
|
|
if (frm.top().GetIndent() >= indent_size)
|
|
{
|
|
frm.prev().SetIndent(frm.top().GetIndent() - indent_size);
|
|
}
|
|
log_prev_indent();
|
|
}
|
|
// Indent the body of a #if here
|
|
log_rule_B("pp_if_indent_code");
|
|
|
|
if ( options::pp_if_indent_code()
|
|
&& ( pc->GetParentType() == CT_PP_IF
|
|
|| pc->GetParentType() == CT_PP_ELSE))
|
|
{
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
int should_indent_preproc = true;
|
|
int should_ignore_preproc = false;
|
|
Chunk *preproc_next = pc->GetNextNl();
|
|
preproc_next = preproc_next->GetNextNcNnlNet();
|
|
|
|
/* Look ahead at what's on the line after the #if */
|
|
log_rule_B("pp_indent_brace");
|
|
log_rule_B("pp_indent_func_def");
|
|
log_rule_B("pp_indent_case");
|
|
log_rule_B("pp_indent_extern");
|
|
|
|
while ( preproc_next->IsNotNullChunk()
|
|
&& preproc_next->IsNot(CT_NEWLINE))
|
|
{
|
|
if ( (preproc_next->Is(CT_BRACE_OPEN))
|
|
|| (preproc_next->Is(CT_BRACE_CLOSE)))
|
|
{
|
|
if (options::pp_indent_brace() == 0)
|
|
{
|
|
should_indent_preproc = false;
|
|
break;
|
|
}
|
|
else if (options::pp_indent_brace() == -1)
|
|
{
|
|
should_ignore_preproc = true;
|
|
break;
|
|
}
|
|
}
|
|
else if ( ( preproc_next->Is(CT_FUNC_DEF)
|
|
&& !options::pp_indent_func_def())
|
|
|| ( preproc_next->Is(CT_CASE)
|
|
&& !options::pp_indent_case())
|
|
|| ( preproc_next->Is(CT_EXTERN)
|
|
&& !options::pp_indent_extern()))
|
|
{
|
|
should_indent_preproc = false;
|
|
break;
|
|
}
|
|
preproc_next = preproc_next->GetNext();
|
|
}
|
|
|
|
if (should_indent_preproc)
|
|
{
|
|
// Hack to get the logs to look right
|
|
|
|
const E_Token memtype = next->GetType();
|
|
next->SetType(CT_PP_IF_INDENT);
|
|
frm.push(next, __func__, __LINE__);
|
|
next->SetType(memtype);
|
|
|
|
if (should_ignore_preproc)
|
|
{
|
|
// Preserve original indentation
|
|
frm.top().SetIndent(pc->GetNextNl()->GetNext()->GetOrigCol());
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
// Indent one level except if the #if is a #include guard
|
|
size_t extra = ( pc->GetPpLevel() == 0
|
|
&& ifdef_over_whole_file())
|
|
? 0 : indent_size;
|
|
|
|
frm.top().SetIndent(frm.prev().GetIndent() + extra);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.prev().GetIndentTab() + extra);
|
|
}
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetInPreproc(false);
|
|
log_indent_tmp();
|
|
}
|
|
}
|
|
log_rule_B("indent_member_single");
|
|
|
|
if (options::indent_member_single())
|
|
{
|
|
if (pc->GetParentType() == CT_PP_IF)
|
|
{
|
|
// do nothing
|
|
}
|
|
else if (pc->GetParentType() == CT_PP_ELSE)
|
|
{
|
|
if ( frm.top().GetOpenToken() == CT_MEMBER
|
|
&& frm.top().GetPopChunk()->IsNotNullChunk()
|
|
&& frm.top().GetOpenChunk() != frmbkup.top().GetOpenChunk())
|
|
{
|
|
Chunk *tmp = pc->GetNextNcNnlNpp();
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
if ( tmp->Is(CT_WORD)
|
|
|| tmp->Is(CT_TYPE))
|
|
{
|
|
tmp = pc->GetNextNcNnlNpp();
|
|
}
|
|
else if ( tmp->Is(CT_FUNC_CALL)
|
|
|| tmp->Is(CT_FPAREN_OPEN))
|
|
{
|
|
tmp = tmp->GetNextType(CT_FPAREN_CLOSE, tmp->GetLevel());
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
tmp = pc->GetNextNcNnlNpp();
|
|
}
|
|
}
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
frm.top().SetPopChunk(tmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pc->GetParentType() == CT_PP_ENDIF)
|
|
{
|
|
if ( frmbkup.top().GetOpenToken() == CT_MEMBER
|
|
&& frm.top().GetOpenToken() == CT_MEMBER)
|
|
{
|
|
frm.top().SetPopChunk(frmbkup.top().GetPopChunk());
|
|
}
|
|
}
|
|
}
|
|
// Transition into a preproc by creating a dummy indent
|
|
Chunk *pp_next = pc->GetNext();
|
|
|
|
if (pp_next->IsNullChunk())
|
|
{
|
|
return;
|
|
}
|
|
frm.push(pp_next, __func__, __LINE__);
|
|
|
|
if ( pc->GetParentType() == CT_PP_DEFINE
|
|
|| pc->GetParentType() == CT_PP_UNDEF)
|
|
{
|
|
log_rule_B("pp_define_at_level");
|
|
frm.top().SetIndentTmp(options::pp_define_at_level()
|
|
? frm.prev().GetIndentTmp() : 1);
|
|
|
|
log_rule_B("pp_multiline_define_body_indent");
|
|
|
|
if (options::pp_multiline_define_body_indent() < 0)
|
|
{
|
|
frm.top().SetIndent(-options::pp_multiline_define_body_indent());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(pc->GetColumn() + options::pp_multiline_define_body_indent());
|
|
}
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( ( pc->GetParentType() == CT_PP_PRAGMA
|
|
|| pc->GetParentType() == CT_PP_OTHER)
|
|
&& options::pp_define_at_level())
|
|
{
|
|
log_rule_B("pp_define_at_level");
|
|
frm.top().SetIndentTmp(frm.prev().GetIndentTmp());
|
|
frm.top().SetIndent(frm.top().GetIndentTmp() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( pc->GetParentType() == CT_PP_INCLUDE
|
|
&& options::pp_include_at_level())
|
|
{
|
|
log_rule_B("pp_include_at_level");
|
|
frm.top().SetIndentTmp(frm.prev().GetIndentTmp());
|
|
frm.top().SetIndent(frm.top().GetIndentTmp() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else
|
|
{
|
|
if ( (frm.prev().GetOpenToken() == CT_PP_REGION_INDENT)
|
|
|| ( (frm.prev().GetOpenToken() == CT_PP_IF_INDENT)
|
|
&& (frm.top().GetOpenToken() != CT_PP_ENDIF)))
|
|
{
|
|
frm.top().SetIndent(frm.prev(2).GetIndent());
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
log_indent();
|
|
}
|
|
log_indent();
|
|
|
|
|
|
int val = 0;
|
|
|
|
if ( pc->GetParentType() == CT_PP_REGION
|
|
|| pc->GetParentType() == CT_PP_ENDREGION)
|
|
{
|
|
log_rule_B("pp_indent_region");
|
|
val = options::pp_indent_region();
|
|
log_indent();
|
|
}
|
|
else if ( pc->GetParentType() == CT_PP_IF
|
|
|| pc->GetParentType() == CT_PP_ELSE
|
|
|| pc->GetParentType() == CT_PP_ENDIF)
|
|
{
|
|
log_rule_B("pp_indent_if");
|
|
val = options::pp_indent_if();
|
|
log_indent();
|
|
}
|
|
|
|
if (val != 0)
|
|
{
|
|
size_t indent = frm.top().GetIndent();
|
|
indent = (val > 0) ? val // reassign if positive val,
|
|
: ((size_t)(abs(val)) < indent) // else if no underflow
|
|
? (indent + val) : 0; // reduce, else 0
|
|
frm.top().SetIndent(indent);
|
|
}
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
}
|
|
// Check for close XML tags "</..."
|
|
log_rule_B("indent_xml_string");
|
|
|
|
if (options::indent_xml_string() > 0)
|
|
{
|
|
if (pc->Is(CT_STRING))
|
|
{
|
|
if ( pc->Len() > 4
|
|
&& xml_indent > 0
|
|
&& pc->GetStr()[1] == '<'
|
|
&& pc->GetStr()[2] == '/')
|
|
{
|
|
log_rule_B("indent_xml_string");
|
|
xml_indent -= options::indent_xml_string();
|
|
}
|
|
}
|
|
else if (!pc->IsCommentOrNewline())
|
|
{
|
|
xml_indent = 0;
|
|
}
|
|
}
|
|
// Handle non-brace closures
|
|
log_indent_tmp();
|
|
|
|
bool token_used = false;
|
|
size_t old_frm_size;
|
|
|
|
do
|
|
{
|
|
old_frm_size = frm.size();
|
|
|
|
// End anything that drops a level
|
|
if ( !pc->IsCommentOrNewline()
|
|
&& frm.top().GetOpenLevel() > pc->GetLevel())
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
if (frm.top().GetOpenLevel() >= pc->GetLevel())
|
|
{
|
|
// process virtual braces closes (no text output)
|
|
if ( pc->Is(CT_VBRACE_CLOSE)
|
|
&& frm.top().GetOpenToken() == CT_VBRACE_OPEN)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
pc = pc->GetNext();
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
|
|
if (pc->IsNullChunk())
|
|
{
|
|
// need to break out of both the do and while loops
|
|
goto null_pc;
|
|
}
|
|
}
|
|
|
|
if ( pc->Is(CT_BRACE_CLOSE)
|
|
&& pc->GetParentType() == CT_ENUM)
|
|
{
|
|
Chunk *prev_ncnl = pc->GetPrevNcNnl();
|
|
LOG_FMT(LINDLINE, "%s(%d): prev_ncnl is '%s', orig line is %zu, orig col is %zu\n",
|
|
__func__, __LINE__, prev_ncnl->Text(), prev_ncnl->GetOrigLine(), prev_ncnl->GetOrigCol());
|
|
|
|
if (prev_ncnl->Is(CT_COMMA))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): prev_ncnl is comma\n", __func__, __LINE__);
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): prev_ncnl is NOT comma\n", __func__, __LINE__);
|
|
}
|
|
}
|
|
|
|
// End any assign operations with a semicolon on the same level
|
|
if (is_end_of_assignment(pc, frm))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
// Pop Colon from stack in ternary operator
|
|
// a
|
|
// ? b
|
|
// : e/*top*/;/*pc*/
|
|
log_rule_B("indent_inside_ternary_operator");
|
|
|
|
if ( options::indent_inside_ternary_operator()
|
|
&& (frm.top().GetOpenToken() == CT_COND_COLON)
|
|
&& ( pc->IsSemicolon()
|
|
|| pc->Is(CT_COMMA)
|
|
|| pc->Is(CT_OC_MSG_NAME)
|
|
|| pc->Is(CT_SPAREN_CLOSE))) // Issue #1130, #1715
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// End any assign operations with a semicolon on the same level
|
|
if ( pc->IsSemicolon()
|
|
&& ( (frm.top().GetOpenToken() == CT_IMPORT)
|
|
|| (frm.top().GetOpenToken() == CT_USING)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// End any custom macro-based open/closes
|
|
if ( !token_used
|
|
&& (frm.top().GetOpenToken() == CT_MACRO_OPEN)
|
|
&& pc->Is(CT_MACRO_CLOSE))
|
|
{
|
|
token_used = true;
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// End any CPP/ObjC class colon stuff
|
|
if ( ( (frm.top().GetOpenToken() == CT_CLASS_COLON)
|
|
|| (frm.top().GetOpenToken() == CT_CONSTR_COLON))
|
|
&& ( pc->Is(CT_BRACE_OPEN)
|
|
|| pc->Is(CT_OC_END)
|
|
|| pc->Is(CT_OC_SCOPE)
|
|
|| pc->Is(CT_OC_PROPERTY)
|
|
|| pc->Is(CT_TYPEDEF) // Issue #2675
|
|
|| pc->Is(CT_MACRO_OPEN)
|
|
|| pc->Is(CT_MACRO_CLOSE)
|
|
|| ( language_is_set(LANG_OC)
|
|
&& pc->IsComment()
|
|
&& pc->GetParentType() == CT_COMMENT_WHOLE) // Issue #2675
|
|
|| pc->IsSemicolon()))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// End ObjC class colon stuff inside of generic definition (like Test<T1: id<T3>>)
|
|
if ( (frm.top().GetOpenToken() == CT_CLASS_COLON)
|
|
&& pc->Is(CT_ANGLE_CLOSE)
|
|
&& pc->GetParentType() == CT_OC_GENERIC_SPEC)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// End Objc nested message and boxed array
|
|
// TODO: ideally formatting would know which opens occurred on a line and group closes in the same manor
|
|
if ( language_is_set(LANG_OC)
|
|
&& pc->Is(CT_SQUARE_CLOSE)
|
|
&& pc->GetParentType() == CT_OC_AT
|
|
&& frm.top().GetOpenLevel() >= pc->GetLevel())
|
|
{
|
|
size_t count = 1;
|
|
Chunk *next = pc->GetNextNc();
|
|
|
|
while ( next->IsNotNullChunk()
|
|
&& ( ( next->Is(CT_BRACE_CLOSE)
|
|
&& next->GetParentType() == CT_OC_AT)
|
|
|| ( next->Is(CT_SQUARE_CLOSE)
|
|
&& next->GetParentType() == CT_OC_AT)
|
|
|| ( next->Is(CT_SQUARE_CLOSE)
|
|
&& next->GetParentType() == CT_OC_MSG)))
|
|
{
|
|
count++;
|
|
next = next->GetNextNc();
|
|
}
|
|
count = std::min(count, frm.size());
|
|
|
|
if (count > 0)
|
|
{
|
|
while (count-- > 0)
|
|
{
|
|
if (frm.top().GetOpenToken() == CT_SQUARE_OPEN)
|
|
{
|
|
if (frm.GetParenCount() == 0)
|
|
{
|
|
fprintf(stderr, "%s(%d): frame parenthesis count is ZERO, cannot be decremented, at line %zu, column %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol());
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
frm.SetParenCount(frm.GetParenCount() - 1);
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
if (next->IsNotNullChunk())
|
|
{
|
|
// End any assign operations with a semicolon on the same level
|
|
if (is_end_of_assignment(next, frm))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
}
|
|
// Indent the brace to match outer most brace/square
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// a case is ended with another case or a close brace
|
|
if ( (frm.top().GetOpenToken() == CT_CASE)
|
|
&& ( pc->Is(CT_BRACE_CLOSE)
|
|
|| pc->Is(CT_CASE)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
if (frm.top().GetPopChunk()->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pop_pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, frm.top().GetPopChunk()->GetOrigLine(), frm.top().GetPopChunk()->GetOrigCol(),
|
|
frm.top().GetPopChunk()->Text(), get_token_name(frm.top().GetPopChunk()->GetType()));
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
|
|
if ( (frm.top().GetOpenToken() == CT_MEMBER)
|
|
&& frm.top().GetPopChunk() == pc)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
if ( (frm.top().GetOpenToken() == CT_LAMBDA)
|
|
&& ( pc->Is(CT_SEMICOLON)
|
|
|| pc->Is(CT_COMMA)
|
|
|| pc->Is(CT_BRACE_OPEN)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
// a class scope is ended with another class scope or a close brace
|
|
log_rule_B("indent_access_spec_body");
|
|
|
|
if ( options::indent_access_spec_body()
|
|
&& (frm.top().GetOpenToken() == CT_ACCESS)
|
|
&& ( pc->Is(CT_BRACE_CLOSE)
|
|
|| pc->Is(CT_ACCESS)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// return & throw are ended with a semicolon
|
|
if ( pc->IsSemicolon()
|
|
&& ( (frm.top().GetOpenToken() == CT_RETURN)
|
|
|| (frm.top().GetOpenToken() == CT_THROW)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// an OC SCOPE ('-' or '+') ends with a semicolon or brace open
|
|
if ( (frm.top().GetOpenToken() == CT_OC_SCOPE)
|
|
&& ( pc->IsSemicolon()
|
|
|| pc->Is(CT_BRACE_OPEN)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
/*
|
|
* a typedef and an OC SCOPE ('-' or '+') ends with a semicolon or
|
|
* brace open
|
|
*/
|
|
if ( (frm.top().GetOpenToken() == CT_TYPEDEF)
|
|
&& ( pc->IsSemicolon()
|
|
|| pc->IsParenOpen()
|
|
|| pc->Is(CT_BRACE_OPEN)))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// an SQL EXEC is ended with a semicolon
|
|
if ( (frm.top().GetOpenToken() == CT_SQL_EXEC)
|
|
&& pc->IsSemicolon())
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// an CLASS is ended with a semicolon or brace open
|
|
if ( (frm.top().GetOpenToken() == CT_CLASS)
|
|
&& ( pc->Is(CT_CLASS_COLON)
|
|
|| pc->Is(CT_BRACE_OPEN)
|
|
|| pc->IsSemicolon()))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
log_rule_B("indent_oc_inside_msg_sel");
|
|
|
|
// Pop OC msg selector stack
|
|
if ( options::indent_oc_inside_msg_sel()
|
|
&& (frm.top().GetOpenToken() != CT_SQUARE_OPEN)
|
|
&& frm.top().GetOpenLevel() >= pc->GetLevel()
|
|
&& ( pc->Is(CT_OC_MSG_FUNC)
|
|
|| pc->Is(CT_OC_MSG_NAME))) // Issue #2658
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// Close out parenthesis and squares
|
|
if ( (frm.top().GetOpenToken() == (pc->GetType() - 1))
|
|
&& ( pc->Is(CT_PAREN_CLOSE)
|
|
|| pc->Is(CT_LPAREN_CLOSE) // Issue #3054
|
|
|| pc->Is(CT_SPAREN_CLOSE)
|
|
|| pc->Is(CT_FPAREN_CLOSE)
|
|
|| pc->Is(CT_RPAREN_CLOSE) // Issue #3914
|
|
|| pc->Is(CT_SQUARE_CLOSE)
|
|
|| pc->Is(CT_ANGLE_CLOSE))
|
|
&& ( !pc->TestFlags(PCF_CONT_LINE)
|
|
|| options::indent_continue() >= 0))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
|
|
if (frm.GetParenCount() == 0)
|
|
{
|
|
fprintf(stderr, "%s(%d): frame parenthesis count is ZERO, cannot be decremented, at line %zu, column %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol());
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
frm.SetParenCount(frm.GetParenCount() - 1);
|
|
}
|
|
}
|
|
} while (old_frm_size > frm.size());
|
|
|
|
// Grab a copy of the current indent
|
|
indent_column_set(frm.top().GetIndentTmp()); // Issue #3294
|
|
log_indent_tmp();
|
|
|
|
log_rule_B("indent_single_newlines");
|
|
|
|
if ( pc->Is(CT_NEWLINE)
|
|
&& options::indent_single_newlines())
|
|
{
|
|
pc->SetNlColumn(indent_column);
|
|
}
|
|
|
|
if ( !pc->IsCommentOrNewline()
|
|
&& log_sev_on(LINDPC))
|
|
{
|
|
LOG_FMT(LINDPC, "%s(%d):\n", __func__, __LINE__);
|
|
LOG_FMT(LINDPC, " -=[ pc orig line is %zu, orig col is %zu, Text() is '%s' ]=-, frm.size() is %zu\n",
|
|
pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), frm.size());
|
|
|
|
for (size_t ttidx = frm.size() - 1; ttidx > 0; ttidx--)
|
|
{
|
|
LOG_FMT(LINDPC, " [%zu %zu:%zu '%s' %s/%s tmp=%zu indent=%zu brace indent=%zu indent tab=%zu indent continue=%d level=%zu pc brace level=%zu]\n",
|
|
ttidx,
|
|
frm.at(ttidx).GetOpenChunk()->GetOrigLine(),
|
|
frm.at(ttidx).GetOpenChunk()->GetOrigCol(),
|
|
frm.at(ttidx).GetOpenChunk()->Text(),
|
|
get_token_name(frm.at(ttidx).GetOpenToken()),
|
|
get_token_name(frm.at(ttidx).GetOpenChunk()->GetParentType()),
|
|
frm.at(ttidx).GetIndentTmp(),
|
|
frm.at(ttidx).GetIndent(),
|
|
frm.at(ttidx).GetBraceIndent(),
|
|
frm.at(ttidx).GetIndentTab(),
|
|
frm.at(ttidx).GetIndentContinue(),
|
|
frm.at(ttidx).GetOpenLevel(),
|
|
frm.at(ttidx).GetOpenChunk()->GetBraceLevel());
|
|
}
|
|
}
|
|
char copy[1000];
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, orig col is %zu, column is %zu, Text() is '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn(), pc->ElidedText(copy));
|
|
|
|
// Issue #672
|
|
if ( pc->Is(CT_BRACE_OPEN)
|
|
&& classFound)
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): CT_BRACE_OPEN found, CLOSE IT\n",
|
|
__func__, __LINE__);
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
classFound = false;
|
|
}
|
|
/*
|
|
* Handle stuff that can affect the current indent:
|
|
* - brace close
|
|
* - vbrace open
|
|
* - brace open
|
|
* - case (immediate)
|
|
* - labels (immediate)
|
|
* - class colons (immediate)
|
|
*
|
|
* And some stuff that can't
|
|
* - open paren
|
|
* - open square
|
|
* - assignment
|
|
* - return
|
|
*/
|
|
log_rule_B("indent_braces");
|
|
log_rule_B("indent_braces_no_func");
|
|
log_rule_B("indent_braces_no_class");
|
|
log_rule_B("indent_braces_no_struct");
|
|
const bool brace_indent = ( ( pc->Is(CT_BRACE_CLOSE)
|
|
|| pc->Is(CT_BRACE_OPEN))
|
|
&& options::indent_braces()
|
|
&& ( !options::indent_braces_no_func()
|
|
|| pc->GetParentType() != CT_FUNC_DEF)
|
|
&& ( !options::indent_braces_no_func()
|
|
|| pc->GetParentType() != CT_FUNC_CLASS_DEF)
|
|
&& ( !options::indent_braces_no_class()
|
|
|| pc->GetParentType() != CT_CLASS)
|
|
&& ( !options::indent_braces_no_struct()
|
|
|| pc->GetParentType() != CT_STRUCT));
|
|
LOG_FMT(LINDENT, "%s(%d): brace_indent is %s\n",
|
|
__func__, __LINE__, brace_indent ? "true" : "false");
|
|
|
|
if (pc->Is(CT_BRACE_CLOSE))
|
|
{
|
|
if (language_is_set(LANG_OC))
|
|
{
|
|
if ( frm.top().GetOpenToken() == CT_BRACE_OPEN
|
|
&& frm.top().GetOpenLevel() >= pc->GetLevel())
|
|
{
|
|
size_t count = 1;
|
|
Chunk *next = pc->GetNextNc();
|
|
|
|
while ( next->IsNotNullChunk()
|
|
&& ( ( next->Is(CT_BRACE_CLOSE)
|
|
&& next->GetParentType() == CT_OC_AT)
|
|
|| ( next->Is(CT_SQUARE_CLOSE)
|
|
&& next->GetParentType() == CT_OC_AT)))
|
|
{
|
|
count++;
|
|
next = next->GetNextNc();
|
|
}
|
|
count = std::min(count, frm.size());
|
|
|
|
// End Objc nested boxed dictionary
|
|
// TODO: ideally formatting would know which opens occurred on a line and group closes in the same manor
|
|
if ( count > 0
|
|
&& pc->Is(CT_BRACE_CLOSE)
|
|
&& pc->GetParentType() == CT_OC_AT)
|
|
{
|
|
if (frm.top().GetIndentData().ref)
|
|
{
|
|
pc->IndentData().ref = frm.top().GetIndentData().ref;
|
|
pc->IndentData().delta = 0;
|
|
}
|
|
|
|
while (count-- > 0)
|
|
{
|
|
LOG_CHUNK(LINDLINE, pc);
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
if (next->IsNotNullChunk())
|
|
{
|
|
// End any assign operations with a semicolon on the same level
|
|
if (is_end_of_assignment(next, frm))
|
|
{
|
|
LOG_CHUNK(LINDLINE, pc);
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
}
|
|
|
|
// Indent the brace to match outer most brace/square
|
|
if (frm.top().GetIndentContinue())
|
|
{
|
|
indent_column_set(frm.top().GetIndentTmp() - indent_size);
|
|
}
|
|
else
|
|
{
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Indent the brace to match the open brace
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
|
|
if (frm.top().GetIndentData().ref)
|
|
{
|
|
pc->IndentData().ref = frm.top().GetIndentData().ref;
|
|
pc->IndentData().delta = 0;
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
}
|
|
}
|
|
else if (frm.top().GetBraceIndent()) // Issue #3421
|
|
{
|
|
// Indent the brace to match the open brace
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
|
|
if (frm.top().GetIndentData().ref)
|
|
{
|
|
pc->IndentData().ref = frm.top().GetIndentData().ref;
|
|
pc->IndentData().delta = 0;
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
}
|
|
else if (pc->Is(CT_VBRACE_OPEN))
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
log_rule_B("indent_min_vbrace_open");
|
|
size_t iMinIndent = options::indent_min_vbrace_open();
|
|
|
|
if (indent_size > iMinIndent)
|
|
{
|
|
iMinIndent = indent_size;
|
|
}
|
|
size_t iNewIndent = frm.prev().GetIndent() + iMinIndent;
|
|
|
|
log_rule_B("indent_vbrace_open_on_tabstop");
|
|
|
|
if (options::indent_vbrace_open_on_tabstop())
|
|
{
|
|
iNewIndent = next_tab_column(iNewIndent);
|
|
}
|
|
frm.top().SetIndent(iNewIndent);
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
// Always indent on virtual braces
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
}
|
|
else if ( pc->Is(CT_BRACE_OPEN)
|
|
&& pc->GetNext()->IsNot(CT_NAMESPACE))
|
|
{
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
log_rule_B("indent_macro_brace");
|
|
|
|
if ( !options::indent_macro_brace()
|
|
&& frm.prev().GetOpenToken() == CT_PP_DEFINE
|
|
&& frm.prev().GetOpenLine() == frm.top().GetOpenLine())
|
|
{
|
|
LOG_FMT(LINDENT2, "%s(%d): indent_macro_brace\n", __func__, __LINE__);
|
|
}
|
|
else if ( options::indent_cpp_lambda_body()
|
|
&& pc->GetParentType() == CT_CPP_LAMBDA)
|
|
{
|
|
log_rule_B("indent_cpp_lambda_body");
|
|
frm.top().SetBraceIndent(frm.prev().GetIndent());
|
|
|
|
Chunk *head = frm.top().GetOpenChunk()->GetPrevNcNnlNpp();
|
|
Chunk *tail = Chunk::NullChunkPtr;
|
|
Chunk *frm_prev = frm.prev().GetOpenChunk();
|
|
bool enclosure = ( frm_prev->GetParentType() != CT_FUNC_DEF // Issue #3407
|
|
&& frm_prev != frm_prev->GetClosingParen());
|
|
bool linematch = true;
|
|
|
|
for (auto it = frm.rbegin(); it != frm.rend() && tail->IsNullChunk(); ++it)
|
|
{
|
|
if (it->GetOpenChunk() != frm.top().GetOpenChunk())
|
|
{
|
|
linematch &= it->GetOpenChunk()->IsOnSameLine(head);
|
|
}
|
|
Chunk *match = it->GetOpenChunk()->GetClosingParen();
|
|
|
|
if (match->IsNullChunk())
|
|
{
|
|
continue;
|
|
}
|
|
Chunk *target = match->GetNextNcNnlNpp();
|
|
|
|
while ( tail->IsNullChunk()
|
|
&& target->IsNotNullChunk())
|
|
{
|
|
if ( target->IsSemicolon()
|
|
&& target->GetLevel() == match->GetLevel())
|
|
{
|
|
tail = target;
|
|
}
|
|
else if (target->GetLevel() < match->GetLevel())
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
target = target->GetNextNcNnlNpp();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool toplevel = true;
|
|
|
|
for (auto it = frm.rbegin(); it != frm.rend() && tail->IsNotNullChunk(); ++it)
|
|
{
|
|
if (!it->GetOpenChunk()->Is(CT_FPAREN_OPEN))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (it->GetOpenChunk()->GetLevel() < tail->GetLevel())
|
|
{
|
|
toplevel = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// A few things to check:
|
|
// 1. The matching brace is on the same line as the ending semicolon
|
|
// 2a. If it's an assignment, check that both sides of the assignment operator are on the same line
|
|
// 2b. If it's inside some closure, check that all the frames are on the same line,
|
|
// and it is in the top level closure, and indent_continue is non-zero
|
|
bool sameLine = frm.top().GetOpenChunk()->GetClosingParen()->IsOnSameLine(tail);
|
|
|
|
bool isAssignSameLine =
|
|
!enclosure
|
|
&& options::align_assign_span() == 0
|
|
&& !options::indent_align_assign()
|
|
&& frm.prev().GetOpenChunk()->GetPrevNcNnlNpp()->IsOnSameLine(frm.prev().GetOpenChunk())
|
|
&& frm.prev().GetOpenChunk()->IsOnSameLine(frm.prev().GetOpenChunk()->GetNextNcNnlNpp());
|
|
|
|
bool closureSameLineTopLevel =
|
|
(options::indent_continue() > 0)
|
|
&& enclosure
|
|
&& linematch
|
|
&& toplevel
|
|
&& frm.top().GetOpenChunk()->GetClosingParen()->IsOnSameLine(frm.top().GetOpenChunk());
|
|
|
|
if ( sameLine
|
|
&& ( (isAssignSameLine)
|
|
|| (closureSameLineTopLevel)))
|
|
{
|
|
if (indent_size > frm.top().GetBraceIndent()) // if options::indent_indent_columns() is too big
|
|
{
|
|
frm.top().SetBraceIndent(1);
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetBraceIndent(frm.top().GetBraceIndent() - indent_size);
|
|
}
|
|
}
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(indent_column + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
frm.prev().SetIndentTmp(frm.top().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( language_is_set(LANG_CPP)
|
|
&& options::indent_cpp_lambda_only_once()
|
|
&& (pc->GetParentType() == CT_CPP_LAMBDA))
|
|
{
|
|
// test example cpp:30756
|
|
log_rule_B("indent_cpp_lambda_only_once");
|
|
|
|
size_t namespace_indent_to_ignore = 0; // Issue #1813
|
|
log_rule_B("indent_namespace");
|
|
|
|
if (!options::indent_namespace())
|
|
{
|
|
for (auto i = frm.rbegin(); i != frm.rend(); ++i)
|
|
{
|
|
if (i->GetNsCount())
|
|
{
|
|
namespace_indent_to_ignore = i->GetNsCount();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Issue # 1296
|
|
frm.top().SetBraceIndent(1 + (pc->GetBraceLevel() - namespace_indent_to_ignore) * indent_size);
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(indent_column + indent_size);
|
|
log_indent();
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
frm.prev().SetIndentTmp(frm.top().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( language_is_set(LANG_CS | LANG_JAVA)
|
|
&& options::indent_cs_delegate_brace()
|
|
&& ( pc->GetParentType() == CT_LAMBDA
|
|
|| pc->GetParentType() == CT_DELEGATE))
|
|
{
|
|
log_rule_B("indent_cs_delegate_brace");
|
|
frm.top().SetBraceIndent(1 + (pc->GetBraceLevel() + 1) * indent_size);
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(indent_column + indent_size);
|
|
log_indent();
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
frm.prev().SetIndentTmp(frm.top().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( language_is_set(LANG_CS | LANG_JAVA)
|
|
&& !options::indent_cs_delegate_brace()
|
|
&& !options::indent_align_paren()
|
|
&& ( pc->GetParentType() == CT_LAMBDA
|
|
|| pc->GetParentType() == CT_DELEGATE))
|
|
{
|
|
log_rule_B("indent_cs_delegate_brace");
|
|
log_rule_B("indent_align_paren");
|
|
frm.top().SetBraceIndent(frm.prev().GetIndent());
|
|
|
|
// Issue # 1620, UNI-24090.cs
|
|
if (frm.prev().GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk()->GetPrevNcNnlNpp()))
|
|
{
|
|
frm.top().SetBraceIndent(frm.top().GetBraceIndent() - indent_size);
|
|
}
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(indent_column + indent_size);
|
|
log_indent();
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
frm.prev().SetIndentTmp(frm.top().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( !options::indent_paren_open_brace()
|
|
&& !language_is_set(LANG_CS)
|
|
&& pc->GetParentType() == CT_CPP_LAMBDA
|
|
&& ( pc->TestFlags(PCF_IN_FCN_DEF)
|
|
|| pc->TestFlags(PCF_IN_FCN_CTOR)) // Issue #2152
|
|
&& pc->GetNextNc()->IsNewline())
|
|
{
|
|
log_rule_B("indent_paren_open_brace");
|
|
// Issue #1165
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, brace level is %zu, for '%s', pc->GetLevel() is %zu, pc(-1)->GetLevel() is %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetBraceLevel(), pc->Text(), pc->GetLevel(), frm.prev().GetOpenChunk()->GetLevel());
|
|
frm.top().SetBraceIndent(1 + (pc->GetBraceLevel() + 1) * indent_size);
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
// any '{' that is inside of a '(' overrides the '(' indent
|
|
// only to help the vim command }
|
|
else if ( !options::indent_paren_open_brace()
|
|
&& frm.prev().GetOpenChunk()->IsParenOpen()
|
|
&& pc->GetNextNc()->IsNewline())
|
|
{
|
|
log_rule_B("indent_paren_open_brace");
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, brace level is %zu, for '%s', pc->GetLevel() is %zu, pc(-1)->GetLevel() is %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetBraceLevel(), pc->Text(), pc->GetLevel(), frm.prev().GetOpenChunk()->GetLevel());
|
|
// FIXME: I don't know how much of this is necessary, but it seems to work
|
|
frm.top().SetBraceIndent(1 + pc->GetBraceLevel() * indent_size);
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(indent_column + indent_size);
|
|
log_indent();
|
|
|
|
if ( (pc->GetParentType() == CT_OC_BLOCK_EXPR)
|
|
&& pc->TestFlags(PCF_IN_OC_MSG))
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
log_indent();
|
|
frm.top().SetBraceIndent(frm.prev().GetIndentTmp());
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
}
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
frm.prev().SetIndentTmp(frm.top().GetIndentTmp());
|
|
}
|
|
else if ( frm.GetParenCount() != 0
|
|
&& !pc->TestFlags(PCF_IN_LAMBDA)) // Issue #3761
|
|
{
|
|
if (frm.top().GetOpenChunk()->GetParentType() == CT_OC_BLOCK_EXPR)
|
|
{
|
|
log_rule_B("indent_oc_block_msg");
|
|
|
|
if ( pc->TestFlags(PCF_IN_OC_MSG)
|
|
&& options::indent_oc_block_msg())
|
|
{
|
|
frm.top().IndentData().ref = oc_msg_block_indent(pc, false, false, false, true);
|
|
log_rule_B("indent_oc_block_msg");
|
|
frm.top().IndentData().delta = options::indent_oc_block_msg();
|
|
}
|
|
log_rule_B("indent_oc_block");
|
|
log_rule_B("indent_oc_block_msg_xcode_style");
|
|
|
|
if ( options::indent_oc_block()
|
|
|| options::indent_oc_block_msg_xcode_style())
|
|
{
|
|
bool in_oc_msg = pc->TestFlags(PCF_IN_OC_MSG);
|
|
log_rule_B("indent_oc_block_msg_from_keyword");
|
|
bool indent_from_keyword = options::indent_oc_block_msg_from_keyword()
|
|
&& in_oc_msg;
|
|
log_rule_B("indent_oc_block_msg_from_colon");
|
|
bool indent_from_colon = options::indent_oc_block_msg_from_colon()
|
|
&& in_oc_msg;
|
|
log_rule_B("indent_oc_block_msg_from_caret");
|
|
bool indent_from_caret = options::indent_oc_block_msg_from_caret()
|
|
&& in_oc_msg;
|
|
log_rule_B("indent_oc_block_msg_from_brace");
|
|
bool indent_from_brace = options::indent_oc_block_msg_from_brace()
|
|
&& in_oc_msg;
|
|
|
|
/*
|
|
* In "Xcode indent mode", we want to indent:
|
|
* - if the colon is aligned (namely, if a newline has been
|
|
* added before it), indent_from_brace
|
|
* - otherwise, indent from previous block (the "else" statement here)
|
|
*/
|
|
log_rule_B("indent_oc_block_msg_xcode_style");
|
|
|
|
if (options::indent_oc_block_msg_xcode_style())
|
|
{
|
|
Chunk *bbc = pc->GetClosingParen(); // block brace close '}'
|
|
Chunk *bbc_next_ncnl = bbc->GetNextNcNnl();
|
|
|
|
if ( bbc_next_ncnl->GetType() == CT_OC_MSG_NAME
|
|
|| bbc_next_ncnl->GetType() == CT_OC_MSG_FUNC)
|
|
{
|
|
indent_from_brace = false;
|
|
indent_from_colon = false;
|
|
indent_from_caret = false;
|
|
indent_from_keyword = true;
|
|
}
|
|
else
|
|
{
|
|
indent_from_brace = false;
|
|
indent_from_colon = false;
|
|
indent_from_caret = false;
|
|
indent_from_keyword = false;
|
|
}
|
|
}
|
|
Chunk *ref = oc_msg_block_indent(pc, indent_from_brace,
|
|
indent_from_caret,
|
|
indent_from_colon,
|
|
indent_from_keyword);
|
|
|
|
if (ref->IsNotNullChunk())
|
|
{
|
|
frm.top().SetIndent(indent_size + ref->GetColumn());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(1 + ((pc->GetBraceLevel() + 1) * indent_size));
|
|
}
|
|
log_indent();
|
|
indent_column_set(frm.top().GetIndent() - indent_size);
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
log_indent();
|
|
}
|
|
}
|
|
else if ( frm.top().GetOpenChunk()->GetType() == CT_BRACE_OPEN
|
|
&& frm.top().GetOpenChunk()->GetParentType() == CT_OC_AT)
|
|
{
|
|
// We are inside @{ ... } -- indent one tab from the paren
|
|
if (frm.prev().GetIndentContinue())
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
}
|
|
log_indent();
|
|
}
|
|
// Issue # 1620, UNI-24090.cs
|
|
else if ( frm.prev().GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk())
|
|
&& !options::indent_align_paren()
|
|
&& frm.prev().GetOpenChunk()->IsParenOpen()
|
|
&& !pc->TestFlags(PCF_ONE_LINER))
|
|
{
|
|
log_rule_B("indent_align_paren");
|
|
// We are inside ({ ... }) -- where { and ( are on the same line, avoiding double indentations.
|
|
// only to help the vim command }
|
|
frm.top().SetBraceIndent(frm.prev().GetIndent() - indent_size);
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
log_indent();
|
|
}
|
|
else if ( frm.prev().GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk()->GetPrevNcNnlNpp())
|
|
&& !options::indent_align_paren()
|
|
&& frm.prev().GetOpenChunk()->IsParenOpen()
|
|
&& !pc->TestFlags(PCF_ONE_LINER))
|
|
{
|
|
log_rule_B("indent_align_paren");
|
|
// We are inside ({ ... }) -- where { and ( are on adjacent lines, avoiding indentation of brace.
|
|
// only to help the vim command }
|
|
frm.top().SetBraceIndent(frm.prev().GetIndent() - indent_size);
|
|
indent_column_set(frm.top().GetBraceIndent());
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
log_indent();
|
|
}
|
|
else if ( options::indent_oc_inside_msg_sel()
|
|
&& ( frm.prev().GetOpenToken() == CT_OC_MSG_FUNC
|
|
|| frm.prev().GetOpenToken() == CT_OC_MSG_NAME)) // Issue #2658
|
|
{
|
|
log_rule_B("indent_oc_inside_msg_sel");
|
|
// [Class Message:{<here>
|
|
frm.top().SetIndent(frm.prev().GetOpenChunk()->GetColumn() + indent_size);
|
|
log_indent();
|
|
indent_column_set(frm.prev().GetOpenChunk()->GetColumn());
|
|
}
|
|
// Issue #3813
|
|
else if (pc->TestFlags(PCF_OC_IN_BLOCK) && pc->GetParentType() == CT_SWITCH)
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
}
|
|
else
|
|
{
|
|
// We are inside ({ ... }) -- indent one tab from the paren
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
|
|
if (!frm.prev().GetOpenChunk()->IsParenOpen())
|
|
{
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
}
|
|
log_indent();
|
|
}
|
|
}
|
|
else if ( frm.top().GetOpenChunk()->GetType() == CT_BRACE_OPEN
|
|
&& frm.top().GetOpenChunk()->GetParentType() == CT_OC_AT)
|
|
{
|
|
// We are inside @{ ... } -- indent one tab from the paren
|
|
if (frm.prev().GetIndentContinue())
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
}
|
|
log_indent();
|
|
}
|
|
else if ( ( pc->GetParentType() == CT_BRACED_INIT_LIST
|
|
|| ( !options::indent_compound_literal_return()
|
|
&& pc->GetParentType() == CT_C_CAST))
|
|
&& frm.prev().GetOpenToken() == CT_RETURN)
|
|
{
|
|
log_rule_B("indent_compound_literal_return");
|
|
|
|
// we're returning either a c compound literal (CT_C_CAST) or a
|
|
// C++11 initialization list (CT_BRACED_INIT_LIST), use indent from the return.
|
|
if (frm.prev().GetIndentContinue())
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
}
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
// Use the prev indent level + indent_size.
|
|
if (pc->GetParentType() == CT_SWITCH)
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + options::indent_switch_body());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, ... indent is %zu\n",
|
|
__func__, __LINE__, frm.size() - 1, frm.top().GetIndent());
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', parent type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(),
|
|
get_token_name(pc->GetParentType()));
|
|
|
|
// If this brace is part of a statement, bump it out by indent_brace
|
|
if ( pc->GetParentType() == CT_IF
|
|
|| pc->GetParentType() == CT_ELSE
|
|
|| pc->GetParentType() == CT_ELSEIF
|
|
|| pc->GetParentType() == CT_TRY
|
|
|| pc->GetParentType() == CT_CATCH
|
|
|| pc->GetParentType() == CT_DO
|
|
|| pc->GetParentType() == CT_WHILE
|
|
|| pc->GetParentType() == CT_USING_STMT
|
|
|| pc->GetParentType() == CT_SWITCH
|
|
|| pc->GetParentType() == CT_SYNCHRONIZED
|
|
|| pc->GetParentType() == CT_FOR)
|
|
{
|
|
if (parent_token_indent != 0)
|
|
{
|
|
frm.top().SetIndent(frm.top().GetIndent() + parent_token_indent - indent_size);
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
log_rule_B("indent_brace");
|
|
frm.top().SetIndent(frm.top().GetIndent() + options::indent_brace());
|
|
log_indent();
|
|
indent_column_set(indent_column + options::indent_brace());
|
|
}
|
|
}
|
|
else if (pc->GetParentType() == CT_CASE)
|
|
{
|
|
if (options::indent_ignore_case_brace())
|
|
{
|
|
log_rule_B("indent_ignore_case_brace");
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
else
|
|
{
|
|
log_rule_B("indent_case_brace");
|
|
const auto tmp_indent = static_cast<int>(frm.prev().GetIndent())
|
|
- static_cast<int>(indent_size)
|
|
+ options::indent_case_brace();
|
|
/*
|
|
* An open brace with the parent of case does not indent by default
|
|
* options::indent_case_brace() can be used to indent the brace.
|
|
* So we need to take the CASE indent, subtract off the
|
|
* indent_size that was added above and then add indent_case_brace.
|
|
* may take negative value
|
|
*/
|
|
indent_column_set(max(tmp_indent, 0));
|
|
}
|
|
// Stuff inside the brace still needs to be indented
|
|
frm.top().SetIndent(indent_column + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( pc->GetParentType() == CT_CLASS
|
|
&& !options::indent_class())
|
|
{
|
|
log_rule_B("indent_class");
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, orig col is %zu, text is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
|
|
frm.top().SetIndent(frm.top().GetIndent() - indent_size);
|
|
log_indent();
|
|
}
|
|
else if (pc->GetParentType() == CT_NAMESPACE)
|
|
{
|
|
frm.top().SetNsCount(frm.prev().GetNsCount() + 1);
|
|
|
|
log_rule_B("indent_namespace");
|
|
log_rule_B("indent_namespace_single_indent");
|
|
|
|
if ( options::indent_namespace()
|
|
&& options::indent_namespace_single_indent())
|
|
{
|
|
if (frm.top().GetNsCount() >= 2)
|
|
{
|
|
// undo indent on all except the first namespace
|
|
frm.top().SetIndent(frm.top().GetIndent() - indent_size);
|
|
log_indent();
|
|
}
|
|
indent_column_set(frm.prev(frm.top().GetNsCount()).GetIndent());
|
|
}
|
|
else if ( options::indent_namespace()
|
|
&& options::indent_namespace_inner_only())
|
|
{
|
|
if (frm.top().GetNsCount() == 1)
|
|
{
|
|
// undo indent on first namespace only
|
|
frm.top().SetIndent(frm.top().GetIndent() - indent_size);
|
|
log_indent();
|
|
}
|
|
}
|
|
else if ( pc->TestFlags(PCF_LONG_BLOCK)
|
|
|| !options::indent_namespace())
|
|
{
|
|
log_rule_B("indent_namespace");
|
|
// don't indent long blocks
|
|
frm.top().SetIndent(frm.top().GetIndent() - indent_size);
|
|
log_indent();
|
|
}
|
|
else // indenting 'short' namespace
|
|
{
|
|
log_rule_B("indent_namespace_level");
|
|
|
|
if (options::indent_namespace_level() > 0)
|
|
{
|
|
frm.top().SetIndent(frm.top().GetIndent() - indent_size);
|
|
log_indent();
|
|
frm.top().SetIndent(frm.top().GetIndent() + options::indent_namespace_level());
|
|
log_indent();
|
|
}
|
|
}
|
|
}
|
|
else if ( pc->GetParentType() == CT_EXTERN
|
|
&& !options::indent_extern())
|
|
{
|
|
log_rule_B("indent_extern");
|
|
frm.top().SetIndent(frm.top().GetIndent() - indent_size);
|
|
log_indent();
|
|
}
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
}
|
|
|
|
if (pc->TestFlags(PCF_DONT_INDENT))
|
|
{
|
|
frm.top().SetIndent(pc->GetColumn());
|
|
log_indent();
|
|
|
|
indent_column_set(pc->GetColumn());
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If there isn't a newline between the open brace and the next
|
|
* item, just indent to wherever the next token is.
|
|
* This covers this sort of stuff:
|
|
* { a++;
|
|
* b--; };
|
|
*/
|
|
Chunk *next = pc->GetNextNcNnl();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
Chunk *prev = pc->GetPrev();
|
|
|
|
if ( pc->GetParentType() == CT_BRACED_INIT_LIST
|
|
&& prev->Is(CT_BRACE_OPEN)
|
|
&& prev->GetParentType() == CT_BRACED_INIT_LIST)
|
|
{
|
|
indent_column = frm.prev().GetBraceIndent();
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
log_indent();
|
|
}
|
|
else if ( !pc->IsNewlineBetween(next)
|
|
&& next->GetParentType() != CT_BRACED_INIT_LIST
|
|
&& options::indent_token_after_brace()
|
|
&& !pc->TestFlags(PCF_ONE_LINER)) // Issue #1108
|
|
{
|
|
log_rule_B("indent_token_after_brace");
|
|
frm.top().SetIndent(next->GetColumn());
|
|
log_indent();
|
|
}
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetOpenLine(pc->GetOrigLine());
|
|
log_indent_tmp();
|
|
|
|
log_rule_B("Update the indent_column");
|
|
|
|
// Update the indent_column if needed
|
|
if ( brace_indent
|
|
|| parent_token_indent != 0)
|
|
{
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
}
|
|
// Save the brace indent
|
|
frm.top().SetBraceIndent(indent_column);
|
|
}
|
|
else if (pc->Is(CT_SQL_END))
|
|
{
|
|
if (frm.top().GetOpenToken() == CT_SQL_BEGIN)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_SQL_BEGIN)
|
|
|| pc->Is(CT_MACRO_OPEN)
|
|
|| ( pc->Is(CT_CLASS)
|
|
&& language_is_set(LANG_CS))) // Issue #3536
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if (pc->Is(CT_SQL_EXEC))
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if (pc->Is(CT_MACRO_ELSE))
|
|
{
|
|
if (frm.top().GetOpenToken() == CT_MACRO_OPEN)
|
|
{
|
|
indent_column_set(frm.prev().GetIndent());
|
|
}
|
|
}
|
|
else if (pc->Is(CT_CASE))
|
|
{
|
|
// Start a case - indent options::indent_switch_case() from the switch level
|
|
log_rule_B("indent_switch_case");
|
|
const size_t tmp = frm.top().GetIndent() + indent_size
|
|
- options::indent_switch_body()
|
|
+ options::indent_switch_case();
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(tmp);
|
|
log_indent();
|
|
|
|
log_rule_B("indent_case_shift");
|
|
frm.top().SetIndentTmp(tmp - indent_size + options::indent_case_shift());
|
|
frm.top().SetIndentTab(tmp);
|
|
log_indent_tmp();
|
|
|
|
// Always set on case statements
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
|
|
if (options::indent_case_comment())
|
|
{
|
|
// comments before 'case' need to be aligned with the 'case'
|
|
Chunk *pct = pc;
|
|
|
|
while ( ((pct = pct->GetPrevNnl())->IsNotNullChunk())
|
|
&& pct->IsComment())
|
|
{
|
|
Chunk *t2 = pct->GetPrev();
|
|
|
|
if (t2->IsNewline())
|
|
{
|
|
pct->SetColumn(frm.top().GetIndentTmp());
|
|
pct->SetColumnIndent(pct->GetColumn());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pc->Is(CT_BREAK))
|
|
{
|
|
Chunk *prev = pc->GetPrevNcNnl();
|
|
|
|
if ( prev->Is(CT_BRACE_CLOSE)
|
|
&& prev->GetParentType() == CT_CASE)
|
|
{
|
|
// issue #663 + issue #1366
|
|
Chunk *prev_prev_newline = pc->GetPrevNl()->GetPrevNl();
|
|
|
|
if (prev_prev_newline->IsNotNullChunk())
|
|
{
|
|
// This only affects the 'break', so no need for a stack entry
|
|
indent_column_set(prev_prev_newline->GetNext()->GetColumn());
|
|
}
|
|
}
|
|
}
|
|
else if (pc->Is(CT_LABEL))
|
|
{
|
|
if (options::indent_ignore_label())
|
|
{
|
|
log_rule_B("indent_ignore_label");
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
else
|
|
{
|
|
log_rule_B("indent_label");
|
|
const int val = options::indent_label();
|
|
size_t pse_indent = frm.top().GetIndent();
|
|
|
|
// Labels get sent to the left or backed up
|
|
if (val > 0)
|
|
{
|
|
indent_column_set(val);
|
|
|
|
Chunk *next = pc->GetNext()->GetNext(); // colon + possible statement
|
|
|
|
if ( next->IsNotNullChunk()
|
|
&& !next->IsNewline()
|
|
// label (+ 2, because there is colon and space after it) must fit into indent
|
|
&& (val + pc->Len() + 2 <= pse_indent))
|
|
{
|
|
reindent_line(next, pse_indent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool no_underflow = (size_t)(abs(val)) < pse_indent;
|
|
indent_column_set((no_underflow ? (pse_indent + val) : 0));
|
|
}
|
|
}
|
|
}
|
|
else if (pc->Is(CT_ACCESS))
|
|
{
|
|
log_rule_B("indent_access_spec_body");
|
|
|
|
if (options::indent_access_spec_body())
|
|
{
|
|
const size_t tmp = frm.top().GetIndent() + indent_size;
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(tmp);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(tmp - indent_size);
|
|
frm.top().SetIndentTab(tmp);
|
|
log_indent_tmp();
|
|
|
|
/*
|
|
* If we are indenting the body, then we must leave the access spec
|
|
* indented at brace level
|
|
*/
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
// Issues 1161 + 2704
|
|
// comments before 'access specifier' need to be aligned with the 'access specifier'
|
|
// unless it is a Doxygen comment
|
|
Chunk *pct = pc;
|
|
|
|
while ( ((pct = pct->GetPrevNnl())->IsNotNullChunk())
|
|
&& pct->IsComment()
|
|
&& !pct->IsDoxygenComment())
|
|
{
|
|
Chunk *t2 = pct->GetPrev();
|
|
|
|
if (t2->IsNewline())
|
|
{
|
|
pct->SetColumn(frm.top().GetIndentTmp());
|
|
pct->SetColumnIndent(pct->GetColumn());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Access spec labels get sent to the left or backed up
|
|
log_rule_B("indent_access_spec");
|
|
int val = options::indent_access_spec();
|
|
|
|
if (val > 0)
|
|
{
|
|
indent_column_set(val);
|
|
}
|
|
else
|
|
{
|
|
size_t pse_indent = frm.top().GetIndent();
|
|
bool no_underflow = (size_t)(abs(val)) < pse_indent;
|
|
|
|
indent_column_set(no_underflow ? (pse_indent + val) : 0);
|
|
}
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_CLASS_COLON)
|
|
|| pc->Is(CT_CONSTR_COLON))
|
|
{
|
|
// just indent one level
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
if (pc->Is(CT_CLASS_COLON))
|
|
{
|
|
if (options::indent_ignore_before_class_colon())
|
|
{
|
|
log_rule_B("indent_ignore_before_class_colon");
|
|
frm.top().SetIndentTmp(pc->GetOrigCol());
|
|
log_indent_tmp();
|
|
}
|
|
else if (options::indent_before_class_colon() != 0)
|
|
{
|
|
log_rule_B("indent_before_class_colon");
|
|
frm.top().SetIndentTmp(std::max<ptrdiff_t>(frm.top().GetIndentTmp() + options::indent_before_class_colon(), 0));
|
|
log_indent_tmp();
|
|
}
|
|
}
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
|
|
log_rule_B("indent_class_colon");
|
|
|
|
if ( options::indent_class_colon()
|
|
&& pc->Is(CT_CLASS_COLON))
|
|
{
|
|
log_rule_B("indent_class_on_colon");
|
|
|
|
if (options::indent_class_on_colon())
|
|
{
|
|
frm.top().SetIndent(pc->GetColumn());
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if ( next->IsNotNullChunk()
|
|
&& !next->IsNewline())
|
|
{
|
|
frm.top().SetIndent(next->GetColumn());
|
|
log_indent();
|
|
}
|
|
}
|
|
}
|
|
else if (pc->Is(CT_CONSTR_COLON))
|
|
{
|
|
if (options::indent_ignore_before_constr_colon())
|
|
{
|
|
log_rule_B("indent_ignore_before_constr_colon");
|
|
frm.top().SetIndentTmp(pc->GetOrigCol());
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
}
|
|
|
|
if (options::indent_constr_colon())
|
|
{
|
|
log_rule_B("indent_constr_colon");
|
|
Chunk *prev = pc->GetPrev();
|
|
|
|
if (prev->IsNewline())
|
|
{
|
|
log_rule_B("indent_ctor_init_following");
|
|
frm.top().SetIndent(frm.top().GetIndent() + options::indent_ctor_init_following());
|
|
log_indent();
|
|
}
|
|
// TODO: Create a dedicated indent_constr_on_colon?
|
|
log_rule_B("indent_class_on_colon");
|
|
|
|
if (options::indent_ctor_init() != 0)
|
|
{
|
|
log_rule_B("indent_ctor_init");
|
|
/*
|
|
* If the std::max() calls were specialized with size_t (the type of the underlying variable),
|
|
* they would never actually do their job, because size_t is unsigned and therefore even
|
|
* a "negative" result would be always greater than zero.
|
|
* Using ptrdiff_t (a standard signed type of the same size as size_t) in order to avoid that.
|
|
*/
|
|
frm.top().SetIndent(std::max<ptrdiff_t>(frm.top().GetIndent() + options::indent_ctor_init(), 0));
|
|
log_indent();
|
|
frm.top().SetIndentTmp(std::max<ptrdiff_t>(frm.top().GetIndentTmp() + options::indent_ctor_init(), 0));
|
|
frm.top().SetIndentTab(std::max<ptrdiff_t>(frm.top().GetIndentTab() + options::indent_ctor_init(), 0));
|
|
log_indent_tmp();
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
}
|
|
else if (options::indent_class_on_colon())
|
|
{
|
|
frm.top().SetIndent(pc->GetColumn());
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if ( next->IsNotNullChunk()
|
|
&& !next->IsNewline())
|
|
{
|
|
frm.top().SetIndent(next->GetColumn());
|
|
log_indent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_PAREN_OPEN)
|
|
&& ( pc->GetParentType() == CT_ASM
|
|
|| ( pc->GetPrevNcNnl()->IsNotNullChunk()
|
|
&& pc->GetPrevNcNnl()->GetType() == CT_ASM))
|
|
&& options::indent_ignore_asm_block())
|
|
{
|
|
log_rule_B("indent_ignore_asm_block");
|
|
Chunk *tmp = pc->GetClosingParen();
|
|
|
|
int move = 0;
|
|
|
|
if ( pc->GetPrev()->IsNewline()
|
|
&& pc->GetColumn() != indent_column)
|
|
{
|
|
move = indent_column - pc->GetColumn();
|
|
}
|
|
else
|
|
{
|
|
move = pc->GetColumn() - pc->GetOrigCol();
|
|
}
|
|
|
|
do
|
|
{
|
|
if (!pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
pc->SetColumn(pc->GetOrigCol() + move);
|
|
}
|
|
pc = pc->GetNext();
|
|
} while (pc != tmp);
|
|
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if ( ( pc->Is(CT_PAREN_OPEN)
|
|
|| pc->Is(CT_LPAREN_OPEN) // Issue #3054
|
|
|| pc->Is(CT_SPAREN_OPEN)
|
|
|| pc->Is(CT_FPAREN_OPEN)
|
|
|| pc->Is(CT_RPAREN_OPEN) // Issue #3914
|
|
|| pc->Is(CT_SQUARE_OPEN)
|
|
|| pc->Is(CT_ANGLE_OPEN))
|
|
&& ( !pc->TestFlags(PCF_CONT_LINE)
|
|
|| options::indent_continue() >= 0))
|
|
{
|
|
/*
|
|
* Open parenthesis and squares - never update indent_column,
|
|
* unless right after a newline.
|
|
*/
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
if ( pc->GetPrev()->IsNewline()
|
|
&& pc->GetColumn() != indent_column
|
|
&& !pc->TestFlags(PCF_DONT_INDENT))
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent => %zu, text is '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
frm.top().SetIndent(pc->GetColumn() + pc->Len());
|
|
log_indent();
|
|
|
|
if ( pc->Is(CT_SQUARE_OPEN)
|
|
&& language_is_set(LANG_D))
|
|
{
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
}
|
|
bool skipped = false;
|
|
log_rule_B("indent_inside_ternary_operator");
|
|
log_rule_B("indent_align_paren");
|
|
|
|
if ( options::indent_inside_ternary_operator()
|
|
&& ( pc->Is(CT_FPAREN_OPEN)
|
|
|| pc->Is(CT_PAREN_OPEN))
|
|
&& frm.size() > 2
|
|
&& ( frm.prev().GetOpenToken() == CT_QUESTION
|
|
|| frm.prev().GetOpenToken() == CT_COND_COLON)
|
|
&& !options::indent_align_paren())
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
log_indent();
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( ( pc->Is(CT_FPAREN_OPEN)
|
|
|| pc->Is(CT_ANGLE_OPEN))
|
|
&& ( ( options::indent_func_call_param()
|
|
&& ( pc->GetParentType() == CT_FUNC_CALL
|
|
|| pc->GetParentType() == CT_FUNC_CALL_USER))
|
|
|| ( options::indent_func_proto_param()
|
|
&& pc->GetParentType() == CT_FUNC_PROTO)
|
|
|| ( options::indent_func_class_param()
|
|
&& ( pc->GetParentType() == CT_FUNC_CLASS_DEF
|
|
|| pc->GetParentType() == CT_FUNC_CLASS_PROTO))
|
|
|| ( options::indent_template_param()
|
|
&& pc->GetParentType() == CT_TEMPLATE)
|
|
|| ( options::indent_func_ctor_var_param()
|
|
&& pc->GetParentType() == CT_FUNC_CTOR_VAR)
|
|
|| ( options::indent_func_def_param()
|
|
&& pc->GetParentType() == CT_FUNC_DEF)
|
|
|| ( !options::indent_func_def_param() // Issue #931
|
|
&& pc->GetParentType() == CT_FUNC_DEF
|
|
&& options::indent_func_def_param_paren_pos_threshold() > 0
|
|
&& pc->GetOrigCol() > options::indent_func_def_param_paren_pos_threshold())))
|
|
{
|
|
log_rule_B("indent_func_call_param");
|
|
log_rule_B("indent_func_proto_param");
|
|
log_rule_B("indent_func_class_param");
|
|
log_rule_B("indent_template_param");
|
|
log_rule_B("indent_func_ctor_var_param");
|
|
log_rule_B("indent_func_def_param");
|
|
log_rule_B("indent_func_def_param_paren_pos_threshold");
|
|
// Skip any continuation indents
|
|
size_t idx = (!frm.empty()) ? frm.size() - 2 : 0;
|
|
|
|
while ( ( ( idx > 0
|
|
&& frm.at(idx).GetOpenToken() != CT_BRACE_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_VBRACE_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_PAREN_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_FPAREN_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_RPAREN_OPEN // Issue #3914
|
|
&& frm.at(idx).GetOpenToken() != CT_SPAREN_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_SQUARE_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_ANGLE_OPEN
|
|
&& frm.at(idx).GetOpenToken() != CT_CASE
|
|
&& frm.at(idx).GetOpenToken() != CT_MEMBER
|
|
&& frm.at(idx).GetOpenToken() != CT_QUESTION
|
|
&& frm.at(idx).GetOpenToken() != CT_COND_COLON
|
|
&& frm.at(idx).GetOpenToken() != CT_LAMBDA
|
|
&& frm.at(idx).GetOpenToken() != CT_ASSIGN_NL)
|
|
|| frm.at(idx).GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk()))
|
|
&& ( frm.at(idx).GetOpenToken() != CT_CLASS_COLON
|
|
&& frm.at(idx).GetOpenToken() != CT_CONSTR_COLON
|
|
&& !( frm.at(idx).GetOpenToken() == CT_LAMBDA
|
|
&& frm.at(idx).GetOpenChunk()->GetPrevNc()->GetType() == CT_NEWLINE)))
|
|
{
|
|
if (idx == 0)
|
|
{
|
|
fprintf(stderr, "%s(%d): idx is ZERO, cannot be decremented, at line %zu, column %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol());
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
idx--;
|
|
skipped = true;
|
|
}
|
|
// PR#381
|
|
log_rule_B("indent_param");
|
|
|
|
if (options::indent_param() != 0)
|
|
{
|
|
frm.top().SetIndent(frm.at(idx).GetIndent() + options::indent_param());
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.at(idx).GetIndent() + indent_size);
|
|
log_indent();
|
|
}
|
|
log_rule_B("indent_func_param_double");
|
|
|
|
if (options::indent_func_param_double())
|
|
{
|
|
// double is: Use both values of the options indent_columns and indent_param
|
|
frm.top().SetIndent(frm.top().GetIndent() + indent_size);
|
|
log_indent();
|
|
}
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
}
|
|
else if ( options::indent_oc_inside_msg_sel()
|
|
&& pc->Is(CT_PAREN_OPEN)
|
|
&& frm.size() > 2
|
|
&& ( frm.prev().GetOpenToken() == CT_OC_MSG_FUNC
|
|
|| frm.prev().GetOpenToken() == CT_OC_MSG_NAME)
|
|
&& !options::indent_align_paren()) // Issue #2658
|
|
{
|
|
log_rule_B("indent_oc_inside_msg_sel");
|
|
log_rule_B("indent_align_paren");
|
|
// When parens are inside OC messages, push on the parse frame stack
|
|
// [Class Message:(<here>
|
|
frm.top().SetIndent(frm.prev().GetOpenChunk()->GetColumn() + indent_size);
|
|
log_indent();
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( pc->Is(CT_PAREN_OPEN)
|
|
&& !pc->GetNext()->IsNewline()
|
|
&& !options::indent_align_paren()
|
|
&& !pc->TestFlags(PCF_IN_SPAREN))
|
|
{
|
|
log_rule_B("indent_align_paren");
|
|
size_t idx = frm.size() - 2;
|
|
|
|
while ( idx > 0
|
|
&& frm.at(idx).GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk()))
|
|
{
|
|
idx--;
|
|
skipped = true;
|
|
}
|
|
frm.top().SetIndent(frm.at(idx).GetIndent() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
skipped = true;
|
|
}
|
|
else if ( ( pc->IsString("(")
|
|
&& !options::indent_paren_nl())
|
|
|| ( pc->IsString("<")
|
|
&& !options::indent_paren_nl()) // TODO: add indent_angle_nl?
|
|
|| ( pc->IsString("[")
|
|
&& !options::indent_square_nl()))
|
|
{
|
|
log_rule_B("indent_paren_nl");
|
|
log_rule_B("indent_square_nl");
|
|
Chunk *next = pc->GetNextNc();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
log_rule_B("indent_paren_after_func_def");
|
|
log_rule_B("indent_paren_after_func_decl");
|
|
log_rule_B("indent_paren_after_func_call");
|
|
|
|
if ( next->IsNewline()
|
|
&& !options::indent_paren_after_func_def()
|
|
&& !options::indent_paren_after_func_decl()
|
|
&& !options::indent_paren_after_func_call()
|
|
&& ( !pc->TestFlags(PCF_CONT_LINE)
|
|
|| options::indent_continue() >= 0))
|
|
{
|
|
size_t sub = 2;
|
|
|
|
if ( (frm.prev().GetOpenToken() == CT_ASSIGN)
|
|
|| (frm.prev().GetOpenToken() == CT_RETURN))
|
|
{
|
|
sub = 3;
|
|
}
|
|
sub = frm.size() - sub;
|
|
|
|
log_rule_B("indent_align_paren");
|
|
|
|
if (!options::indent_align_paren())
|
|
{
|
|
sub = frm.size() - 2;
|
|
|
|
while ( sub > 0
|
|
&& frm.at(sub).GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk()))
|
|
{
|
|
sub--;
|
|
skipped = true;
|
|
}
|
|
|
|
if ( ( frm.at(sub + 1).GetOpenToken() == CT_CLASS_COLON
|
|
|| frm.at(sub + 1).GetOpenToken() == CT_CONSTR_COLON)
|
|
&& (frm.at(sub + 1).GetOpenChunk()->GetPrev()->Is(CT_NEWLINE)))
|
|
{
|
|
sub = sub + 1;
|
|
}
|
|
}
|
|
frm.top().SetIndent(frm.at(sub).GetIndent() + indent_size);
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
skipped = true;
|
|
}
|
|
else
|
|
{
|
|
if ( next->IsNotNullChunk()
|
|
&& !next->IsComment())
|
|
{
|
|
if (next->Is(CT_SPACE))
|
|
{
|
|
next = next->GetNextNc();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (next->GetPrev()->IsComment())
|
|
{
|
|
// Issue #2099
|
|
frm.top().SetIndent(next->GetPrev()->GetColumn());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(next->GetColumn());
|
|
}
|
|
log_indent();
|
|
}
|
|
}
|
|
}
|
|
log_rule_B("use_indent_continue_only_once");
|
|
log_rule_B("indent_paren_after_func_decl");
|
|
log_rule_B("indent_paren_after_func_def");
|
|
log_rule_B("indent_paren_after_func_call");
|
|
|
|
if ( ( ( !frm.top().GetIndentContinue() // Issue #3567
|
|
&& vardefcol == 0)
|
|
|| ( !options::use_indent_continue_only_once() // Issue #1160
|
|
&& !options::indent_ignore_first_continue())) // Issue #3561
|
|
&& ( pc->Is(CT_FPAREN_OPEN)
|
|
&& pc->GetPrev()->IsNewline())
|
|
&& ( ( ( pc->GetParentType() == CT_FUNC_PROTO
|
|
|| pc->GetParentType() == CT_FUNC_CLASS_PROTO)
|
|
&& options::indent_paren_after_func_decl())
|
|
|| ( ( pc->GetParentType() == CT_FUNC_DEF
|
|
|| pc->GetParentType() == CT_FUNC_CLASS_DEF)
|
|
&& options::indent_paren_after_func_def())
|
|
|| ( ( pc->GetParentType() == CT_FUNC_CALL
|
|
|| pc->GetParentType() == CT_FUNC_CALL_USER)
|
|
&& options::indent_paren_after_func_call())
|
|
|| !pc->GetNext()->IsNewline()))
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
log_indent();
|
|
|
|
indent_column_set(frm.top().GetIndent());
|
|
}
|
|
log_rule_B("indent_continue");
|
|
|
|
if ( pc->GetParentType() != CT_OC_AT
|
|
&& ( options::indent_ignore_first_continue()
|
|
|| options::indent_continue() != 0)
|
|
&& !skipped)
|
|
{
|
|
if (options::indent_ignore_first_continue())
|
|
{
|
|
frm.top().SetIndent(get_indent_first_continue(pc->GetNext()));
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
}
|
|
log_indent();
|
|
|
|
if ( pc->GetLevel() == pc->GetBraceLevel()
|
|
&& !options::indent_ignore_first_continue()
|
|
&& ( pc->Is(CT_FPAREN_OPEN)
|
|
|| pc->Is(CT_RPAREN_OPEN) // Issue #1170
|
|
|| pc->Is(CT_SPAREN_OPEN)
|
|
|| ( pc->Is(CT_SQUARE_OPEN)
|
|
&& pc->GetParentType() != CT_OC_MSG)
|
|
|| pc->Is(CT_ANGLE_OPEN))) // Issue #1170
|
|
{
|
|
log_rule_B("use_indent_continue_only_once");
|
|
|
|
if ( (options::use_indent_continue_only_once())
|
|
&& (frm.top().GetIndentContinue())
|
|
&& vardefcol != 0)
|
|
{
|
|
/*
|
|
* The value of the indentation for a continuation line is calculate
|
|
* differently if the line is:
|
|
* a declaration :your case with QString fileName ...
|
|
* an assignment :your case with pSettings = new QSettings( ...
|
|
* At the second case the option value might be used twice:
|
|
* at the assignment
|
|
* at the function call (if present)
|
|
* If you want to prevent the double use of the option value
|
|
* you may use the new option :
|
|
* use_indent_continue_only_once
|
|
* with the value "true".
|
|
* use/don't use indent_continue once Guy 2016-05-16
|
|
*/
|
|
|
|
// if vardefcol isn't zero, use it
|
|
frm.top().SetIndent(vardefcol);
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(calc_indent_continue(frm));
|
|
log_indent();
|
|
frm.top().SetIndentContinue(true);
|
|
|
|
log_rule_B("indent_sparen_extra");
|
|
|
|
if ( pc->Is(CT_SPAREN_OPEN)
|
|
&& options::indent_sparen_extra() != 0)
|
|
{
|
|
frm.top().SetIndent(frm.top().GetIndent() + options::indent_sparen_extra());
|
|
log_indent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
frm.SetParenCount(frm.GetParenCount() + 1);
|
|
}
|
|
else if ( options::indent_member_single()
|
|
&& pc->Is(CT_MEMBER)
|
|
&& (strcmp(pc->Text(), ".") == 0)
|
|
&& language_is_set(LANG_CS | LANG_CPP))
|
|
{
|
|
log_rule_B("indent_member_single");
|
|
|
|
if (frm.top().GetOpenToken() != CT_MEMBER)
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
Chunk *tmp = frm.top().GetOpenChunk()->GetPrevNcNnlNpp();
|
|
|
|
if (frm.prev().GetOpenChunk()->IsOnSameLine(tmp))
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
}
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
|
|
if (pc->GetPrev()->IsNewline())
|
|
{
|
|
if ( pc->Is(CT_MEMBER) // Issue #2890
|
|
&& language_is_set(LANG_CPP))
|
|
{
|
|
// will be done at another place
|
|
// look at the comment: XXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
}
|
|
else
|
|
{
|
|
indent_column_set(frm.top().GetIndent());
|
|
reindent_line(pc, indent_column);
|
|
did_newline = false;
|
|
}
|
|
}
|
|
//check for the series of CT_member chunks else pop it.
|
|
Chunk *tmp = pc->GetNextNcNnlNpp();
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
if (tmp->Is(CT_FUNC_CALL))
|
|
{
|
|
tmp = tmp->GetNextType(CT_FPAREN_CLOSE, tmp->GetLevel());
|
|
tmp = tmp->GetNextNcNnlNpp();
|
|
}
|
|
else if ( tmp->Is(CT_WORD)
|
|
|| tmp->Is(CT_TYPE))
|
|
{
|
|
tmp = tmp->GetNextNcNnlNpp();
|
|
}
|
|
}
|
|
|
|
if ( tmp->IsNotNullChunk()
|
|
&& ( (strcmp(tmp->Text(), ".") != 0)
|
|
|| tmp->IsNot(CT_MEMBER)))
|
|
{
|
|
if (tmp->IsParenClose())
|
|
{
|
|
tmp = tmp->GetPrevNcNnlNpp();
|
|
}
|
|
Chunk *local_prev = tmp->GetPrev(); // Issue #3294
|
|
|
|
if (local_prev->IsComment())
|
|
{
|
|
tmp = tmp->GetPrev(); // Issue #3294
|
|
}
|
|
|
|
if ( tmp->IsNotNullChunk()
|
|
&& tmp->GetPrev()->IsNewline())
|
|
{
|
|
tmp = tmp->GetPrevNcNnlNpp()->GetNextNl();
|
|
}
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
frm.top().SetPopChunk(tmp);
|
|
}
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_ASSIGN)
|
|
|| pc->Is(CT_IMPORT)
|
|
|| ( pc->Is(CT_USING)
|
|
&& language_is_set(LANG_CS)))
|
|
{
|
|
/*
|
|
* if there is a newline after the '=' or the line starts with a '=',
|
|
* just indent one level,
|
|
* otherwise align on the '='.
|
|
*/
|
|
if ( pc->Is(CT_ASSIGN)
|
|
&& pc->GetPrev()->IsNewline())
|
|
{
|
|
if (frm.top().GetOpenToken() == CT_ASSIGN_NL)
|
|
{
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndentTmp(frm.top().GetIndent() + indent_size);
|
|
}
|
|
log_indent_tmp();
|
|
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] assign => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, frm.top().GetIndentTmp());
|
|
}
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if (next->IsNotNullChunk())
|
|
{
|
|
/*
|
|
* fixes 1260 , 1268 , 1277 (Extra indentation after line with multiple assignments)
|
|
* For multiple consecutive assignments in single line , the indent of all these
|
|
* assignments should be same and one more than this line's indent.
|
|
* so popping the previous assign and pushing the new one
|
|
*/
|
|
if ( frm.top().GetOpenToken() == CT_ASSIGN
|
|
&& pc->Is(CT_ASSIGN))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
if ( pc->Is(CT_ASSIGN)
|
|
&& pc->GetPrev()->IsNewline())
|
|
{
|
|
frm.top().SetOpenToken(CT_ASSIGN_NL);
|
|
}
|
|
log_rule_B("indent_continue");
|
|
|
|
if (options::indent_ignore_first_continue())
|
|
{
|
|
frm.top().SetIndent(get_indent_first_continue(pc));
|
|
log_indent();
|
|
frm.top().SetIndentContinue(true); // Issue #3567
|
|
}
|
|
else if (options::indent_continue() != 0)
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
log_indent();
|
|
|
|
if ( pc->GetLevel() == pc->GetBraceLevel()
|
|
&& ( pc->IsNot(CT_ASSIGN)
|
|
|| ( pc->GetParentType() != CT_FUNC_PROTO
|
|
&& pc->GetParentType() != CT_FUNC_DEF)))
|
|
{
|
|
log_rule_B("use_indent_continue_only_once");
|
|
|
|
if ( (options::use_indent_continue_only_once())
|
|
&& (frm.top().GetIndentContinue())
|
|
&& vardefcol != 0)
|
|
{
|
|
// if vardefcol isn't zero, use it
|
|
frm.top().SetIndent(vardefcol);
|
|
log_indent();
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(calc_indent_continue(frm));
|
|
log_indent();
|
|
|
|
vardefcol = frm.top().GetIndent(); // use the same variable for the next line
|
|
frm.top().SetIndentContinue(true);
|
|
}
|
|
}
|
|
}
|
|
else if ( next->IsNewline()
|
|
|| !options::indent_align_assign())
|
|
{
|
|
log_rule_B("indent_align_assign");
|
|
log_rule_B("indent_off_after_assign");
|
|
|
|
if (options::indent_off_after_assign()) // Issue #2591
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp());
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndentTmp() + indent_size);
|
|
}
|
|
log_indent();
|
|
|
|
if ( pc->Is(CT_ASSIGN)
|
|
&& next->IsNewline())
|
|
{
|
|
frm.top().SetOpenToken(CT_ASSIGN_NL);
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(pc->GetColumn() + pc->Len() + 1);
|
|
log_indent();
|
|
}
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_RETURN)
|
|
|| ( pc->Is(CT_THROW)
|
|
&& pc->GetParentType() == CT_NONE))
|
|
{
|
|
// don't count returns inside a () or []
|
|
if ( pc->GetLevel() == pc->GetBraceLevel()
|
|
|| pc->TestFlags(PCF_IN_LAMBDA))
|
|
{
|
|
Chunk *next = pc->GetNext();
|
|
|
|
// Avoid indentation on return token set by the option.
|
|
log_rule_B("indent_off_after_return");
|
|
|
|
// Avoid indentation on return token if the next token is a new token
|
|
// to properly indent object initializers returned by functions.
|
|
log_rule_B("indent_off_after_return_new");
|
|
bool indent_after_return = ( next->IsNotNullChunk()
|
|
&& next->GetType() == CT_NEW)
|
|
? !options::indent_off_after_return_new()
|
|
: !options::indent_off_after_return();
|
|
|
|
if ( indent_after_return
|
|
|| next->IsNullChunk())
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
log_rule_B("indent_single_after_return");
|
|
|
|
if ( next->IsNewline()
|
|
|| ( pc->Is(CT_RETURN)
|
|
&& options::indent_single_after_return()))
|
|
{
|
|
// apply normal single indentation
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
}
|
|
else
|
|
{
|
|
// indent after the return token
|
|
frm.top().SetIndent(frm.prev().GetIndent() + pc->Len() + 1);
|
|
}
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.prev().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
log_indent();
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_OC_SCOPE)
|
|
|| pc->Is(CT_TYPEDEF))
|
|
{
|
|
frm.push(pc, __func__, __LINE__);
|
|
// Issue #405
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
LOG_FMT(LINDLINE, "%s(%d): .indent is %zu, .indent_tmp is %zu\n",
|
|
__func__, __LINE__, frm.top().GetIndent(), frm.top().GetIndentTmp());
|
|
|
|
log_rule_B("indent_continue");
|
|
|
|
if (options::indent_ignore_first_continue())
|
|
{
|
|
frm.top().SetIndent(get_indent_first_continue(pc));
|
|
log_indent();
|
|
}
|
|
else if (options::indent_continue() != 0)
|
|
{
|
|
frm.top().SetIndent(calc_indent_continue(frm, frm.size() - 2));
|
|
log_indent();
|
|
|
|
frm.top().SetIndentContinue(true);
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
log_indent();
|
|
}
|
|
}
|
|
else if (pc->Is(CT_C99_MEMBER))
|
|
{
|
|
// nothing to do
|
|
}
|
|
else if (pc->Is(CT_WHERE_SPEC))
|
|
{
|
|
/* class indentation is ok already, just need to adjust func */
|
|
/* TODO: make this configurable, obviously.. */
|
|
if ( pc->GetParentType() == CT_FUNC_DEF
|
|
|| pc->GetParentType() == CT_FUNC_PROTO
|
|
|| ( pc->GetParentType() == CT_STRUCT
|
|
&& frm.top().GetOpenToken() != CT_CLASS_COLON))
|
|
{
|
|
indent_column_set(frm.top().GetIndent() + 4);
|
|
}
|
|
}
|
|
else if ( options::indent_inside_ternary_operator()
|
|
&& ( pc->Is(CT_QUESTION)
|
|
|| pc->Is(CT_COND_COLON))) // Issue #1130, #1715
|
|
{
|
|
log_rule_B("indent_inside_ternary_operator");
|
|
|
|
// Pop any colons before because they should already be processed
|
|
while ( pc->Is(CT_COND_COLON)
|
|
&& frm.top().GetOpenToken() == CT_COND_COLON)
|
|
{
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
log_rule_B("indent_inside_ternary_operator");
|
|
|
|
// Pop Question from stack in ternary operator
|
|
if ( options::indent_inside_ternary_operator()
|
|
&& pc->Is(CT_COND_COLON)
|
|
&& frm.top().GetOpenToken() == CT_QUESTION)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
indent_column_set(frm.top().GetIndentTmp());
|
|
}
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( pc->Is(CT_LAMBDA)
|
|
&& (language_is_set(LANG_CS | LANG_JAVA))
|
|
&& pc->GetNextNcNnlNpp()->IsNot(CT_BRACE_OPEN)
|
|
&& options::indent_cs_delegate_body())
|
|
{
|
|
log_rule_B("indent_cs_delegate_body");
|
|
frm.push(pc, __func__, __LINE__);
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
log_indent();
|
|
|
|
if ( pc->GetPrevNc()->IsNewline()
|
|
&& !frm.prev().GetOpenChunk()->IsOnSameLine(pc->GetPrevNcNnl()))
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
log_indent();
|
|
reindent_line(pc, (frm.prev().GetIndent() + indent_size));
|
|
did_newline = false;
|
|
}
|
|
else if ( pc->GetNextNc()->IsNewline()
|
|
&& !frm.prev().GetOpenChunk()->IsOnSameLine(frm.top().GetOpenChunk()))
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + indent_size);
|
|
}
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
}
|
|
else if ( options::indent_oc_inside_msg_sel()
|
|
&& ( pc->Is(CT_OC_MSG_FUNC)
|
|
|| pc->Is(CT_OC_MSG_NAME))
|
|
&& pc->GetNextNcNnl()->Is(CT_OC_COLON)) // Issue #2658
|
|
{
|
|
log_rule_B("indent_oc_inside_msg_sel");
|
|
// Pop the OC msg name that is on the top of the stack
|
|
// [Class Message:<here>
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
frm.top().SetIndent(frm.prev().GetIndent());
|
|
frm.top().SetIndentTab(frm.prev().GetIndentTab());
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.prev().GetIndentTmp());
|
|
log_indent_tmp();
|
|
}
|
|
else if (pc->IsComment())
|
|
{
|
|
// Issue #3294
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if (next->Is(CT_COND_COLON))
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): Comment and COND_COLON: pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
// uncomment the line below to get debug info
|
|
// #define ANYTHING_ELSE
|
|
#ifdef ANYTHING_ELSE
|
|
else
|
|
{
|
|
// anything else?
|
|
// Issue #3294
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
LOG_FMT(LSPACE, "\n\n%s(%d): WARNING: unrecognize indent_text:\n",
|
|
__func__, __LINE__);
|
|
}
|
|
#endif /* ANYTHING_ELSE */
|
|
}
|
|
else
|
|
{
|
|
// anything else?
|
|
#ifdef ANYTHING_ELSE
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
LOG_FMT(LSPACE, "\n\n%s(%d): WARNING: unrecognize indent_text:\n",
|
|
__func__, __LINE__);
|
|
#endif /* ANYTHING_ELSE */
|
|
}
|
|
// Handle shift expression continuation indenting
|
|
size_t shiftcontcol = 0;
|
|
|
|
log_rule_B("indent_shift");
|
|
|
|
if ( options::indent_shift() == 1
|
|
&& !pc->TestFlags(PCF_IN_ENUM)
|
|
&& pc->GetParentType() != CT_OPERATOR
|
|
&& !pc->IsComment()
|
|
&& pc->IsNot(CT_BRACE_OPEN)
|
|
&& pc->GetLevel() > 0
|
|
&& !pc->IsEmptyText())
|
|
{
|
|
bool in_shift = false;
|
|
bool is_operator = false;
|
|
|
|
// Are we in such an expression? Go both forwards and backwards.
|
|
Chunk *tmp = pc;
|
|
|
|
do
|
|
{
|
|
if (tmp->Is(CT_SHIFT))
|
|
{
|
|
in_shift = true;
|
|
LOG_FMT(LINDENT2, "%s(%d): in_shift set to TRUE\n",
|
|
__func__, __LINE__);
|
|
|
|
tmp = tmp->GetPrevNcNnl();
|
|
|
|
if (tmp->Is(CT_OPERATOR))
|
|
{
|
|
is_operator = true;
|
|
}
|
|
break;
|
|
}
|
|
tmp = tmp->GetPrevNcNnl();
|
|
} while ( !in_shift
|
|
&& tmp->IsNotNullChunk()
|
|
&& tmp->IsNot(CT_SEMICOLON)
|
|
&& tmp->IsNot(CT_BRACE_OPEN)
|
|
&& tmp->IsNot(CT_BRACE_CLOSE)
|
|
&& tmp->IsNot(CT_COMMA)
|
|
&& tmp->IsNot(CT_SPAREN_OPEN)
|
|
&& tmp->IsNot(CT_SPAREN_CLOSE));
|
|
|
|
tmp = pc;
|
|
|
|
do
|
|
{
|
|
tmp = tmp->GetNextNcNnl();
|
|
|
|
if ( tmp->IsNotNullChunk()
|
|
&& tmp->Is(CT_SHIFT))
|
|
{
|
|
in_shift = true;
|
|
LOG_FMT(LINDENT2, "%s(%d): in_shift set to TRUE\n",
|
|
__func__, __LINE__);
|
|
|
|
tmp = tmp->GetPrevNcNnl();
|
|
|
|
if (tmp->Is(CT_OPERATOR))
|
|
{
|
|
is_operator = true;
|
|
}
|
|
break;
|
|
}
|
|
} while ( !in_shift
|
|
&& tmp->IsNotNullChunk()
|
|
&& tmp->IsNot(CT_SEMICOLON)
|
|
&& tmp->IsNot(CT_BRACE_OPEN)
|
|
&& tmp->IsNot(CT_BRACE_CLOSE)
|
|
&& tmp->IsNot(CT_COMMA)
|
|
&& tmp->IsNot(CT_SPAREN_OPEN)
|
|
&& tmp->IsNot(CT_SPAREN_CLOSE));
|
|
|
|
LOG_FMT(LINDENT2, "%s(%d): in_shift is %s\n",
|
|
__func__, __LINE__, in_shift ? "TRUE" : "FALSE");
|
|
Chunk *prev_nonl = pc->GetPrevNcNnl();
|
|
Chunk *prev2 = pc->GetPrevNc();
|
|
|
|
if (( prev_nonl->IsSemicolon()
|
|
|| prev_nonl->IsBraceOpen()
|
|
|| prev_nonl->IsBraceClose()
|
|
|| prev_nonl->Is(CT_CASE_COLON)
|
|
|| ( prev_nonl->IsNotNullChunk()
|
|
&& prev_nonl->TestFlags(PCF_IN_PREPROC)) != pc->TestFlags(PCF_IN_PREPROC)
|
|
|| prev_nonl->Is(CT_COMMA)
|
|
|| is_operator))
|
|
{
|
|
in_shift = false;
|
|
}
|
|
LOG_FMT(LINDENT2, "%s(%d): in_shift is %s\n",
|
|
__func__, __LINE__, in_shift ? "TRUE" : "FALSE");
|
|
|
|
if ( prev2->Is(CT_NEWLINE)
|
|
&& in_shift)
|
|
{
|
|
shiftcontcol = calc_indent_continue(frm);
|
|
// Calling frm.top().SetIndentContinue(true) in the top context when the indent is not also set
|
|
// just leads to complications when succeeding statements try to indent based on being
|
|
// embedded in a continuation. In other words setting frm.top().SetIndentContinue(true)
|
|
// should only be set if frm.top().indent is also set.
|
|
|
|
// Work around the doubly increased indent in RETURNs and assignments
|
|
bool need_workaround = false;
|
|
size_t sub = 0;
|
|
|
|
for (int i = frm.size() - 1; i >= 0; i--)
|
|
{
|
|
if ( frm.at(i).GetOpenToken() == CT_RETURN
|
|
|| frm.at(i).GetOpenToken() == CT_ASSIGN)
|
|
{
|
|
need_workaround = true;
|
|
sub = frm.size() - i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (need_workaround)
|
|
{
|
|
shiftcontcol = calc_indent_continue(frm, frm.size() - 1 - sub);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle variable definition continuation indenting
|
|
if ( vardefcol == 0
|
|
&& ( pc->Is(CT_WORD)
|
|
|| pc->Is(CT_FUNC_CTOR_VAR))
|
|
&& !pc->TestFlags(PCF_IN_FCN_DEF)
|
|
&& pc->TestFlags(PCF_VAR_1ST_DEF))
|
|
{
|
|
log_rule_B("indent_continue");
|
|
|
|
if (options::indent_ignore_first_continue())
|
|
{
|
|
vardefcol = get_indent_first_continue(pc);
|
|
}
|
|
else if (options::indent_continue() != 0)
|
|
{
|
|
vardefcol = calc_indent_continue(frm);
|
|
// Calling frm.top().SetIndentContinue(true) in the top context when the indent is not also set
|
|
// just leads to complications when succeeding statements try to indent based on being
|
|
// embedded in a continuation. In other words setting frm.top().SetIndentContinue(true)
|
|
// should only be set if frm.top().indent is also set.
|
|
}
|
|
else if ( options::indent_var_def_cont()
|
|
|| pc->GetPrev()->IsNewline())
|
|
{
|
|
log_rule_B("indent_var_def_cont");
|
|
vardefcol = frm.top().GetIndent() + indent_size;
|
|
}
|
|
else
|
|
{
|
|
// Issue #3010
|
|
vardefcol = pc->GetColumn();
|
|
// BUT, we need to skip backward over any '*'
|
|
Chunk *tmp = pc->GetPrevNc();
|
|
|
|
while (tmp->Is(CT_PTR_TYPE))
|
|
{
|
|
vardefcol = tmp->GetColumn();
|
|
tmp = tmp->GetPrevNc();
|
|
}
|
|
// BUT, we need to skip backward over any '::' or TYPE
|
|
//tmp = pc->GetPrevNc();
|
|
|
|
//if (tmp->Is(CT_DC_MEMBER))
|
|
//{
|
|
// // look for a type
|
|
// Chunk *tmp2 = tmp->GetPrevNc();
|
|
// if (tmp2->Is(CT_TYPE))
|
|
// {
|
|
// // we have something like "SomeLongNamespaceName::Foo()"
|
|
// vardefcol = tmp2->GetColumn();
|
|
// LOG_FMT(LINDENT, "%s(%d): orig line is %zu, vardefcol is %zu\n",
|
|
// __func__, __LINE__, pc->GetOrigLine(), vardefcol);
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
|
|
if ( pc->IsSemicolon()
|
|
|| ( pc->Is(CT_BRACE_OPEN)
|
|
&& ( pc->GetParentType() == CT_FUNCTION
|
|
|| pc->GetParentType() == CT_CLASS))) //Issue #3576
|
|
{
|
|
vardefcol = 0;
|
|
}
|
|
|
|
// Indent the line if needed
|
|
if ( did_newline
|
|
&& !pc->IsNewline()
|
|
&& (pc->Len() != 0))
|
|
{
|
|
if ( pc->TestFlags(PCF_CONT_LINE)
|
|
&& options::indent_continue() < 0)
|
|
{
|
|
log_rule_B("indent_continue");
|
|
indent_column = calc_indent_continue(frm);
|
|
log_indent();
|
|
}
|
|
pc->SetColumnIndent(frm.top().GetIndentTab());
|
|
|
|
if (frm.top().GetIndentData().ref)
|
|
{
|
|
pc->IndentData().ref = frm.top().GetIndentData().ref;
|
|
pc->IndentData().delta = frm.top().GetIndentData().delta;
|
|
}
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, pc->GetColumn() indent is %zu, indent_column is %zu, for '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetColumnIndent(), indent_column, pc->ElidedText(copy));
|
|
|
|
/*
|
|
* Check for special continuations.
|
|
* Note that some of these could be done as a stack item like
|
|
* everything else
|
|
*/
|
|
|
|
Chunk *prev = pc->GetPrevNcNnl();
|
|
Chunk *prevv = prev->GetPrevNcNnl();
|
|
Chunk *next = pc->GetNextNcNnl();
|
|
|
|
bool do_vardefcol = false;
|
|
|
|
if ( vardefcol > 0
|
|
&& pc->GetLevel() == pc->GetBraceLevel()
|
|
&& ( prev->Is(CT_COMMA)
|
|
|| prev->Is(CT_TYPE)
|
|
|| prev->Is(CT_PTR_TYPE)
|
|
|| prev->Is(CT_WORD)))
|
|
{
|
|
Chunk *tmp = pc;
|
|
|
|
while (tmp->Is(CT_PTR_TYPE))
|
|
{
|
|
tmp = tmp->GetNextNcNnl();
|
|
}
|
|
LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, for '%s'",
|
|
__func__, __LINE__, tmp->GetOrigLine(), tmp->Text());
|
|
LOG_FMT(LINDENT2, " tmp->GetFlags(): ");
|
|
log_pcf_flags(LINDENT2, tmp->GetFlags()); // Issue #2332
|
|
|
|
if ( tmp->TestFlags(PCF_VAR_DEF)
|
|
&& ( tmp->Is(CT_WORD)
|
|
|| tmp->Is(CT_FUNC_CTOR_VAR)))
|
|
{
|
|
do_vardefcol = true;
|
|
}
|
|
}
|
|
//LOG_FMT(LINDENT2, "%s(%d): GUY 2:\n", __func__, __LINE__);
|
|
|
|
if (pc->TestFlags(PCF_DONT_INDENT))
|
|
{
|
|
// no change
|
|
}
|
|
else if ( pc->GetParentType() == CT_SQL_EXEC
|
|
&& options::indent_preserve_sql())
|
|
{
|
|
log_rule_B("indent_preserve_sql");
|
|
reindent_line(pc, sql_col + (pc->GetOrigCol() - sql_orig_col));
|
|
LOG_FMT(LINDENT, "Indent SQL: [%s] to %zu (%zu/%zu)\n",
|
|
pc->Text(), pc->GetColumn(), sql_col, sql_orig_col);
|
|
}
|
|
else if ( !options::indent_member_single()
|
|
&& !pc->TestFlags(PCF_STMT_START)
|
|
&& ( pc->Is(CT_MEMBER)
|
|
|| ( pc->Is(CT_DC_MEMBER)
|
|
&& prev->Is(CT_TYPE))
|
|
|| ( prev->Is(CT_MEMBER)
|
|
|| ( prev->Is(CT_DC_MEMBER)
|
|
&& prevv->Is(CT_TYPE)))))
|
|
{
|
|
log_rule_B("indent_member_single");
|
|
log_rule_B("indent_member");
|
|
size_t tmp = options::indent_member() + indent_column;
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, member => %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), tmp);
|
|
reindent_line(pc, tmp);
|
|
}
|
|
else if (do_vardefcol)
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, vardefcol is %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), vardefcol);
|
|
reindent_line(pc, vardefcol);
|
|
}
|
|
else if (shiftcontcol > 0)
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, shiftcontcol is %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), shiftcontcol);
|
|
reindent_line(pc, shiftcontcol);
|
|
}
|
|
else if ( pc->Is(CT_NAMESPACE)
|
|
&& options::indent_namespace()
|
|
&& options::indent_namespace_single_indent()
|
|
&& frm.top().GetNsCount())
|
|
{
|
|
log_rule_B("indent_namespace");
|
|
log_rule_B("indent_namespace_single_indent");
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, Namespace => %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), frm.top().GetBraceIndent());
|
|
reindent_line(pc, frm.top().GetBraceIndent());
|
|
}
|
|
else if ( pc->Is(CT_STRING)
|
|
&& prev->Is(CT_STRING)
|
|
&& options::indent_align_string())
|
|
{
|
|
log_rule_B("indent_align_string");
|
|
const int tmp = (xml_indent != 0) ? xml_indent : prev->GetColumn();
|
|
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, String => %d\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), tmp);
|
|
reindent_line(pc, tmp);
|
|
}
|
|
else if (pc->IsComment())
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, comment => %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), frm.top().GetIndentTmp());
|
|
indent_comment(pc, frm.top().GetIndentTmp());
|
|
}
|
|
else if (pc->Is(CT_PREPROC))
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, pp-indent => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if ( pc->IsParenClose()
|
|
|| pc->Is(CT_ANGLE_CLOSE))
|
|
{
|
|
/*
|
|
* This is a big hack. We assume that since we hit a paren close,
|
|
* that we just removed a paren open
|
|
*/
|
|
LOG_FMT(LINDLINE, "%s(%d): indent_column is %zu\n",
|
|
__func__, __LINE__, indent_column);
|
|
|
|
if (frm.lastPopped().GetOpenToken() == E_Token(pc->GetType() - 1))
|
|
{
|
|
// Issue # 405
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
Chunk *ck1 = frm.lastPopped().GetOpenChunk();
|
|
LOG_FMT(LINDLINE, "%s(%d): ck1 orig line is %zu, orig col is %zu, Text() is '%s', GetType() is %s\n",
|
|
__func__, __LINE__, ck1->GetOrigLine(), ck1->GetOrigCol(), ck1->Text(), get_token_name(ck1->GetType()));
|
|
Chunk *ck2 = ck1->GetPrev();
|
|
LOG_FMT(LINDLINE, "%s(%d): ck2 orig line is %zu, orig col is %zu, Text() is '%s', GetType() is %s\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), ck2->Text(), get_token_name(ck2->GetType()));
|
|
|
|
log_rule_B("indent_paren_close");
|
|
|
|
if (options::indent_paren_close() == -1)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is -1\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol());
|
|
indent_column_set(pc->GetOrigCol());
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column);
|
|
}
|
|
else if ( ck2->IsNewline()
|
|
|| (options::indent_paren_close() == 1))
|
|
{
|
|
/*
|
|
* If the open parenthesis was the first thing on the line or we
|
|
* are doing mode 1, then put the close parenthesis in the same
|
|
* column
|
|
*/
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is 1\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol());
|
|
indent_column_set(ck1->GetColumn());
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column);
|
|
}
|
|
else
|
|
{
|
|
if (options::indent_paren_close() != 2)
|
|
{
|
|
// indent_paren_close is 0 or 1
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is 0 or 1\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol());
|
|
indent_column_set(frm.lastPopped().GetIndentTmp());
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column);
|
|
pc->SetColumnIndent(frm.lastPopped().GetIndentTab());
|
|
log_rule_B("indent_paren_close");
|
|
|
|
if (options::indent_paren_close() == 1)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is 1\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol());
|
|
|
|
if (indent_column == 0)
|
|
{
|
|
fprintf(stderr, "%s(%d): indent_column is ZERO, cannot be decremented, at line %zu, column %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol());
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
indent_column--;
|
|
LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// indent_paren_close is 2: Indent to the brace level
|
|
LOG_FMT(LINDLINE, "%s(%d): indent_paren_close is 2\n",
|
|
__func__, __LINE__);
|
|
LOG_FMT(LINDLINE, "%s(%d): ck2 orig line is %zu, orig col is %zu, ck2->Text() is '%s'\n",
|
|
__func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), ck2->Text());
|
|
|
|
if (pc->GetPrev()->GetType() == CT_NEWLINE)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
LOG_FMT(LINDLINE, "%s(%d): prev is <newline>\n",
|
|
__func__, __LINE__);
|
|
Chunk *search = pc;
|
|
|
|
while (search->GetNext()->IsParenClose())
|
|
{
|
|
search = search->GetNext();
|
|
}
|
|
Chunk *searchNext = search->GetNext();
|
|
|
|
// Issue #3407 - Skip over a possible 'noexcept' keyword before going forward.
|
|
if (searchNext->GetType() == CT_NOEXCEPT)
|
|
{
|
|
searchNext = searchNext->GetNext();
|
|
}
|
|
|
|
if ( searchNext->GetType() == CT_SEMICOLON
|
|
|| searchNext->GetType() == CT_MEMBER // Issue #2582
|
|
|| searchNext->GetType() == CT_NEWLINE)
|
|
{
|
|
LOG_FMT(LINDLINE, "%s(%d):\n", __func__, __LINE__);
|
|
search = search->GetOpeningParen();
|
|
|
|
if ( options::indent_oc_inside_msg_sel()
|
|
&& search->GetPrevNcNnl()->Is(CT_OC_COLON)
|
|
&& ( frm.top().GetOpenToken() == CT_OC_MSG_FUNC
|
|
|| frm.top().GetOpenToken() == CT_OC_MSG_NAME)) // Issue #2658
|
|
{
|
|
log_rule_B("indent_oc_inside_msg_sel");
|
|
// [Class Message:(...)<here>
|
|
indent_column_set(frm.top().GetOpenChunk()->GetColumn());
|
|
}
|
|
else if ( options::indent_inside_ternary_operator()
|
|
&& ( frm.top().GetOpenToken() == CT_QUESTION
|
|
|| frm.top().GetOpenToken() == CT_COND_COLON)) // Issue #1130, #1715
|
|
{
|
|
log_rule_B("indent_inside_ternary_operator");
|
|
indent_column_set(frm.top().GetIndent());
|
|
}
|
|
else
|
|
{
|
|
search = search->GetPrevNl()->GetNext();
|
|
|
|
if (search->IsNullChunk())
|
|
{
|
|
search = Chunk::GetHead();
|
|
}
|
|
indent_column_set(search->GetColumn());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
size_t indent_value = 0;
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, closing parenthesis => %zu, text is '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
LOG_FMT(LINDENT, "%s(%d): [%s/%s]\n",
|
|
__func__, __LINE__,
|
|
get_token_name(pc->GetType()), get_token_name(pc->GetParentType()));
|
|
Chunk *prev2 = pc->GetPrev(); // Issue #2930
|
|
LOG_FMT(LINDENT, "%s(%d): prev2 is orig line is %zu, text is '%s'\n",
|
|
__func__, __LINE__, prev2->GetOrigLine(), prev2->Text());
|
|
Chunk *next2 = pc->GetNext();
|
|
LOG_FMT(LINDENT, "%s(%d): next2 is orig line is %zu, text is '%s'\n",
|
|
__func__, __LINE__, next2->GetOrigLine(), next2->Text());
|
|
|
|
if ( pc->GetParentType() == CT_FUNC_DEF
|
|
&& prev2->IsNewline()
|
|
&& next2->IsNewline())
|
|
{
|
|
if (options::donot_indent_func_def_close_paren())
|
|
{
|
|
indent_value = 1;
|
|
}
|
|
else
|
|
{
|
|
reindent_line(pc, indent_column);
|
|
indent_value = indent_column;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
indent_value = indent_column;
|
|
}
|
|
reindent_line(pc, indent_value);
|
|
}
|
|
else if (pc->Is(CT_COMMA))
|
|
{
|
|
bool indent_align = false;
|
|
bool indent_ignore = false;
|
|
|
|
if (frm.top().GetOpenChunk()->IsParenOpen())
|
|
{
|
|
log_rule_B("indent_comma_paren");
|
|
indent_align = options::indent_comma_paren() == (int)indent_mode_e::ALIGN;
|
|
indent_ignore = options::indent_comma_paren() == (int)indent_mode_e::IGNORE;
|
|
}
|
|
else if (frm.top().GetOpenChunk()->IsBraceOpen())
|
|
{
|
|
log_rule_B("indent_comma_brace");
|
|
indent_align = options::indent_comma_brace() == (int)indent_mode_e::ALIGN;
|
|
indent_ignore = options::indent_comma_brace() == (int)indent_mode_e::IGNORE;
|
|
}
|
|
|
|
if (indent_ignore)
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
else if (indent_align)
|
|
{
|
|
indent_column_set(frm.top().GetOpenChunk()->GetColumn());
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] comma => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if ( options::indent_func_const()
|
|
&& pc->Is(CT_QUALIFIER)
|
|
&& strncasecmp(pc->Text(), "const", pc->Len()) == 0
|
|
&& ( next->Is(CT_BRACED)
|
|
|| next->IsBraceOpen()
|
|
|| next->Is(CT_NEWLINE)
|
|
|| next->Is(CT_SEMICOLON)
|
|
|| next->Is(CT_THROW)))
|
|
{
|
|
// indent const - void GetFoo(void)\n const\n { return (m_Foo); }
|
|
log_rule_B("indent_func_const");
|
|
indent_column_set(frm.top().GetIndent() + options::indent_func_const());
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] const => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if ( options::indent_func_throw()
|
|
&& pc->Is(CT_THROW)
|
|
&& pc->GetParentType() != CT_NONE)
|
|
{
|
|
// indent throw - void GetFoo(void)\n throw()\n { return (m_Foo); }
|
|
log_rule_B("indent_func_throw");
|
|
indent_column_set(options::indent_func_throw());
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] throw => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if (pc->Is(CT_SEMICOLON))
|
|
{
|
|
if ( pc->TestFlags(PCF_IN_FOR)
|
|
&& options::indent_semicolon_for_paren())
|
|
{
|
|
log_rule_B("indent_semicolon_for_paren");
|
|
indent_column_set(frm.top().GetOpenChunk()->GetColumn());
|
|
|
|
log_rule_B("indent_first_for_expr");
|
|
|
|
if (options::indent_first_for_expr())
|
|
{
|
|
reindent_line(frm.top().GetOpenChunk()->GetNext(),
|
|
indent_column + pc->Len() + 1);
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] SEMICOLON => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else
|
|
{
|
|
log_rule_B("indent_ignore_semicolon");
|
|
|
|
if (options::indent_ignore_semicolon())
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] semicolon => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
}
|
|
else if (pc->Is(CT_BOOL))
|
|
{
|
|
if (frm.top().GetOpenChunk()->IsParenOpen())
|
|
{
|
|
log_rule_B("indent_bool_paren");
|
|
|
|
if (options::indent_bool_paren() == (int)indent_mode_e::IGNORE)
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
else if (options::indent_bool_paren() == (int)indent_mode_e::ALIGN)
|
|
{
|
|
indent_column_set(frm.top().GetOpenChunk()->GetColumn());
|
|
|
|
log_rule_B("indent_first_bool_expr");
|
|
|
|
if (options::indent_first_bool_expr())
|
|
{
|
|
reindent_line(frm.top().GetOpenChunk()->GetNext(),
|
|
indent_column + pc->Len() + 1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_rule_B("indent_ignore_bool");
|
|
|
|
if (options::indent_ignore_bool())
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] bool => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if ( pc->Is(CT_ARITH)
|
|
|| pc->Is(CT_CARET))
|
|
{
|
|
log_rule_B("indent_ignore_arith");
|
|
|
|
if (options::indent_ignore_arith())
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] arith => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if (pc->Is(CT_SHIFT))
|
|
{
|
|
log_rule_B("indent_shift");
|
|
|
|
if (options::indent_shift() == -1)
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] shift => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if (pc->Is(CT_ASSIGN))
|
|
{
|
|
log_rule_B("indent_ignore_assign");
|
|
|
|
if (options::indent_ignore_assign())
|
|
{
|
|
indent_column_set(pc->GetOrigCol());
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] assign => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else if ( options::indent_ternary_operator() == 1
|
|
&& prev->Is(CT_COND_COLON))
|
|
{
|
|
log_rule_B("indent_ternary_operator");
|
|
Chunk *tmp = prev->GetPrevType(CT_QUESTION);
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
tmp = tmp->GetNextNcNnl();
|
|
|
|
if (tmp->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LINDENT, "%s: %zu] ternarydefcol => %zu [%s]\n",
|
|
__func__, pc->GetOrigLine(), tmp->GetColumn(), pc->Text());
|
|
reindent_line(pc, tmp->GetColumn());
|
|
}
|
|
}
|
|
}
|
|
else if ( options::indent_ternary_operator() == 2
|
|
&& pc->Is(CT_COND_COLON))
|
|
{
|
|
log_rule_B("indent_ternary_operator");
|
|
// get the parent, the QUESTION
|
|
Chunk *question = pc->GetParent();
|
|
|
|
if (question->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LINDENT, "%s: %zu] ternarydefcol => %zu [%s]\n",
|
|
__func__, pc->GetOrigLine(), question->GetColumn(), pc->Text());
|
|
reindent_line(pc, question->GetColumn());
|
|
}
|
|
}
|
|
else if ( options::indent_oc_inside_msg_sel()
|
|
&& ( pc->Is(CT_OC_MSG_FUNC)
|
|
|| pc->Is(CT_OC_MSG_NAME))) // Issue #2658
|
|
{
|
|
log_rule_B("indent_oc_inside_msg_sel");
|
|
reindent_line(pc, frm.top().GetIndent());
|
|
}
|
|
else
|
|
{
|
|
bool use_indent = true;
|
|
const size_t ttidx = frm.size() - 1;
|
|
|
|
if (ttidx > 0)
|
|
{
|
|
LOG_FMT(LINDPC, "%s(%d): (frm.at(ttidx).pc)->GetParentType() is %s\n",
|
|
__func__, __LINE__, get_token_name((frm.at(ttidx).GetOpenChunk())->GetParentType()));
|
|
|
|
if ((frm.at(ttidx).GetOpenChunk())->GetParentType() == CT_FUNC_CALL)
|
|
{
|
|
LOG_FMT(LINDPC, "FUNC_CALL OK [%d]\n", __LINE__);
|
|
|
|
log_rule_B("use_indent_func_call_param");
|
|
|
|
if (options::use_indent_func_call_param())
|
|
{
|
|
LOG_FMT(LINDPC, "use is true [%d]\n", __LINE__);
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LINDPC, "use is false [%d]\n", __LINE__);
|
|
use_indent = false;
|
|
}
|
|
}
|
|
}
|
|
LOG_FMT(LINDENT, "%s(%d): pc->line is %zu, pc->GetColumn() is %zu, pc->Text() is '%s, indent_column is %zu\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->Text(), indent_column);
|
|
|
|
if ( use_indent
|
|
&& pc->IsNot(CT_PP_IGNORE)) // Leave indentation alone for PP_IGNORE tokens
|
|
{
|
|
log_rule_B("pos_conditional");
|
|
|
|
if ( ( pc->Is(CT_QUESTION) // Issue #2101
|
|
|| pc->Is(CT_COND_COLON)) // Issue #2101
|
|
&& options::pos_conditional() == TP_IGNORE)
|
|
{
|
|
// do not indent this line
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] don't indent this line\n",
|
|
__func__, __LINE__, pc->GetOrigLine());
|
|
}
|
|
else if (pc->Is(CT_BREAK))
|
|
{
|
|
// Issue #1692
|
|
log_rule_B("indent_switch_break_with_case");
|
|
|
|
// Issue #2281
|
|
if ( options::indent_switch_break_with_case()
|
|
&& pc->GetTypeOfParent() == CT_SWITCH)
|
|
{
|
|
// look for a case before Issue #2735
|
|
Chunk *whereIsCase = pc->GetPrevType(CT_CASE, pc->GetLevel());
|
|
|
|
if (whereIsCase->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n",
|
|
__func__, __LINE__, whereIsCase->GetOrigLine(), whereIsCase->GetOrigCol(), whereIsCase->Text());
|
|
LOG_FMT(LINDENT, "%s(%d): column is %zu\n",
|
|
__func__, __LINE__, whereIsCase->GetColumn());
|
|
reindent_line(pc, whereIsCase->GetColumn());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent_column set to %zu, for '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
}
|
|
else if ( pc->Is(CT_MEMBER) // Issue #2890
|
|
&& language_is_set(LANG_CPP))
|
|
{
|
|
// comment name: XXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent_column set to %zu, for '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
const size_t frm_size = frm.size();
|
|
LOG_FMT(LINDPC, "%s(%d): frm_size is %zu\n",
|
|
__func__, __LINE__, frm_size);
|
|
// get pc
|
|
LOG_FMT(LINDPC, "%s(%d): Text() is '%s', (frm.at(frm_size - 1).pc)->GetType() is %s\n",
|
|
__func__, __LINE__, (frm.at(frm_size - 1).GetOpenChunk())->Text(), get_token_name((frm.at(frm_size - 1).GetOpenChunk())->GetType()));
|
|
// get the token before
|
|
const size_t temp_ttidx = frm_size - 2;
|
|
|
|
if (temp_ttidx == 0)
|
|
{
|
|
indent_column = 1 + indent_size;
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else
|
|
{
|
|
Chunk *token_before = frm.at(temp_ttidx).GetOpenChunk();
|
|
LOG_FMT(LINDPC, "%s(%d): Text() is '%s', token_before->GetType() is %s\n",
|
|
__func__, __LINE__, token_before->Text(), get_token_name(token_before->GetType()));
|
|
|
|
size_t vor_col = 0;
|
|
|
|
if (token_before->Is(CT_ASSIGN))
|
|
{
|
|
Chunk *before_Assign = frm.at(temp_ttidx - 1).GetOpenChunk();
|
|
|
|
if (before_Assign->IsNullChunk())
|
|
{
|
|
indent_column = 1 + indent_size;
|
|
}
|
|
else
|
|
{
|
|
vor_col = before_Assign->GetColumn();
|
|
LOG_FMT(LINDPC, "%s(%d): Text() is '%s', before_Assign->GetType() is %s, column is %zu\n",
|
|
__func__, __LINE__, before_Assign->Text(), get_token_name(before_Assign->GetType()), vor_col);
|
|
indent_column = vor_col + 2 * indent_size;
|
|
}
|
|
}
|
|
else if (token_before->Is(CT_BRACE_OPEN))
|
|
{
|
|
vor_col = token_before->GetColumn();
|
|
LOG_FMT(LINDPC, "%s(%d): Text() is '%s', token_before->GetType() is %s, column is %zu\n",
|
|
__func__, __LINE__, token_before->Text(), get_token_name(token_before->GetType()), vor_col);
|
|
indent_column = vor_col + 2 * indent_size;
|
|
}
|
|
else if (token_before->Is(CT_RETURN))
|
|
{
|
|
Chunk *before_Return = frm.at(temp_ttidx - 1).GetOpenChunk();
|
|
vor_col = before_Return->GetColumn();
|
|
LOG_FMT(LINDPC, "%s(%d): Text() is '%s', before_Return->GetType() is %s, column is %zu\n",
|
|
__func__, __LINE__, before_Return->Text(), get_token_name(before_Return->GetType()), vor_col);
|
|
indent_column = vor_col + 2 * indent_size;
|
|
}
|
|
else
|
|
{
|
|
// TO DO
|
|
}
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent_column set to %zu, for '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text());
|
|
reindent_line(pc, indent_column);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// do not indent this line
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] don't indent this line\n",
|
|
__func__, __LINE__, pc->GetOrigLine());
|
|
}
|
|
}
|
|
did_newline = false;
|
|
|
|
if ( pc->Is(CT_SQL_EXEC)
|
|
|| pc->Is(CT_SQL_BEGIN)
|
|
|| pc->Is(CT_SQL_END))
|
|
{
|
|
sql_col = pc->GetColumn();
|
|
sql_orig_col = pc->GetOrigCol();
|
|
}
|
|
|
|
// Handle indent for variable defs at the top of a block of code
|
|
if (pc->TestFlags(PCF_VAR_TYPE))
|
|
{
|
|
if ( !frm.top().GetNonVardef()
|
|
&& (frm.top().GetOpenToken() == CT_BRACE_OPEN))
|
|
{
|
|
log_rule_B("indent_var_def_blk");
|
|
int val = options::indent_var_def_blk();
|
|
|
|
if (val != 0)
|
|
{
|
|
size_t indent = indent_column;
|
|
indent = (val > 0) ? val // reassign if positive val,
|
|
: ((size_t)(abs(val)) < indent) // else if no underflow
|
|
? (indent + val) : 0; // reduce, else 0
|
|
|
|
LOG_FMT(LINDENT, "%s(%d): %zu] var_type indent => %zu [%s]\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), indent, pc->Text());
|
|
reindent_line(pc, indent);
|
|
}
|
|
}
|
|
}
|
|
else if (pc != frm.top().GetOpenChunk())
|
|
{
|
|
frm.top().SetNonVardef(true);
|
|
}
|
|
}
|
|
|
|
// if we hit a newline, reset indent_tmp
|
|
if ( pc->IsNewline()
|
|
|| pc->Is(CT_COMMENT_MULTI)
|
|
|| pc->Is(CT_COMMENT_CPP))
|
|
{
|
|
log_indent();
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
|
|
/*
|
|
* Handle the case of a multi-line #define w/o anything on the
|
|
* first line (indent_tmp will be 1 or 0)
|
|
*/
|
|
if ( pc->Is(CT_NL_CONT)
|
|
&& frm.top().GetIndentTmp() <= indent_size
|
|
&& frm.top().GetOpenToken() != CT_PP_DEFINE)
|
|
{
|
|
frm.top().SetIndentTmp(indent_size + 1);
|
|
log_indent_tmp();
|
|
}
|
|
// Get ready to indent the next item
|
|
did_newline = true;
|
|
}
|
|
// Check for open XML tags "</..."
|
|
log_rule_B("indent_xml_string");
|
|
|
|
if ( options::indent_xml_string() > 0
|
|
&& pc->Is(CT_STRING)
|
|
&& pc->Len() > 4
|
|
&& pc->GetStr()[1] == '<'
|
|
&& pc->GetStr()[2] != '/'
|
|
&& pc->GetStr()[pc->Len() - 3] != '/')
|
|
{
|
|
if (xml_indent <= 0)
|
|
{
|
|
xml_indent = pc->GetColumn();
|
|
}
|
|
log_rule_B("indent_xml_string");
|
|
xml_indent += options::indent_xml_string();
|
|
}
|
|
// Issue #672
|
|
log_rule_B("indent_continue_class_head");
|
|
|
|
if ( pc->Is(CT_CLASS)
|
|
&& language_is_set(LANG_CPP | LANG_JAVA)
|
|
&& ( options::indent_ignore_first_continue()
|
|
|| options::indent_continue_class_head() != 0)
|
|
&& !classFound)
|
|
{
|
|
LOG_FMT(LINDENT, "%s(%d): orig line is %zu, CT_CLASS found, OPEN IT\n",
|
|
__func__, __LINE__, pc->GetOrigLine());
|
|
frm.push(pc, __func__, __LINE__);
|
|
|
|
if (options::indent_ignore_first_continue())
|
|
{
|
|
frm.top().SetIndent(get_indent_first_continue(pc));
|
|
}
|
|
else
|
|
{
|
|
frm.top().SetIndent(frm.prev().GetIndent() + options::indent_continue_class_head());
|
|
}
|
|
log_indent();
|
|
|
|
frm.top().SetIndentTmp(frm.top().GetIndent());
|
|
frm.top().SetIndentTab(frm.top().GetIndent());
|
|
log_indent_tmp();
|
|
classFound = true;
|
|
}
|
|
pc = pc->GetNext();
|
|
|
|
if (pc->Is(CT_SPACE)) // Issue #3710
|
|
{
|
|
pc = pc->GetNext();
|
|
}
|
|
LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()));
|
|
}
|
|
null_pc:
|
|
|
|
// Throw out any stuff inside a preprocessor - no need to warn
|
|
while ( !frm.empty()
|
|
&& frm.top().GetInPreproc())
|
|
{
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
// Throw out any VBRACE_OPEN at the end - implied with the end of file
|
|
while ( !frm.empty()
|
|
&& frm.top().GetOpenToken() == CT_VBRACE_OPEN)
|
|
{
|
|
frm.pop(__func__, __LINE__, pc);
|
|
}
|
|
|
|
for (size_t idx_temp = 1; idx_temp < frm.size(); idx_temp++)
|
|
{
|
|
LOG_FMT(LWARN, "%s(%d): size is %zu\n",
|
|
__func__, __LINE__, frm.size());
|
|
LOG_FMT(LWARN, "%s(%d): File: %s, open_line is %zu, parent is %s: Unmatched %s\n",
|
|
__func__, __LINE__, cpd.filename.c_str(), frm.at(idx_temp).GetOpenLine(),
|
|
get_token_name(frm.at(idx_temp).GetParent()),
|
|
get_token_name(frm.at(idx_temp).GetOpenToken()));
|
|
exit(EX_IOERR);
|
|
}
|
|
|
|
LOG_FMT(LINDLINE, "%s(%d): before quick_align_again\n", __func__, __LINE__);
|
|
quick_align_again();
|
|
quick_indent_again();
|
|
LOG_FMT(LINDLINE, "%s(%d): after quick_align_again\n", __func__, __LINE__);
|
|
} // indent_text
|
|
|
|
|
|
static bool single_line_comment_indent_rule_applies(Chunk *start, bool forward)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
if (!start->IsSingleLineComment())
|
|
{
|
|
return(false);
|
|
}
|
|
Chunk *pc = start;
|
|
size_t nl_count = 0;
|
|
|
|
while ((pc = forward ? pc->GetNext() : pc->GetPrev())->IsNotNullChunk())
|
|
{
|
|
if (pc->IsNewline())
|
|
{
|
|
if ( nl_count > 0
|
|
|| pc->GetNlCount() > 1)
|
|
{
|
|
return(false);
|
|
}
|
|
nl_count++;
|
|
}
|
|
else if (pc->IsSingleLineComment())
|
|
{
|
|
nl_count = 0;
|
|
}
|
|
else if ( pc->Is(CT_COMMENT_MULTI)
|
|
|| (forward && pc->IsBraceClose())
|
|
|| (!forward && pc->IsBraceOpen()))
|
|
{
|
|
/*
|
|
* check for things we wouldn't want to indent the comment for
|
|
* example: non-single line comment, closing brace
|
|
*/
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
return(true);
|
|
}
|
|
}
|
|
return(false);
|
|
} // single_line_comment_indent_rule_applies
|
|
|
|
|
|
static bool is_end_of_assignment(Chunk *pc, const ParsingFrame &frm)
|
|
{
|
|
return( ( frm.top().GetOpenToken() == CT_ASSIGN_NL
|
|
|| frm.top().GetOpenToken() == CT_MEMBER
|
|
|| frm.top().GetOpenToken() == CT_ASSIGN)
|
|
&& ( pc->IsSemicolon()
|
|
|| pc->Is(CT_COMMA)
|
|
|| pc->Is(CT_BRACE_OPEN)
|
|
|| pc->Is(CT_SPAREN_CLOSE)
|
|
|| ( pc->Is(CT_SQUARE_OPEN)
|
|
&& pc->GetParentType() == CT_ASSIGN))
|
|
&& pc->GetParentType() != CT_CPP_LAMBDA);
|
|
}
|
|
|
|
|
|
static size_t calc_comment_next_col_diff(Chunk *pc)
|
|
{
|
|
Chunk *next = pc; // assumes pc has a comment type
|
|
|
|
LOG_FMT(LCMTIND, "%s(%d): next->Text() is '%s'\n",
|
|
__func__, __LINE__, next->Text());
|
|
|
|
// Note: every comment is squashed into a single token
|
|
// (including newline chars for multiline comments) and is followed by
|
|
// a newline token (unless there are no more tokens left)
|
|
do
|
|
{
|
|
Chunk *newline_token = next->GetNext();
|
|
LOG_FMT(LCMTIND, "%s(%d): newline_token->Text() is '%s', orig line is %zu, orig col is %zu\n",
|
|
__func__, __LINE__, newline_token->Text(), newline_token->GetOrigLine(), newline_token->GetOrigCol());
|
|
|
|
if ( newline_token->IsNullChunk()
|
|
|| newline_token->GetNlCount() > 1)
|
|
{
|
|
return(5000); // FIXME: Max thresh magic number 5000
|
|
}
|
|
next = newline_token->GetNext();
|
|
|
|
if (next->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): next->Text() is '%s', orig line is %zu, orig col is %zu\n",
|
|
__func__, __LINE__, next->Text(), next->GetOrigLine(), next->GetOrigCol());
|
|
}
|
|
} while (next->IsComment());
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
return(5000); // FIXME: Max thresh magic number 5000
|
|
}
|
|
LOG_FMT(LCMTIND, "%s(%d): next->Text() is '%s'\n",
|
|
__func__, __LINE__, next->Text());
|
|
// here next is the first non comment, non newline token
|
|
return(next->GetOrigCol() > pc->GetOrigCol()
|
|
? next->GetOrigCol() - pc->GetOrigCol()
|
|
: pc->GetOrigCol() - next->GetOrigCol());
|
|
}
|
|
|
|
|
|
static void indent_comment(Chunk *pc, size_t col)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
char copy[1000];
|
|
|
|
LOG_FMT(LCMTIND, "%s(%d): pc->Text() is '%s', orig line %zu, orig col %zu, level %zu\n",
|
|
__func__, __LINE__, pc->ElidedText(copy), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel());
|
|
|
|
// force column 1 comment to column 1 if not changing them
|
|
log_rule_B("indent_col1_comment");
|
|
|
|
if ( pc->GetOrigCol() == 1
|
|
&& !options::indent_col1_comment()
|
|
&& !pc->TestFlags(PCF_INSERTED))
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): rule 1 - keep in col 1\n", __func__, __LINE__);
|
|
reindent_line(pc, 1);
|
|
return;
|
|
}
|
|
Chunk *nl = pc->GetPrev();
|
|
|
|
if (nl->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): nl->Text() is '%s', orig line %zu, orig col %zu, level %zu\n",
|
|
__func__, __LINE__, nl->Text(), nl->GetOrigLine(), nl->GetOrigCol(), nl->GetLevel());
|
|
}
|
|
|
|
if (pc->GetOrigCol() > 1)
|
|
{
|
|
Chunk *prev = nl->GetPrev();
|
|
|
|
if (prev->IsNotNullChunk())
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): prev->Text() is '%s', orig line %zu, orig col %zu, level %zu\n",
|
|
__func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol(), prev->GetLevel());
|
|
log_pcf_flags(LCMTIND, prev->GetFlags());
|
|
}
|
|
|
|
if ( prev->IsComment()
|
|
&& nl->GetNlCount() == 1)
|
|
{
|
|
const size_t prev_col_diff = (prev->GetOrigCol() > pc->GetOrigCol())
|
|
? prev->GetOrigCol() - pc->GetOrigCol()
|
|
: pc->GetOrigCol() - prev->GetOrigCol();
|
|
LOG_FMT(LCMTIND, "%s(%d): prev_col_diff is %zu\n",
|
|
__func__, __LINE__, prev_col_diff);
|
|
|
|
/*
|
|
* Here we want to align comments that are relatively close one to
|
|
* another but not when the comment is a Doxygen comment (Issue #1134)
|
|
*/
|
|
if (prev_col_diff <= options::indent_comment_align_thresh())
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): prev->Text() is '%s', Doxygen_comment(prev) is %s\n",
|
|
__func__, __LINE__, prev->Text(), prev->IsDoxygenComment() ? "TRUE" : "FALSE");
|
|
LOG_FMT(LCMTIND, "%s(%d): pc->Text() is '%s', Doxygen_comment(pc) is %s\n",
|
|
__func__, __LINE__, pc->Text(), pc->IsDoxygenComment() ? "TRUE" : "FALSE");
|
|
|
|
if (prev->IsDoxygenComment() == pc->IsDoxygenComment())
|
|
{
|
|
const size_t next_col_diff = calc_comment_next_col_diff(pc);
|
|
LOG_FMT(LCMTIND, "%s(%d): next_col_diff is %zu\n",
|
|
__func__, __LINE__, next_col_diff);
|
|
|
|
// Align to the previous comment or to the next token?
|
|
if ( prev_col_diff <= next_col_diff
|
|
|| next_col_diff == 5000) // FIXME: Max thresh magic number 5000
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): rule 3 - prev comment, coldiff = %zu, now in %zu\n",
|
|
__func__, __LINE__, prev_col_diff, pc->GetColumn());
|
|
reindent_line(pc, prev->GetColumn());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// check if special single-line-comment-before-code rule applies
|
|
log_rule_B("indent_single_line_comments_before");
|
|
|
|
if ( (options::indent_single_line_comments_before() > 0)
|
|
&& single_line_comment_indent_rule_applies(pc, true))
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): rule 4 - indent single line comments before code, now in %zu\n",
|
|
__func__, __LINE__, pc->GetColumn());
|
|
reindent_line(pc, col + options::indent_single_line_comments_before());
|
|
return;
|
|
}
|
|
// check if special single-line-comment-after-code rule applies
|
|
log_rule_B("indent_single_line_comments_after");
|
|
|
|
if ( (options::indent_single_line_comments_after() > 0)
|
|
&& single_line_comment_indent_rule_applies(pc, false))
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): rule 4 - indent single line comments after code, now in %zu\n",
|
|
__func__, __LINE__, pc->GetColumn());
|
|
reindent_line(pc, col + options::indent_single_line_comments_after());
|
|
return;
|
|
}
|
|
log_rule_B("indent_comment");
|
|
|
|
if ( pc->GetOrigCol() > 1
|
|
&& !options::indent_comment())
|
|
{
|
|
LOG_FMT(LCMTIND, "%s(%d): rule 5 - keep in orig col\n", __func__, __LINE__);
|
|
reindent_line(pc, pc->GetOrigCol());
|
|
return;
|
|
}
|
|
LOG_FMT(LCMTIND, "%s(%d): rule 6 - fall-through, stay in %zu\n",
|
|
__func__, __LINE__, col);
|
|
reindent_line(pc, col);
|
|
} // indent_comment
|
|
|
|
|
|
bool ifdef_over_whole_file()
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
// if requested, treat an #if that guards the entire file the same as any other #if
|
|
// if running as frag, assume #if is not a guard
|
|
if ( options::pp_indent_in_guard()
|
|
|| cpd.frag)
|
|
{
|
|
return(false);
|
|
}
|
|
|
|
// the results for this file are cached
|
|
if (cpd.ifdef_over_whole_file)
|
|
{
|
|
return(cpd.ifdef_over_whole_file > 0);
|
|
}
|
|
Chunk *start_pp = Chunk::NullChunkPtr;
|
|
Chunk *end_pp = Chunk::NullChunkPtr;
|
|
size_t IFstage = 0;
|
|
|
|
for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext())
|
|
{
|
|
LOG_FMT(LNOTE, "%s(%d): pc->pp level is %zu, pc orig line is %zu, orig col is %zu, pc->Text() is '%s'\n",
|
|
__func__, __LINE__, pc->GetPpLevel(), pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
|
|
|
|
if (pc->IsCommentOrNewline())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (IFstage == 0) // 0 is BEGIN
|
|
{
|
|
// Check the first preprocessor, make sure it is an #if type
|
|
if (pc->IsNot(CT_PREPROC))
|
|
{
|
|
break;
|
|
}
|
|
Chunk *next = pc->GetNext();
|
|
|
|
if ( next->IsNullChunk()
|
|
|| next->IsNot(CT_PP_IF))
|
|
{
|
|
break;
|
|
}
|
|
IFstage = 1; // 1 is CT_PP_IF found
|
|
start_pp = pc;
|
|
}
|
|
else if (IFstage == 1) // 1 is CT_PP_IF found
|
|
{
|
|
// Scan until a preprocessor at level 0 is found - the close to the #if
|
|
if (pc->Is(CT_PREPROC))
|
|
{
|
|
if (pc->GetPpLevel() == 0)
|
|
{
|
|
IFstage = 2;
|
|
end_pp = pc;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
else if (IFstage == 2)
|
|
{
|
|
// We should only see the rest of the preprocessor
|
|
if ( pc->Is(CT_PREPROC)
|
|
|| !pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
IFstage = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
cpd.ifdef_over_whole_file = (IFstage == 2) ? 1 : -1;
|
|
|
|
if (cpd.ifdef_over_whole_file > 0)
|
|
{
|
|
start_pp->SetFlagBits(PCF_WF_IF);
|
|
end_pp->SetFlagBits(PCF_WF_ENDIF);
|
|
}
|
|
LOG_FMT(LNOTE, "The whole file is%s covered by a #IF\n",
|
|
(cpd.ifdef_over_whole_file > 0) ? "" : " NOT");
|
|
return(cpd.ifdef_over_whole_file > 0);
|
|
} // ifdef_over_whole_file
|
|
|
|
|
|
void indent_preproc()
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
// Scan to see if the whole file is covered by one #ifdef
|
|
const size_t pp_level_sub = ifdef_over_whole_file() ? 1 : 0;
|
|
|
|
for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext())
|
|
{
|
|
LOG_FMT(LPPIS, "%s(%d): orig line is %zu, orig col is %zu, pc->Text() is '%s'\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
|
|
|
|
if (pc->IsNot(CT_PREPROC))
|
|
{
|
|
continue;
|
|
}
|
|
Chunk *next = pc->GetNextNcNnl();
|
|
|
|
if (next->IsNullChunk())
|
|
{
|
|
break;
|
|
}
|
|
const size_t pp_level = (pc->GetPpLevel() > pp_level_sub)
|
|
? pc->GetPpLevel() - pp_level_sub : 0;
|
|
|
|
// Adjust the indent of the '#'
|
|
if (options::pp_indent() & IARF_ADD)
|
|
{
|
|
log_rule_B("pp_indent ADD");
|
|
reindent_line(pc, 1 + pp_level * options::pp_indent_count());
|
|
}
|
|
else if (options::pp_indent() & IARF_REMOVE)
|
|
{
|
|
log_rule_B("pp_indent REMOVE");
|
|
reindent_line(pc, 1);
|
|
}
|
|
// Add spacing by adjusting the length
|
|
log_rule_B("pp_space_after");
|
|
|
|
if ( (options::pp_space_after() != IARF_IGNORE)
|
|
&& next->IsNotNullChunk())
|
|
{
|
|
if (options::pp_space_after() & IARF_ADD)
|
|
{
|
|
log_rule_B("pp_space_after ADD");
|
|
const size_t mult = options::pp_space_count();
|
|
reindent_line(next, pc->GetColumn() + pc->Len() + (pp_level * mult));
|
|
}
|
|
else if (options::pp_space_after() & IARF_REMOVE)
|
|
{
|
|
log_rule_B("pp_space_after REMOVE");
|
|
reindent_line(next, pc->GetColumn() + pc->Len());
|
|
}
|
|
}
|
|
// Mark as already handled if not region stuff or in column 1
|
|
log_rule_B("pp_indent_at_level");
|
|
|
|
bool at_file_level = pc->GetBraceLevel() <= ((pc->GetParentType() == CT_PP_DEFINE) ? 1 : 0);
|
|
|
|
if ( ( ( at_file_level
|
|
&& !options::pp_indent_at_level0())
|
|
|| ( !at_file_level
|
|
&& !options::pp_indent_at_level()))
|
|
&& pc->GetParentType() != CT_PP_REGION
|
|
&& pc->GetParentType() != CT_PP_ENDREGION)
|
|
{
|
|
log_rule_B("pp_define_at_level");
|
|
|
|
if ( !options::pp_define_at_level()
|
|
|| pc->GetParentType() != CT_PP_DEFINE)
|
|
{
|
|
pc->SetFlagBits(PCF_DONT_INDENT);
|
|
}
|
|
}
|
|
LOG_FMT(LPPIS, "%s(%d): orig line %zu to %zu (len %zu, next->col %zu)\n",
|
|
__func__, __LINE__, pc->GetOrigLine(), 1 + pp_level, pc->Len(),
|
|
next ? next->GetColumn() : -1);
|
|
}
|
|
} // indent_preproc
|