blob: a66104facf9acbc7144eafa32d2bbb26032feeca [file] [log] [blame]
/**
* @file indent.cpp
* Does all the indenting stuff.
*
* @author Ben Gardner
* @license GPL v2+
*/
#include "uncrustify_types.h"
#include "chunk_list.h"
#include "prototypes.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include "unc_ctype.h"
/**
* 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_funcion_name(
* param1, param2);
* a_really_long_funcion_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 assignemts
* 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;
*/
static void indent_comment(chunk_t *pc, int col);
static bool ifdef_over_whole_file();
void indent_to_column(chunk_t *pc, int column)
{
LOG_FUNC_ENTRY();
if (column < pc->column)
{
column = pc->column;
}
reindent_line(pc, column);
}
enum align_mode
{
ALMODE_SHIFT, /* shift relative to the current column */
ALMODE_KEEP_ABS, /* try to keep the original absolute column */
ALMODE_KEEP_REL, /* try to keep the original gap */
};
/* Same as indent_to_column, except we can move both ways */
void align_to_column(chunk_t *pc, int column)
{
LOG_FUNC_ENTRY();
if (column == pc->column)
{
return;
}
LOG_FMT(LINDLINE, "%s: %d] col %d on %s [%s] => %d\n",
__func__, pc->orig_line, pc->column, pc->str.c_str(),
get_token_name(pc->type), column);
int col_delta = column - pc->column;
int min_col = column;
int min_delta;
pc->column = column;
do
{
chunk_t *next = chunk_get_next(pc);
chunk_t *prev;
align_mode almod = ALMODE_SHIFT;
if (next == NULL)
{
break;
}
min_delta = space_col_align(pc, next);
min_col += min_delta;
prev = pc;
pc = next;
if (chunk_is_comment(pc) && (pc->parent_type != CT_COMMENT_EMBED))
{
almod = (chunk_is_single_line_comment(pc) &&
cpd.settings[UO_indent_relative_single_line_comments].b) ?
ALMODE_KEEP_REL : ALMODE_KEEP_ABS;
}
if (almod == ALMODE_KEEP_ABS)
{
/* Keep same absolute column */
pc->column = pc->orig_col;
if (pc->column < min_col)
{
pc->column = min_col;
}
}
else if (almod == ALMODE_KEEP_REL)
{
/* Keep same relative column */
int orig_delta = pc->orig_col - prev->orig_col;
if (orig_delta < min_delta)
{
orig_delta = min_delta;
}
pc->column = prev->column + orig_delta;
}
else /* ALMODE_SHIFT */
{
/* Shift by the same amount */
pc->column += col_delta;
if (pc->column < min_col)
{
pc->column = min_col;
}
}
LOG_FMT(LINDLINED, " %s set column of %s on line %d to col %d (orig %d)\n",
(almod == ALMODE_KEEP_ABS) ? "abs" :
(almod == ALMODE_KEEP_REL) ? "rel" : "sft",
get_token_name(pc->type), pc->orig_line, pc->column, pc->orig_col);
} while ((pc != NULL) && (pc->nl_count == 0));
}
/**
* Changes the initial indent for a line to the given column
*
* @param pc The chunk at the start of the line
* @param column The desired column
*/
void reindent_line(chunk_t *pc, int column)
{
LOG_FUNC_ENTRY();
LOG_FMT(LINDLINE, "%s: %d] col %d on '%s' [%s/%s] => %d",
__func__, pc->orig_line, pc->column, pc->str.c_str(),
get_token_name(pc->type), get_token_name(pc->parent_type),
column);
log_func_stack_inline(LINDLINE);
if (column == pc->column)
{
return;
}
int col_delta = column - pc->column;
int min_col = column;
pc->column = column;
do
{
chunk_t *next = chunk_get_next(pc);
if (next == NULL)
{
break;
}
if (pc->nl_count)
{
min_col = 0;
col_delta = 0;
}
min_col += space_col_align(pc, next);
pc = next;
bool is_comment = chunk_is_comment(pc);
bool keep = is_comment && chunk_is_single_line_comment(pc) &&
cpd.settings[UO_indent_relative_single_line_comments].b;
if (is_comment && (pc->parent_type != CT_COMMENT_EMBED) && !keep)
{
pc->column = pc->orig_col;
if (pc->column < min_col)
{
pc->column = min_col; // + 1;
}
LOG_FMT(LINDLINE, "%s: set comment on line %d to col %d (orig %d)\n",
__func__, pc->orig_line, pc->column, pc->orig_col);
}
else
{
pc->column += col_delta;
if (pc->column < min_col)
{
pc->column = min_col;
}
LOG_FMT(LINDLINED, " set column of '%s' to %d (orig %d)\n",
pc->str.c_str(), pc->column, pc->orig_col);
}
} while ((pc != NULL) && (pc->nl_count == 0));
}
/**
* Starts a new entry
*
* @param frm The parse frame
* @param pc The chunk causing the push
*/
static void indent_pse_push(struct parse_frame& frm, chunk_t *pc)
{
LOG_FUNC_ENTRY();
static int ref = 0;
/* check the stack depth */
if (frm.pse_tos < ((int)ARRAY_SIZE(frm.pse) - 1))
{
/* Bump up the index and initialize it */
frm.pse_tos++;
memset(&frm.pse[frm.pse_tos], 0, sizeof(frm.pse[frm.pse_tos]));
LOG_FMT(LINDPSE, "%4d] (pp=%d) OPEN [%d,%s] level=%d\n",
pc->orig_line, cpd.pp_level, frm.pse_tos, get_token_name(pc->type), pc->level);
frm.pse[frm.pse_tos].pc = pc;
frm.pse[frm.pse_tos].type = pc->type;
frm.pse[frm.pse_tos].level = pc->level;
frm.pse[frm.pse_tos].open_line = pc->orig_line;
frm.pse[frm.pse_tos].ref = ++ref;
frm.pse[frm.pse_tos].in_preproc = (pc->flags & PCF_IN_PREPROC) != 0;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos - 1].indent_tab;
frm.pse[frm.pse_tos].indent_cont = frm.pse[frm.pse_tos - 1].indent_cont;
frm.pse[frm.pse_tos].non_vardef = false;
frm.pse[frm.pse_tos].ns_cnt = frm.pse[frm.pse_tos - 1].ns_cnt;
memcpy(&frm.pse[frm.pse_tos].ip, &frm.pse[frm.pse_tos - 1].ip, sizeof(frm.pse[frm.pse_tos].ip));
}
}
/**
* Removes the top entry
*
* @param frm The parse frame
* @param pc The chunk causing the push
*/
static void indent_pse_pop(struct parse_frame& frm, chunk_t *pc)
{
LOG_FUNC_ENTRY();
/* Bump up the index and initialize it */
if (frm.pse_tos > 0)
{
if (pc != NULL)
{
LOG_FMT(LINDPSE, "%4d] (pp=%d) CLOSE [%d,%s] on %s, started on line %d, level=%d/%d\n",
pc->orig_line, cpd.pp_level, frm.pse_tos,
get_token_name(frm.pse[frm.pse_tos].type),
get_token_name(pc->type),
frm.pse[frm.pse_tos].open_line,
frm.pse[frm.pse_tos].level,
pc->level);
}
else
{
LOG_FMT(LINDPSE, " EOF] CLOSE [%d,%s], started on line %d\n",
frm.pse_tos, get_token_name(frm.pse[frm.pse_tos].type),
frm.pse[frm.pse_tos].open_line);
}
/* Don't clear the stack entry because some code 'cheats' and uses the
* just-popped indent values
*/
frm.pse_tos--;
}
}
static int token_indent(c_token_t 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);
default:
return(0);
}
}
#define indent_column_set(X) \
do { \
indent_column = (X); \
LOG_FMT(LINDENT2, "[line %d] indent_column = %d\n", \
__LINE__, indent_column); \
} while (0)
static int calc_indent_continue(struct parse_frame& frm, int pse_tos)
{
int ic = cpd.settings[UO_indent_continue].n;
if ((ic < 0) && frm.pse[pse_tos].indent_cont)
{
return frm.pse[pse_tos].indent;
}
return frm.pse[pse_tos].indent + abs(ic);
}
/**
* We are on a '{' that has parent = OC_BLOCK_EXPR
* find the column of the param tag
*/
static chunk_t *oc_msg_block_indent(chunk_t *pc, bool from_brace,
bool from_caret, bool from_colon,
bool from_keyword)
{
LOG_FUNC_ENTRY();
chunk_t *tmp = chunk_get_prev_nc(pc);
if (from_brace)
{
return pc;
}
if (chunk_is_paren_close(tmp))
{
tmp = chunk_get_prev_nc(chunk_skip_to_match_rev(tmp));
}
if (!tmp || (tmp->type != CT_OC_BLOCK_CARET))
{
return NULL;
}
if (from_caret)
{
return tmp;
}
tmp = chunk_get_prev_nc(tmp);
if (!tmp || (tmp->type != CT_OC_COLON))
{
return NULL;
}
if (from_colon)
{
return tmp;
}
tmp = chunk_get_prev_nc(tmp);
if (!tmp || ((tmp->type != CT_OC_MSG_NAME) && (tmp->type != CT_OC_MSG_FUNC)))
{
return NULL;
}
if (from_keyword)
{
return tmp;
}
return NULL;
}
/**
* We are on a '{' that has parent = OC_BLOCK_EXPR
*/
static chunk_t *oc_msg_prev_colon(chunk_t *pc)
{
return chunk_get_prev_type(pc, CT_OC_COLON, pc->level, CNAV_ALL);
}
/**
* Change the top-level indentation only by changing the column member in
* the chunk structures.
* The level indicator must already be set.
*/
void indent_text(void)
{
LOG_FUNC_ENTRY();
chunk_t *pc;
chunk_t *next;
chunk_t *prev = NULL;
bool did_newline = true;
int idx;
int vardefcol = 0;
int indent_size = cpd.settings[UO_indent_columns].n;
int tmp;
struct parse_frame frm;
bool in_preproc = false;
int indent_column;
int parent_token_indent = 0;
int xml_indent = 0;
bool token_used;
int sql_col = 0;
int sql_orig_col = 0;
bool in_func_def = false;
c_token_t memtype;
memset(&frm, 0, sizeof(frm));
cpd.frame_count = 0;
/* dummy top-level entry */
frm.pse[0].indent = 1;
frm.pse[0].indent_tmp = 1;
frm.pse[0].indent_tab = 1;
frm.pse[0].type = CT_EOF;
pc = chunk_get_head();
while (pc != NULL)
{
/* Handle preprocessor transitions */
in_preproc = (pc->flags & PCF_IN_PREPROC) != 0;
if (cpd.settings[UO_indent_brace_parent].b)
{
parent_token_indent = token_indent(pc->parent_type);
}
/* Handle "force indentation of function definition to start in column 1" */
if (cpd.settings[UO_indent_func_def_force_col1].b)
{
if (!in_func_def)
{
next = chunk_get_next_ncnl(pc);
if ((pc->parent_type == CT_FUNC_DEF) ||
((pc->type == CT_COMMENT) &&
(next != NULL) &&
(next->parent_type == CT_FUNC_DEF)))
{
in_func_def = true;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent_tmp = 1;
frm.pse[frm.pse_tos].indent = 1;
frm.pse[frm.pse_tos].indent_tab = 1;
}
}
else
{
prev = chunk_get_prev(pc);
if ((prev->type == CT_BRACE_CLOSE) &&
(prev->parent_type == CT_FUNC_DEF))
{
in_func_def = false;
indent_pse_pop(frm, pc);
}
}
}
/* Clean up after a #define, etc */
if (!in_preproc)
{
while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc)
{
c_token_t type = frm.pse[frm.pse_tos].type;
indent_pse_pop(frm, 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.pse[frm.pse_tos].type == CT_PP_REGION_INDENT))
{
indent_pse_pop(frm, pc);
}
}
}
else if (pc->type == CT_PREPROC)
{
/* Close out PP_IF_INDENT before playing with the parse frames */
if ((frm.pse[frm.pse_tos].type == CT_PP_IF_INDENT) &&
((pc->parent_type == CT_PP_ENDIF) ||
(pc->parent_type == CT_PP_ELSE)))
{
indent_pse_pop(frm, pc);
}
pf_check(&frm, pc);
/* Indent the body of a #region here */
if (cpd.settings[UO_pp_region_indent_code].b &&
(pc->parent_type == CT_PP_REGION))
{
next = chunk_get_next(pc);
/* Hack to get the logs to look right */
set_chunk_type(next, CT_PP_REGION_INDENT);
indent_pse_push(frm, next);
set_chunk_type(next, CT_PP_REGION);
/* Indent one level */
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos - 1].indent_tab + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].in_preproc = false;
}
/* Indent the body of a #if here */
if (cpd.settings[UO_pp_if_indent_code].b &&
((pc->parent_type == CT_PP_IF) ||
(pc->parent_type == CT_PP_ELSE)))
{
next = chunk_get_next(pc);
/* Hack to get the logs to look right */
memtype = next->type;
set_chunk_type(next, CT_PP_IF_INDENT);
indent_pse_push(frm, next);
set_chunk_type(next, memtype);
/* Indent one level except if the #if is a #include guard */
int extra = ((pc->pp_level == 0) && ifdef_over_whole_file()) ? 0 : indent_size;
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + extra;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos - 1].indent_tab + extra;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].in_preproc = false;
}
/* Transition into a preproc by creating a dummy indent */
frm.level++;
indent_pse_push(frm, chunk_get_next(pc));
if (pc->parent_type == CT_PP_DEFINE)
{
frm.pse[frm.pse_tos].indent_tmp = cpd.settings[UO_pp_define_at_level].b ?
frm.pse[frm.pse_tos - 1].indent_tmp : 1;
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos].indent_tmp + indent_size;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
else
{
if ((frm.pse[frm.pse_tos - 1].type == CT_PP_REGION_INDENT) ||
((frm.pse[frm.pse_tos - 1].type == CT_PP_IF_INDENT) &&
(frm.pse[frm.pse_tos].type != CT_PP_ENDIF)))
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 2].indent;
}
else
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent;
}
if ((pc->parent_type == CT_PP_REGION) ||
(pc->parent_type == CT_PP_ENDREGION))
{
int val = cpd.settings[UO_pp_indent_region].n;
if (val > 0)
{
frm.pse[frm.pse_tos].indent = val;
}
else
{
frm.pse[frm.pse_tos].indent += val;
}
}
else if ((pc->parent_type == CT_PP_IF) ||
(pc->parent_type == CT_PP_ELSE) ||
(pc->parent_type == CT_PP_ENDIF))
{
int val = cpd.settings[UO_pp_indent_if].n;
if (val > 0)
{
frm.pse[frm.pse_tos].indent = val;
}
else
{
frm.pse[frm.pse_tos].indent += val;
}
}
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
}
}
/* Check for close XML tags "</..." */
if (cpd.settings[UO_indent_xml_string].n > 0)
{
if (pc->type == CT_STRING)
{
if ((pc->len() > 4) &&
(xml_indent > 0) &&
(pc->str[1] == '<') &&
(pc->str[2] == '/'))
{
xml_indent -= cpd.settings[UO_indent_xml_string].n;
}
}
else
{
if (!chunk_is_comment(pc) && !chunk_is_newline(pc))
{
xml_indent = 0;
}
}
}
/**
* Handle non-brace closures
*/
token_used = false;
int old_pse_tos;
do
{
old_pse_tos = frm.pse_tos;
/* End anything that drops a level */
if (!chunk_is_newline(pc) &&
!chunk_is_comment(pc) &&
(frm.pse[frm.pse_tos].level > pc->level))
{
indent_pse_pop(frm, pc);
}
if (frm.pse[frm.pse_tos].level >= pc->level)
{
/* process virtual braces closes (no text output) */
if ((pc->type == CT_VBRACE_CLOSE) &&
(frm.pse[frm.pse_tos].type == CT_VBRACE_OPEN))
{
indent_pse_pop(frm, pc);
frm.level--;
pc = chunk_get_next(pc);
if (!pc)
{
/* need to break out of both the do and while loops */
goto null_pc;
}
}
/* End any assign operations with a semicolon on the same level */
if (((frm.pse[frm.pse_tos].type == CT_ASSIGN_NL) ||
(frm.pse[frm.pse_tos].type == CT_ASSIGN)) &&
(chunk_is_semicolon(pc) ||
(pc->type == CT_COMMA) ||
(pc->type == CT_BRACE_OPEN) ||
(pc->type == CT_SPAREN_CLOSE) ||
((pc->type == CT_SQUARE_OPEN) && (pc->parent_type == CT_OC_AT)) ||
((pc->type == CT_SQUARE_OPEN) && (pc->parent_type == CT_ASSIGN))) &&
(pc->parent_type != CT_CPP_LAMBDA))
{
indent_pse_pop(frm, pc);
}
/* End any assign operations with a semicolon on the same level */
if (chunk_is_semicolon(pc) &&
((frm.pse[frm.pse_tos].type == CT_IMPORT) ||
(frm.pse[frm.pse_tos].type == CT_USING)))
{
indent_pse_pop(frm, pc);
}
/* End any custom macro-based open/closes */
if (!token_used &&
(frm.pse[frm.pse_tos].type == CT_MACRO_OPEN) &&
(pc->type == CT_MACRO_CLOSE))
{
token_used = true;
indent_pse_pop(frm, pc);
}
/* End any CPP/ObjC class colon stuff */
if (((frm.pse[frm.pse_tos].type == CT_CLASS_COLON) ||
(frm.pse[frm.pse_tos].type == CT_CONSTR_COLON)) &&
((pc->type == CT_BRACE_OPEN) ||
(pc->type == CT_OC_END) ||
(pc->type == CT_OC_SCOPE) ||
(pc->type == CT_OC_PROPERTY) ||
chunk_is_semicolon(pc)))
{
indent_pse_pop(frm, pc);
}
/* a case is ended with another case or a close brace */
if ((frm.pse[frm.pse_tos].type == CT_CASE) &&
((pc->type == CT_BRACE_CLOSE) ||
(pc->type == CT_CASE)))
{
indent_pse_pop(frm, pc);
}
/* a class scope is ended with another class scope or a close brace */
if (cpd.settings[UO_indent_access_spec_body].b &&
(frm.pse[frm.pse_tos].type == CT_PRIVATE) &&
((pc->type == CT_BRACE_CLOSE) ||
(pc->type == CT_PRIVATE)))
{
indent_pse_pop(frm, pc);
}
/* return & throw are ended with a semicolon */
if (chunk_is_semicolon(pc) &&
((frm.pse[frm.pse_tos].type == CT_RETURN) ||
(frm.pse[frm.pse_tos].type == CT_THROW)))
{
indent_pse_pop(frm, pc);
}
/* an OC SCOPE ('-' or '+') ends with a semicolon or brace open */
if ((frm.pse[frm.pse_tos].type == CT_OC_SCOPE) &&
(chunk_is_semicolon(pc) ||
(pc->type == CT_BRACE_OPEN)))
{
indent_pse_pop(frm, pc);
}
/* a typedef and an OC SCOPE ('-' or '+') ends with a semicolon or
* brace open */
if ((frm.pse[frm.pse_tos].type == CT_TYPEDEF) &&
(chunk_is_semicolon(pc) ||
chunk_is_paren_open(pc) ||
(pc->type == CT_BRACE_OPEN)))
{
indent_pse_pop(frm, pc);
}
/* an SQL EXEC is ended with a semicolon */
if ((frm.pse[frm.pse_tos].type == CT_SQL_EXEC) &&
chunk_is_semicolon(pc))
{
indent_pse_pop(frm, pc);
}
/* an CLASS is ended with a semicolon or brace open */
if ((frm.pse[frm.pse_tos].type == CT_CLASS) &&
((pc->type == CT_CLASS_COLON) ||
(pc->type == CT_BRACE_OPEN) ||
chunk_is_semicolon(pc)))
{
indent_pse_pop(frm, pc);
}
/* Close out parens and squares */
if ((frm.pse[frm.pse_tos].type == (pc->type - 1)) &&
((pc->type == CT_PAREN_CLOSE) ||
(pc->type == CT_SPAREN_CLOSE) ||
(pc->type == CT_FPAREN_CLOSE) ||
(pc->type == CT_SQUARE_CLOSE) ||
(pc->type == CT_ANGLE_CLOSE)))
{
indent_pse_pop(frm, pc);
frm.paren_count--;
}
}
} while (old_pse_tos > frm.pse_tos);
/* Grab a copy of the current indent */
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
if (!chunk_is_newline(pc) && !chunk_is_comment(pc) && log_sev_on(LINDPC))
{
LOG_FMT(LINDPC, " -=[ %d:%d %s ]=-\n",
pc->orig_line, pc->orig_col, pc->str.c_str());
for (int ttidx = frm.pse_tos; ttidx > 0; ttidx--)
{
LOG_FMT(LINDPC, " [%d %d:%d %s/%s tmp=%d ind=%d bri=%d tab=%d cont=%d lvl=%d blvl=%d]\n",
ttidx,
frm.pse[ttidx].pc->orig_line,
frm.pse[ttidx].pc->orig_col,
get_token_name(frm.pse[ttidx].type),
get_token_name(frm.pse[ttidx].pc->parent_type),
frm.pse[ttidx].indent_tmp,
frm.pse[ttidx].indent,
frm.pse[ttidx].brace_indent,
frm.pse[ttidx].indent_tab,
frm.pse[ttidx].indent_cont,
frm.pse[ttidx].level,
frm.pse[ttidx].pc->brace_level);
}
}
/**
* 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
*/
bool brace_indent = false;
if ((pc->type == CT_BRACE_CLOSE) || (pc->type == CT_BRACE_OPEN))
{
brace_indent = (cpd.settings[UO_indent_braces].b &&
(!cpd.settings[UO_indent_braces_no_func].b ||
(pc->parent_type != CT_FUNC_DEF)) &&
(!cpd.settings[UO_indent_braces_no_func].b ||
(pc->parent_type != CT_FUNC_CLASS_DEF)) &&
(!cpd.settings[UO_indent_braces_no_class].b ||
(pc->parent_type != CT_CLASS)) &&
(!cpd.settings[UO_indent_braces_no_struct].b ||
(pc->parent_type != CT_STRUCT)));
}
if (pc->type == CT_BRACE_CLOSE)
{
if (frm.pse[frm.pse_tos].type == CT_BRACE_OPEN)
{
/* Indent the brace to match the open brace */
indent_column_set(frm.pse[frm.pse_tos].brace_indent);
if (frm.pse[frm.pse_tos].ip.ref)
{
pc->indent.ref = frm.pse[frm.pse_tos].ip.ref;
pc->indent.delta = 0;
}
indent_pse_pop(frm, pc);
frm.level--;
}
}
else if (pc->type == CT_VBRACE_OPEN)
{
frm.level++;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
/* Always indent on virtual braces */
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
}
else if (pc->type == CT_BRACE_OPEN)
{
frm.level++;
indent_pse_push(frm, pc);
/* any '{' that is inside of a '(' overrides the '(' indent */
if (!cpd.settings[UO_indent_paren_open_brace].b &&
chunk_is_paren_open(frm.pse[frm.pse_tos - 1].pc) &&
chunk_is_newline(chunk_get_next_nc(pc)))
{
/* FIXME: I don't know how much of this is necessary, but it seems to work */
frm.pse[frm.pse_tos].brace_indent = 1 + (pc->brace_level * indent_size);
indent_column = frm.pse[frm.pse_tos].brace_indent;
frm.pse[frm.pse_tos].indent = indent_column + indent_size;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos - 1].indent_tmp = frm.pse[frm.pse_tos].indent_tmp;
}
else if (frm.paren_count != 0)
{
if (frm.pse[frm.pse_tos].pc->parent_type == CT_OC_BLOCK_EXPR)
{
if ((pc->flags & PCF_IN_OC_MSG) &&
cpd.settings[UO_indent_oc_block_msg].n)
{
frm.pse[frm.pse_tos].ip.ref = oc_msg_block_indent(pc, false, false, false, true);
frm.pse[frm.pse_tos].ip.delta = cpd.settings[UO_indent_oc_block_msg].n;
}
if (cpd.settings[UO_indent_oc_block].b ||
cpd.settings[UO_indent_oc_block_msg_xcode_style].b)
{
bool in_oc_msg = (pc->flags & PCF_IN_OC_MSG);
bool indent_from_keyword = cpd.settings[UO_indent_oc_block_msg_from_keyword].b && in_oc_msg;
bool indent_from_colon = cpd.settings[UO_indent_oc_block_msg_from_colon].b && in_oc_msg;
bool indent_from_caret = cpd.settings[UO_indent_oc_block_msg_from_caret].b && in_oc_msg;
bool indent_from_brace = cpd.settings[UO_indent_oc_block_msg_from_brace].b && 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)
if (cpd.settings[UO_indent_oc_block_msg_xcode_style].b)
{
chunk_t *colon = oc_msg_prev_colon(pc);
chunk_t *param_name = chunk_get_prev(colon);
chunk_t *before_param = chunk_get_prev(param_name);
if (before_param && (before_param->type == CT_NEWLINE))
{
indent_from_keyword = true;
indent_from_colon = false;
indent_from_caret = false;
indent_from_brace = false;
}
else
{
indent_from_brace = false;
indent_from_colon = false;
indent_from_caret = false;
indent_from_keyword = false;
}
}
chunk_t *ref = oc_msg_block_indent(pc, indent_from_brace,
indent_from_caret,
indent_from_colon,
indent_from_keyword);
if (ref)
{
frm.pse[frm.pse_tos].indent = indent_size + ref->column;
indent_column_set(frm.pse[frm.pse_tos].indent - indent_size);
}
else
{
frm.pse[frm.pse_tos].indent = 1 + ((pc->brace_level + 1) * indent_size);
indent_column_set(frm.pse[frm.pse_tos].indent - indent_size);
}
}
else
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
}
}
else
{
/* We are inside ({ ... }) -- indent one tab from the paren */
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
}
}
else
{
/* Use the prev indent level + indent_size. */
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
/* If this brace is part of a statement, bump it out by indent_brace */
if ((pc->parent_type == CT_IF) ||
(pc->parent_type == CT_ELSE) ||
(pc->parent_type == CT_ELSEIF) ||
(pc->parent_type == CT_TRY) ||
(pc->parent_type == CT_CATCH) ||
(pc->parent_type == CT_DO) ||
(pc->parent_type == CT_WHILE) ||
(pc->parent_type == CT_USING_STMT) ||
(pc->parent_type == CT_SWITCH) ||
(pc->parent_type == CT_FOR))
{
if (parent_token_indent != 0)
{
frm.pse[frm.pse_tos].indent += parent_token_indent - indent_size;
}
else
{
frm.pse[frm.pse_tos].indent += cpd.settings[UO_indent_brace].n;
indent_column_set(indent_column + cpd.settings[UO_indent_brace].n);
}
}
else if (pc->parent_type == CT_CASE)
{
/* An open brace with the parent of case does not indent by default
* UO_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.
*/
indent_column_set(frm.pse[frm.pse_tos - 1].indent - indent_size +
cpd.settings[UO_indent_case_brace].n);
/* Stuff inside the brace still needs to be indented */
frm.pse[frm.pse_tos].indent = indent_column + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
}
else if ((pc->parent_type == CT_CLASS) && !cpd.settings[UO_indent_class].b)
{
frm.pse[frm.pse_tos].indent -= indent_size;
}
else if (pc->parent_type == CT_NAMESPACE)
{
if (cpd.settings[UO_indent_namespace].b &&
cpd.settings[UO_indent_namespace_single_indent].b)
{
if (frm.pse[frm.pse_tos].ns_cnt)
{
/* undo indent on all except the first namespace */
frm.pse[frm.pse_tos].indent -= indent_size;
}
indent_column_set((frm.pse_tos <= 1) ? 1 : frm.pse[frm.pse_tos - 1].brace_indent);
}
else if ((pc->flags & PCF_LONG_BLOCK) ||
!cpd.settings[UO_indent_namespace].b)
{
/* don't indent long blocks */
frm.pse[frm.pse_tos].indent -= indent_size;
}
else /* indenting 'short' namespace */
{
if (cpd.settings[UO_indent_namespace_level].n > 0)
{
frm.pse[frm.pse_tos].indent -= indent_size;
frm.pse[frm.pse_tos].indent +=
cpd.settings[UO_indent_namespace_level].n;
}
}
frm.pse[frm.pse_tos].ns_cnt++;
}
else if ((pc->parent_type == CT_EXTERN) && !cpd.settings[UO_indent_extern].b)
{
frm.pse[frm.pse_tos].indent -= indent_size;
}
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
if ((pc->flags & PCF_DONT_INDENT) != 0)
{
frm.pse[frm.pse_tos].indent = pc->column;
indent_column_set(pc->column);
}
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--; };
*/
next = chunk_get_next_ncnl(pc);
if (!chunk_is_newline_between(pc, next))
{
frm.pse[frm.pse_tos].indent = next->column;
}
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].open_line = pc->orig_line;
/* Update the indent_column if needed */
if (brace_indent || (parent_token_indent != 0))
{
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
}
}
/* Save the brace indent */
frm.pse[frm.pse_tos].brace_indent = indent_column;
}
else if (pc->type == CT_SQL_END)
{
if (frm.pse[frm.pse_tos].type == CT_SQL_BEGIN)
{
indent_pse_pop(frm, pc);
frm.level--;
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
}
}
else if (pc->type == CT_SQL_BEGIN)
{
frm.level++;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
else if (pc->type == CT_SQL_EXEC)
{
frm.level++;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
}
else if (pc->type == CT_MACRO_OPEN)
{
frm.level++;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
else if (pc->type == CT_MACRO_ELSE)
{
if (frm.pse[frm.pse_tos].type == CT_MACRO_OPEN)
{
indent_column_set(frm.pse[frm.pse_tos - 1].indent);
}
}
else if (pc->type == CT_CASE)
{
/* Start a case - indent UO_indent_switch_case from the switch level */
tmp = frm.pse[frm.pse_tos].indent + cpd.settings[UO_indent_switch_case].n;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = tmp;
frm.pse[frm.pse_tos].indent_tmp = tmp - indent_size + cpd.settings[UO_indent_case_shift].n;
frm.pse[frm.pse_tos].indent_tab = tmp;
/* Always set on case statements */
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
/* comments before 'case' need to be aligned with the 'case' */
chunk_t *pct = pc;
while (((pct = chunk_get_prev_nnl(pct)) != NULL) &&
chunk_is_comment(pct))
{
chunk_t *t2 = chunk_get_prev(pct);
if (chunk_is_newline(t2))
{
pct->column = frm.pse[frm.pse_tos].indent_tmp;
pct->column_indent = pct->column;
}
}
}
else if (pc->type == CT_BREAK)
{
prev = chunk_get_prev_ncnl(pc);
if ((prev != NULL) &&
(prev->type == CT_BRACE_CLOSE) &&
(prev->parent_type == CT_CASE))
{
/* This only affects the 'break', so no need for a stack entry */
indent_column_set(prev->column);
}
}
else if (pc->type == CT_LABEL)
{
/* Labels get sent to the left or backed up */
if (cpd.settings[UO_indent_label].n > 0)
{
indent_column_set(cpd.settings[UO_indent_label].n);
}
else
{
indent_column_set(frm.pse[frm.pse_tos].indent +
cpd.settings[UO_indent_label].n);
}
}
else if (pc->type == CT_PRIVATE)
{
if (cpd.settings[UO_indent_access_spec_body].b)
{
tmp = frm.pse[frm.pse_tos].indent + indent_size;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = tmp;
frm.pse[frm.pse_tos].indent_tmp = tmp - indent_size;
frm.pse[frm.pse_tos].indent_tab = tmp;
/* If we are indenting the body, then we must leave the access spec
* indented at brace level
*/
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
}
else
{
/* Access spec labels get sent to the left or backed up */
if (cpd.settings[UO_indent_access_spec].n > 0)
{
indent_column_set(cpd.settings[UO_indent_access_spec].n);
}
else
{
indent_column_set(frm.pse[frm.pse_tos].indent +
cpd.settings[UO_indent_access_spec].n);
}
}
}
else if (pc->type == CT_CLASS)
{
frm.level++;
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
else if ((pc->type == CT_CLASS_COLON) ||
(pc->type == CT_CONSTR_COLON))
{
/* just indent one level */
indent_pse_push(frm, pc);
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
if ((cpd.settings[UO_indent_class_colon].b && (pc->type == CT_CLASS_COLON)) ||
(cpd.settings[UO_indent_constr_colon].b && (pc->type == CT_CONSTR_COLON)))
{
prev = chunk_get_prev(pc);
if (chunk_is_newline(prev))
{
frm.pse[frm.pse_tos].indent += cpd.settings[UO_indent_ctor_init_leading].n;
if (cpd.settings[UO_indent_ctor_init].n > 0)
{
frm.pse[frm.pse_tos].indent += cpd.settings[UO_indent_ctor_init].n;
frm.pse[frm.pse_tos].indent_tmp += cpd.settings[UO_indent_ctor_init].n;
frm.pse[frm.pse_tos].indent_tab += cpd.settings[UO_indent_ctor_init].n;
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
}
}
else
{
if (cpd.settings[UO_indent_class_on_colon].b && (pc->type == CT_CLASS_COLON))
{
frm.pse[frm.pse_tos].indent = pc->column;
}
else
{
next = chunk_get_next(pc);
if ((next != NULL) && !chunk_is_newline(next))
{
frm.pse[frm.pse_tos].indent = next->column;
}
}
}
}
}
else if ((pc->type == CT_PAREN_OPEN) ||
(pc->type == CT_SPAREN_OPEN) ||
(pc->type == CT_FPAREN_OPEN) ||
(pc->type == CT_SQUARE_OPEN) ||
(pc->type == CT_ANGLE_OPEN))
{
/* Open parens and squares - never update indent_column, unless right
* after a newline.
*/
bool skipped = false;
indent_pse_push(frm, pc);
if (chunk_is_newline(chunk_get_prev(pc)) &&
(pc->column != indent_column))
{
LOG_FMT(LINDENT, "%s: %d] indent => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
frm.pse[frm.pse_tos].indent = pc->column + pc->len();
if ((pc->type == CT_SQUARE_OPEN) && (cpd.lang_flags & LANG_D))
{
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
if (((pc->type == CT_FPAREN_OPEN) || (pc->type == CT_ANGLE_OPEN)) &&
((cpd.settings[UO_indent_func_call_param].b &&
((pc->parent_type == CT_FUNC_CALL) ||
(pc->parent_type == CT_FUNC_CALL_USER)))
||
(cpd.settings[UO_indent_func_proto_param].b &&
((pc->parent_type == CT_FUNC_PROTO) ||
(pc->parent_type == CT_FUNC_CLASS_PROTO)))
||
(cpd.settings[UO_indent_func_class_param].b &&
((pc->parent_type == CT_FUNC_CLASS_DEF) ||
(pc->parent_type == CT_FUNC_CLASS_PROTO)))
||
(cpd.settings[UO_indent_template_param].b &&
(pc->parent_type == CT_TEMPLATE))
||
(cpd.settings[UO_indent_func_ctor_var_param].b &&
(pc->parent_type == CT_FUNC_CTOR_VAR))
||
(cpd.settings[UO_indent_func_def_param].b &&
(pc->parent_type == CT_FUNC_DEF))))
{
/* Skip any continuation indents */
idx = frm.pse_tos - 1;
while ((idx > 0) &&
(frm.pse[idx].type != CT_BRACE_OPEN) &&
(frm.pse[idx].type != CT_VBRACE_OPEN) &&
(frm.pse[idx].type != CT_PAREN_OPEN) &&
(frm.pse[idx].type != CT_FPAREN_OPEN) &&
(frm.pse[idx].type != CT_SPAREN_OPEN) &&
(frm.pse[idx].type != CT_SQUARE_OPEN) &&
(frm.pse[idx].type != CT_ANGLE_OPEN) &&
(frm.pse[idx].type != CT_CLASS_COLON) &&
(frm.pse[idx].type != CT_CONSTR_COLON) &&
(frm.pse[idx].type != CT_ASSIGN_NL))
{
idx--;
skipped = true;
}
frm.pse[frm.pse_tos].indent = frm.pse[idx].indent + indent_size;
if (cpd.settings[UO_indent_func_param_double].b)
{
frm.pse[frm.pse_tos].indent += indent_size;
}
frm.pse[frm.pse_tos].indent_tab = frm.pse[frm.pse_tos].indent;
}
else if ((chunk_is_str(pc, "(", 1) && !cpd.settings[UO_indent_paren_nl].b) ||
(chunk_is_str(pc, "<", 1) && !cpd.settings[UO_indent_paren_nl].b) || /* TODO: add indent_angle_nl? */
(chunk_is_str(pc, "[", 1) && !cpd.settings[UO_indent_square_nl].b))
{
next = chunk_get_next_nc(pc);
if (chunk_is_newline(next))
{
int sub = 1;
if (frm.pse[frm.pse_tos - 1].type == CT_ASSIGN ||
frm.pse[frm.pse_tos - 1].type == CT_RETURN)
{
sub = 2;
}
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - sub].indent + indent_size;
skipped = true;
}
else
{
if (next && !chunk_is_comment(next))
{
if (next->type == CT_SPACE)
{
next = chunk_get_next_nc(next);
}
frm.pse[frm.pse_tos].indent = next->column;
}
}
}
if ((pc->type == CT_FPAREN_OPEN) &&
chunk_is_newline(chunk_get_prev(pc)) &&
!chunk_is_newline(chunk_get_next(pc)))
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
indent_column_set(frm.pse[frm.pse_tos].indent);
}
if ((cpd.settings[UO_indent_continue].n != 0) && (!skipped))
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent;
if ((pc->level == pc->brace_level) &&
((pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN)))
{
//frm.pse[frm.pse_tos].indent += abs(cpd.settings[UO_indent_continue].n);
frm.pse[frm.pse_tos].indent = calc_indent_continue(frm, frm.pse_tos);
frm.pse[frm.pse_tos].indent_cont = true;
}
}
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
frm.paren_count++;
}
else if ((pc->type == CT_ASSIGN) ||
(pc->type == CT_IMPORT) ||
(pc->type == CT_USING))
{
/**
* if there is a newline after the '=' or the line starts with a '=',
* just indent one level,
* otherwise align on the '='.
*/
if ((pc->type == CT_ASSIGN) && chunk_is_newline(chunk_get_prev(pc)))
{
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent + indent_size;
indent_column_set(frm.pse[frm.pse_tos].indent_tmp);
LOG_FMT(LINDENT, "%s: %d] assign => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, frm.pse[frm.pse_tos].indent_tmp);
}
next = chunk_get_next(pc);
if (next != NULL)
{
indent_pse_push(frm, pc);
if (cpd.settings[UO_indent_continue].n != 0)
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent;
if ((pc->level == pc->brace_level) &&
((pc->type != CT_ASSIGN) ||
((pc->parent_type != CT_FUNC_PROTO) && (pc->parent_type != CT_FUNC_DEF))))
{
//frm.pse[frm.pse_tos].indent += abs(cpd.settings[UO_indent_continue].n);
frm.pse[frm.pse_tos].indent = calc_indent_continue(frm, frm.pse_tos);
frm.pse[frm.pse_tos].indent_cont = true;
}
}
else if (chunk_is_newline(next) || !cpd.settings[UO_indent_align_assign].b)
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
if (pc->type == CT_ASSIGN)
{
frm.pse[frm.pse_tos].type = CT_ASSIGN_NL;
}
}
else
{
frm.pse[frm.pse_tos].indent = pc->column + pc->len() + 1;
}
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
}
}
else if ((pc->type == CT_RETURN) ||
((pc->type == CT_THROW) && (pc->parent_type == CT_NONE)))
{
/* don't count returns inside a () or [] */
if (pc->level == pc->brace_level)
{
indent_pse_push(frm, pc);
if (chunk_is_newline(chunk_get_next(pc)))
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
}
else
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + pc->len() + 1;
}
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos - 1].indent;
}
}
else if ((pc->type == CT_OC_SCOPE) || (pc->type == CT_TYPEDEF))
{
indent_pse_push(frm, pc);
if (cpd.settings[UO_indent_continue].n != 0)
{
//frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent +
// abs(cpd.settings[UO_indent_continue].n);
frm.pse[frm.pse_tos].indent = calc_indent_continue(frm, frm.pse_tos - 1);
frm.pse[frm.pse_tos].indent_cont = true;
}
else
{
frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;
}
}
else
{
/* anything else? */
}
/**
* Handle variable definition continuation indenting
*/
if ((vardefcol == 0) &&
((pc->type == CT_WORD) || (pc->type == CT_FUNC_CTOR_VAR)) &&
((pc->flags & PCF_IN_FCN_DEF) == 0) &&
((pc->flags & PCF_VAR_1ST_DEF) == PCF_VAR_1ST_DEF))
{
if (cpd.settings[UO_indent_continue].n != 0)
{
//vardefcol = frm.pse[frm.pse_tos].indent +
// abs(cpd.settings[UO_indent_continue].n);
vardefcol = calc_indent_continue(frm, frm.pse_tos);
frm.pse[frm.pse_tos].indent_cont = true;
}
else if (cpd.settings[UO_indent_var_def_cont].b ||
chunk_is_newline(chunk_get_prev(pc)))
{
vardefcol = frm.pse[frm.pse_tos].indent + indent_size;
}
else
{
vardefcol = pc->column;
/* need to skip backward over any '*' */
chunk_t *tmp = chunk_get_prev_nc(pc);
while (chunk_is_token(tmp, CT_PTR_TYPE))
{
vardefcol = tmp->column;
tmp = chunk_get_prev_nc(tmp);
}
}
}
if (chunk_is_semicolon(pc) ||
((pc->type == CT_BRACE_OPEN) && (pc->parent_type == CT_FUNCTION)))
{
vardefcol = 0;
}
/**
* Indent the line if needed
*/
if (did_newline && !chunk_is_newline(pc) && (pc->len() != 0))
{
pc->column_indent = frm.pse[frm.pse_tos].indent_tab;
if (frm.pse[frm.pse_tos].ip.ref)
{
pc->indent.ref = frm.pse[frm.pse_tos].ip.ref;
pc->indent.delta = frm.pse[frm.pse_tos].ip.delta;
}
LOG_FMT(LINDENT2, "%s: %d] %d/%d for %s\n",
__func__, pc->orig_line, pc->column_indent, indent_column, pc->str.c_str());
/**
* Check for special continuations.
* Note that some of these could be done as a stack item like
* everything else
*/
prev = chunk_get_prev_ncnl(pc);
next = chunk_get_next_ncnl(pc);
bool do_vardefcol = false;
if ((vardefcol > 0) &&
(pc->level == pc->brace_level) &&
prev &&
((prev->type == CT_COMMA) ||
(prev->type == CT_TYPE) ||
(prev->type == CT_PTR_TYPE) ||
(prev->type == CT_WORD)))
{
chunk_t *tmp = pc;
while (chunk_is_token(tmp, CT_PTR_TYPE))
{
tmp = chunk_get_next_ncnl(tmp);
}
if (tmp && ((tmp->flags & PCF_VAR_DEF) != 0) &&
((tmp->type == CT_WORD) || (tmp->type == CT_FUNC_CTOR_VAR)))
{
do_vardefcol = true;
}
}
if ((pc->flags & PCF_DONT_INDENT) != 0)
{
/* no change */
}
else if ((pc->parent_type == CT_SQL_EXEC) &&
cpd.settings[UO_indent_preserve_sql].b)
{
reindent_line(pc, sql_col + (pc->orig_col - sql_orig_col));
LOG_FMT(LINDENT, "Indent SQL: [%s] to %d (%d/%d)\n",
pc->str.c_str(), pc->column, sql_col, sql_orig_col);
}
else if (((pc->flags & PCF_STMT_START) == 0) &&
((pc->type == CT_MEMBER) ||
(pc->type == CT_DC_MEMBER) ||
((prev != NULL) &&
((prev->type == CT_MEMBER) ||
(prev->type == CT_DC_MEMBER)))))
{
tmp = cpd.settings[UO_indent_member].n + indent_column;
LOG_FMT(LINDENT, "%s: %d] member => %d\n",
__func__, pc->orig_line, tmp);
reindent_line(pc, tmp);
}
else if (do_vardefcol)
{
LOG_FMT(LINDENT, "%s: %d] Vardefcol => %d\n",
__func__, pc->orig_line, vardefcol);
reindent_line(pc, vardefcol);
}
else if ((pc->type == CT_NAMESPACE) &&
cpd.settings[UO_indent_namespace].b &&
cpd.settings[UO_indent_namespace_single_indent].b &&
frm.pse[frm.pse_tos].ns_cnt)
{
LOG_FMT(LINDENT, "%s: %d] Namespace => %d\n",
__func__, pc->orig_line, frm.pse[frm.pse_tos].brace_indent);
reindent_line(pc, frm.pse[frm.pse_tos].brace_indent);
}
else if ((pc->type == CT_STRING) && (prev != NULL) && (prev->type == CT_STRING) &&
cpd.settings[UO_indent_align_string].b)
{
tmp = (xml_indent != 0) ? xml_indent : prev->column;
LOG_FMT(LINDENT, "%s: %d] String => %d\n",
__func__, pc->orig_line, tmp);
reindent_line(pc, tmp);
}
else if (chunk_is_comment(pc))
{
LOG_FMT(LINDENT, "%s: %d] comment => %d\n",
__func__, pc->orig_line, frm.pse[frm.pse_tos].indent_tmp);
indent_comment(pc, frm.pse[frm.pse_tos].indent_tmp);
}
else if (pc->type == CT_PREPROC)
{
LOG_FMT(LINDENT, "%s: %d] pp-indent => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
else if (chunk_is_paren_close(pc) || (pc->type == CT_ANGLE_CLOSE))
{
/* This is a big hack. We assume that since we hit a paren close,
* that we just removed a paren open */
if (frm.pse[frm.pse_tos + 1].type == c_token_t(pc->type - 1))
{
chunk_t *ck1 = frm.pse[frm.pse_tos + 1].pc;
chunk_t *ck2 = chunk_get_prev(ck1);
/* If the open paren was the first thing on the line or we are
* doing mode 1, then put the close paren in the same column */
if (chunk_is_newline(ck2) ||
(cpd.settings[UO_indent_paren_close].n == 1))
{
indent_column_set(ck1->column);
}
else
{
if (cpd.settings[UO_indent_paren_close].n != 2)
{
indent_column_set(frm.pse[frm.pse_tos + 1].indent_tmp);
if (cpd.settings[UO_indent_paren_close].n == 1)
{
indent_column--;
}
}
}
}
LOG_FMT(LINDENT, "%s: %d] cl paren => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
else if (pc->type == CT_COMMA)
{
if (cpd.settings[UO_indent_comma_paren].b &&
chunk_is_paren_open(frm.pse[frm.pse_tos].pc))
{
indent_column_set(frm.pse[frm.pse_tos].pc->column);
}
LOG_FMT(LINDENT, "%s: %d] comma => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
else if (cpd.settings[UO_indent_func_const].n &&
(pc->type == CT_QUALIFIER) &&
(strncasecmp(pc->text(), "const", pc->len()) == 0) &&
((next == NULL) ||
(next->type == CT_BRACED) ||
(next->type == CT_BRACE_OPEN) ||
(next->type == CT_NEWLINE) ||
(next->type == CT_SEMICOLON) ||
(next->type == CT_THROW) ||
(next->type == CT_VBRACE_OPEN)))
{
// indent const - void GetFoo(void)\n const\n { return (m_Foo); }
indent_column_set(cpd.settings[UO_indent_func_const].n);
LOG_FMT(LINDENT, "%s: %d] const => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
else if (cpd.settings[UO_indent_func_throw].n &&
(pc->type == CT_THROW) &&
(pc->parent_type != CT_NONE))
{
// indent throw - void GetFoo(void)\n throw()\n { return (m_Foo); }
indent_column_set(cpd.settings[UO_indent_func_throw].n);
LOG_FMT(LINDENT, "%s: %d] throw => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
else if (pc->type == CT_BOOL)
{
if (cpd.settings[UO_indent_bool_paren].b &&
chunk_is_paren_open(frm.pse[frm.pse_tos].pc))
{
indent_column_set(frm.pse[frm.pse_tos].pc->column);
if (cpd.settings[UO_indent_first_bool_expr].b)
{
reindent_line(chunk_get_next(frm.pse[frm.pse_tos].pc),
indent_column + pc->len() + 1);
}
}
LOG_FMT(LINDENT, "%s: %d] bool => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
else
{
if (pc->column != indent_column)
{
LOG_FMT(LINDENT, "%s: %d] indent => %d [%s]\n",
__func__, pc->orig_line, indent_column, pc->str.c_str());
reindent_line(pc, indent_column);
}
}
did_newline = false;
if ((pc->type == CT_SQL_EXEC) ||
(pc->type == CT_SQL_BEGIN) ||
(pc->type == CT_SQL_END))
{
sql_col = pc->column;
sql_orig_col = pc->orig_col;
}
/* Handle indent for variable defs at the top of a block of code */
if (pc->flags & PCF_VAR_TYPE)
{
if (!frm.pse[frm.pse_tos].non_vardef &&
(frm.pse[frm.pse_tos].type == CT_BRACE_OPEN))
{
tmp = indent_column;
if (cpd.settings[UO_indent_var_def_blk].n > 0)
{
tmp = cpd.settings[UO_indent_var_def_blk].n;
}
else
{
tmp += cpd.settings[UO_indent_var_def_blk].n;
}
reindent_line(pc, tmp);
LOG_FMT(LINDENT, "%s: %d] var_type indent => %d [%s]\n",
__func__, pc->orig_line, tmp, pc->str.c_str());
}
}
else
{
if (pc != frm.pse[frm.pse_tos].pc)
{
frm.pse[frm.pse_tos].non_vardef = true;
}
}
}
/* if we hit a newline, reset indent_tmp */
if (chunk_is_newline(pc) ||
(pc->type == CT_COMMENT_MULTI) ||
(pc->type == CT_COMMENT_CPP))
{
frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
/**
* Handle the case of a multi-line #define w/o anything on the
* first line (indent_tmp will be 1 or 0)
*/
if ((pc->type == CT_NL_CONT) &&
(frm.pse[frm.pse_tos].indent_tmp <= indent_size))
{
frm.pse[frm.pse_tos].indent_tmp = indent_size + 1;
}
/* Get ready to indent the next item */
did_newline = true;
}
/* Check for open XML tags "</..." */
if (cpd.settings[UO_indent_xml_string].n > 0)
{
if (pc->type == CT_STRING)
{
if ((pc->len() > 4) &&
(pc->str[1] == '<') &&
(pc->str[2] != '/') &&
(pc->str[pc->len() - 3] != '/'))
{
if (xml_indent <= 0)
{
xml_indent = pc->column;
}
xml_indent += cpd.settings[UO_indent_xml_string].n;
}
}
}
if (!chunk_is_comment(pc) && !chunk_is_newline(pc))
{
prev = pc;
}
pc = chunk_get_next(pc);
}
null_pc:
/* Throw out any stuff inside a preprocessor - no need to warn */
while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc)
{
indent_pse_pop(frm, pc);
}
/* Throw out any VBRACE_OPEN at the end - implied with the end of file */
while ((frm.pse_tos > 0) && (frm.pse[frm.pse_tos].type == CT_VBRACE_OPEN))
{
indent_pse_pop(frm, pc);
}
for (idx = 1; idx <= frm.pse_tos; idx++)
{
LOG_FMT(LWARN, "%s:%d Unmatched %s\n",
cpd.filename, frm.pse[idx].open_line,
get_token_name(frm.pse[idx].type));
cpd.error_count++;
}
quick_align_again();
quick_indent_again();
}
/**
* returns true if forward 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_t *start)
{
LOG_FUNC_ENTRY();
chunk_t *pc = start;
int nl_count = 0;
if (!chunk_is_single_line_comment(pc))
{
return(false);
}
/* scan forward, if only single newlines and comments before next line of
* code, we want to apply */
while ((pc = chunk_get_next(pc)) != NULL)
{
if (chunk_is_newline(pc))
{
if ((nl_count > 0) || (pc->nl_count > 1))
{
return(false);
}
nl_count++;
}
else
{
nl_count = 0;
if (!chunk_is_single_line_comment(pc))
{
/* here we check for things to run into that we wouldn't want to
* indent the comment for. for example, non-single line comment,
* closing brace */
if (chunk_is_comment(pc) || chunk_is_closing_brace(pc))
{
return(false);
}
return(true);
}
}
}
return(false);
}
/**
* 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_t *pc, int col)
{
LOG_FUNC_ENTRY();
chunk_t *nl;
chunk_t *prev;
LOG_FMT(LCMTIND, "%s: line %d, col %d, level %d: ", __func__,
pc->orig_line, pc->orig_col, pc->level);
/* force column 1 comment to column 1 if not changing them */
if ((pc->orig_col == 1) && !cpd.settings[UO_indent_col1_comment].b &&
((pc->flags & PCF_INSERTED) == 0))
{
LOG_FMT(LCMTIND, "rule 1 - keep in col 1\n");
reindent_line(pc, 1);
return;
}
nl = chunk_get_prev(pc);
/* outside of any expression or statement? */
if (pc->level == 0)
{
if ((nl != NULL) && (nl->nl_count > 1))
{
LOG_FMT(LCMTIND, "rule 2 - level 0, nl before\n");
reindent_line(pc, 1);
return;
}
}
prev = chunk_get_prev(nl);
if (chunk_is_comment(prev) && (nl->nl_count == 1))
{
int coldiff = prev->orig_col - pc->orig_col;
if ((coldiff <= 3) && (coldiff >= -3))
{
reindent_line(pc, prev->column);
LOG_FMT(LCMTIND, "rule 3 - prev comment, coldiff = %d, now in %d\n",
coldiff, pc->column);
return;
}
}
/* check if special single line comment rule applies */
if ((cpd.settings[UO_indent_sing_line_comments].n > 0) &&
single_line_comment_indent_rule_applies(pc))
{
reindent_line(pc, col + cpd.settings[UO_indent_sing_line_comments].n);
LOG_FMT(LCMTIND, "rule 4 - single line comment indent, now in %d\n", pc->column);
return;
}
LOG_FMT(LCMTIND, "rule 5 - fall-through, stay in %d\n", col);
reindent_line(pc, col);
}
/**
* Scan to see if the whole file is covered by one #ifdef
*/
static bool ifdef_over_whole_file()
{
LOG_FUNC_ENTRY();
chunk_t *pc;
chunk_t *next;
int stage = 0;
/* the results for this file are cached */
if (cpd.ifdef_over_whole_file)
{
return (cpd.ifdef_over_whole_file > 0);
}
for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
{
if (chunk_is_comment(pc) || chunk_is_newline(pc))
{
continue;
}
if (stage == 0)
{
/* Check the first PP, make sure it is an #if type */
if (pc->type != CT_PREPROC)
{
break;
}
next = chunk_get_next(pc);
if ((next == NULL) || (next->type != CT_PP_IF))
{
break;
}
stage = 1;
}
else if (stage == 1)
{
/* Scan until a PP at level 0 is found - the close to the #if */
if ((pc->type == CT_PREPROC) &&
(pc->pp_level == 0))
{
stage = 2;
}
continue;
}
else if (stage == 2)
{
/* We should only see the rest of the preprocessor */
if ((pc->type == CT_PREPROC) ||
((pc->flags & PCF_IN_PREPROC) == 0))
{
stage = 0;
break;
}
}
}
cpd.ifdef_over_whole_file = (stage == 2) ? 1 : -1;
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);
}
/**
* Indent the preprocessor stuff from column 1.
* FIXME: This is broken if there is a comment or escaped newline
* between '#' and 'define'.
*/
void indent_preproc(void)
{
LOG_FUNC_ENTRY();
chunk_t *pc;
chunk_t *next;
int pp_level;
int pp_level_sub = 0;
/* Scan to see if the whole file is covered by one #ifdef */
if (ifdef_over_whole_file())
{
pp_level_sub = 1;
}
for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
{
if (pc->type != CT_PREPROC)
{
continue;
}
next = chunk_get_next_ncnl(pc);
pp_level = pc->pp_level - pp_level_sub;
if (pp_level < 0)
{
pp_level = 0;
}
/* Adjust the indent of the '#' */
if ((cpd.settings[UO_pp_indent].a & AV_ADD) != 0)
{
reindent_line(pc, 1 + pp_level * cpd.settings[UO_pp_indent_count].n);
}
else if ((cpd.settings[UO_pp_indent].a & AV_REMOVE) != 0)
{
reindent_line(pc, 1);
}
/* Add spacing by adjusting the length */
if ((cpd.settings[UO_pp_space].a != AV_IGNORE) && (next != NULL))
{
if ((cpd.settings[UO_pp_space].a & AV_ADD) != 0)
{
int mult = cpd.settings[UO_pp_space_count].n;
if (mult < 1)
{
mult = 1;
}
reindent_line(next, pc->column + pc->len() + (pp_level * mult));
}
else if ((cpd.settings[UO_pp_space].a & AV_REMOVE) != 0)
{
reindent_line(next, pc->column + pc->len());
}
}
/* Mark as already handled if not region stuff or in column 1 */
if ((!cpd.settings[UO_pp_indent_at_level].b ||
(pc->brace_level <= ((pc->parent_type == CT_PP_DEFINE) ? 1 : 0))) &&
(pc->parent_type != CT_PP_REGION) &&
(pc->parent_type != CT_PP_ENDREGION))
{
if (!cpd.settings[UO_pp_define_at_level].b ||
(pc->parent_type != CT_PP_DEFINE))
{
pc->flags |= PCF_DONT_INDENT;
}
}
LOG_FMT(LPPIS, "%s: Indent line %d to %d (len %d, next->col %d)\n",
__func__, pc->orig_line, 1 + pp_level, pc->len(), next->column);
}
}