/** * Scans between two parens and adds additional parens if needed. * This function is recursive. If it hits another open paren, it'll call itself * with the new bounds. * * Adds optional parens in an IF or SWITCH conditional statement. * * This basically just checks for a CT_COMPARE that isn't surrounded by parens. * The edges for the compare are the open, close and any CT_BOOL tokens. * * This only handleds VERY simple patterns: * (!a && b) => (!a && b) -- no change * (a && b == 1) => (a && (b == 1)) * (a == 1 || b > 2) => ((a == 1) || (b > 2)) * * FIXME: we really should bail if we transition between a preprocessor and * a non-preprocessor */ static void check_bool_parens(chunk_t *popen, chunk_t *pclose, int nest) { LOG_FUNC_ENTRY(); chunk_t *pc; chunk_t *ref = popen; chunk_t *next; bool hit_compare = false; LOG_FMT(LPARADD, "%s(%d): popen on %d, col %d, pclose on %d, col %d, level=%d\n", __func__, nest, popen->orig_line, popen->orig_col, pclose->orig_line, pclose->orig_col, popen->level); pc = popen; while (((pc = chunk_get_next_ncnl(pc)) != NULL) && (pc != pclose)) { if (pc->flags & PCF_IN_PREPROC) { LOG_FMT(LPARADD2, " -- bail on PP %s [%s] at line %d col %d, level %d\n", get_token_name(pc->type), pc->str.c_str(), pc->orig_line, pc->orig_col, pc->level); return; } if ((pc->type == CT_BOOL) || (pc->type == CT_QUESTION) || (pc->type == CT_COND_COLON) || (pc->type == CT_COMMA)) { LOG_FMT(LPARADD2, " -- %s [%s] at line %d col %d, level %d\n", get_token_name(pc->type), pc->str.c_str(), pc->orig_line, pc->orig_col, pc->level); if (hit_compare) { hit_compare = false; add_parens_between(ref, pc); } ref = pc; } else if (pc->type == CT_COMPARE) { LOG_FMT(LPARADD2, " -- compare [%s] at line %d col %d, level %d\n", pc->str.c_str(), pc->orig_line, pc->orig_col, pc->level); hit_compare = true; } else if (chunk_is_paren_open(pc)) { next = chunk_skip_to_match(pc); if (next != NULL) { check_bool_parens(pc, next, nest + 1); pc = next; } } else if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_SQUARE_OPEN) || (pc->type == CT_ANGLE_OPEN)) { /* Skip [], {}, and <> */ pc = chunk_skip_to_match(pc); } } if (hit_compare && (ref != popen)) { add_parens_between(ref, pclose); } }
/** * Traverse the if chain and see if all can be removed */ static void process_if_chain(chunk_t *br_start) { chunk_t *braces[256]; chunk_t *br_close; int br_cnt = 0; chunk_t *pc; bool must_have_braces = false; bool tmp; pc = br_start; LOG_FMT(LBRCH, "%s: if starts on line %d\n", __func__, br_start->orig_line); while (pc != NULL) { if (pc->type == CT_BRACE_OPEN) { tmp = can_remove_braces(pc); LOG_FMT(LBRCH, " [%d] line %d - can%s remove %s\n", br_cnt, pc->orig_line, tmp ? "" : "not", get_token_name(pc->type)); if (!tmp) { must_have_braces = true; } } else { tmp = should_add_braces(pc); if (tmp) { must_have_braces = true; } LOG_FMT(LBRCH, " [%d] line %d - %s %s\n", br_cnt, pc->orig_line, tmp ? "should add" : "ignore", get_token_name(pc->type)); } braces[br_cnt++] = pc; br_close = chunk_skip_to_match(pc, CNAV_PREPROC); if (br_close == NULL) { break; } braces[br_cnt++] = br_close; pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC); if ((pc == NULL) || (pc->type != CT_ELSE)) { break; } pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_ELSEIF)) { while ((pc != NULL) && (pc->type != CT_VBRACE_OPEN) && (pc->type != CT_BRACE_OPEN)) { pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); } } if (pc == NULL) { break; } if ((pc->type != CT_BRACE_OPEN) && (pc->type != CT_VBRACE_OPEN)) { break; } } if (must_have_braces) { LOG_FMT(LBRCH, "%s: add braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { braces[br_cnt]->flags |= PCF_KEEP_BRACE; if ((braces[br_cnt]->type == CT_VBRACE_OPEN) || (braces[br_cnt]->type == CT_VBRACE_CLOSE)) { LOG_FMT(LBRCH, " %d", braces[br_cnt]->orig_line); convert_vbrace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " {%d}", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } else { LOG_FMT(LBRCH, "%s: remove braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { if ((braces[br_cnt]->type == CT_BRACE_OPEN) || (braces[br_cnt]->type == CT_BRACE_CLOSE)) { LOG_FMT(LBRCH, " {%d}", braces[br_cnt]->orig_line); convert_brace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " %d", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } }
static void process_if_chain(chunk_t *br_start) { LOG_FUNC_ENTRY(); chunk_t *braces[256]; int br_cnt = 0; bool must_have_braces = false; chunk_t *pc = br_start; LOG_FMT(LBRCH, "%s: if starts on line %zu\n", __func__, br_start->orig_line); while (pc != NULL) { if (pc->type == CT_BRACE_OPEN) { bool tmp = can_remove_braces(pc); LOG_FMT(LBRCH, " [%d] line %zu - can%s remove %s\n", br_cnt, pc->orig_line, tmp ? "" : "not", get_token_name(pc->type)); if (!tmp) { must_have_braces = true; } } else { bool tmp = should_add_braces(pc); if (tmp) { must_have_braces = true; } LOG_FMT(LBRCH, " [%d] line %zu - %s %s\n", br_cnt, pc->orig_line, tmp ? "should add" : "ignore", get_token_name(pc->type)); } braces[br_cnt++] = pc; chunk_t *br_close = chunk_skip_to_match(pc, CNAV_PREPROC); if (br_close == NULL) { break; } braces[br_cnt++] = br_close; pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC); if ((pc == NULL) || (pc->type != CT_ELSE)) { break; } if (cpd.settings[UO_mod_full_brace_if_chain_only].b) { // There is an 'else' - we want full braces. must_have_braces = true; } pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_ELSEIF)) { while ((pc != NULL) && (pc->type != CT_VBRACE_OPEN) && (pc->type != CT_BRACE_OPEN)) { pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); } } if (pc == NULL) { break; } if ((pc->type != CT_BRACE_OPEN) && (pc->type != CT_VBRACE_OPEN)) { break; } } if (must_have_braces) { LOG_FMT(LBRCH, "%s: add braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { chunk_flags_set(braces[br_cnt], PCF_KEEP_BRACE); if ((braces[br_cnt]->type == CT_VBRACE_OPEN) || (braces[br_cnt]->type == CT_VBRACE_CLOSE)) { LOG_FMT(LBRCH, " %zu", braces[br_cnt]->orig_line); convert_vbrace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " {%zu}", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } else if (cpd.settings[UO_mod_full_brace_if_chain].b) { // This might run because either UO_mod_full_brace_if_chain or UO_mod_full_brace_if_chain_only is used. // We only want to remove braces if the first one is active. LOG_FMT(LBRCH, "%s: remove braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { if ((braces[br_cnt]->type == CT_BRACE_OPEN) || (braces[br_cnt]->type == CT_BRACE_CLOSE)) { LOG_FMT(LBRCH, " {%zu}", braces[br_cnt]->orig_line); convert_brace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " %zu", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } } // process_if_chain
/** * Aligns all assignment operators on the same level as first, starting with * first. * * For variable definitions, only consider the '=' for the first variable. * Otherwise, only look at the first '=' on the line. */ chunk_t *align_assign(chunk_t *first, int span, int thresh) { int my_level; chunk_t *pc; int tmp; int var_def_cnt = 0; int equ_count = 0; if (first == NULL) { return(NULL); } my_level = first->level; if (span <= 0) { return(chunk_get_next(first)); } LOG_FMT(LALASS, "%s[%d]: checking %.*s on line %d - span=%d thresh=%d\n", __func__, my_level, first->len, first->str, first->orig_line, span, thresh); AlignStack as; // regular assigns AlignStack vdas; // variable def assigns as.Start(span, thresh); as.m_right_align = true; vdas.Start(span, thresh); vdas.m_right_align = true; pc = first; while ((pc != NULL) && ((pc->level >= my_level) || (pc->level == 0))) { /* Don't check inside PAREN or SQUARE groups */ if ((pc->type == CT_SPAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SQUARE_OPEN) || (pc->type == CT_PAREN_OPEN)) { tmp = pc->orig_line; pc = chunk_skip_to_match(pc); if (pc != NULL) { as.NewLines(pc->orig_line - tmp); vdas.NewLines(pc->orig_line - tmp); } continue; } /* Recurse if a brace set is found */ if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_VBRACE_OPEN)) { int myspan; int mythresh; tmp = pc->orig_line; if (pc->parent_type == CT_ENUM) { myspan = cpd.settings[UO_align_enum_equ_span].n; mythresh = cpd.settings[UO_align_enum_equ_thresh].n; } else { myspan = cpd.settings[UO_align_assign_span].n; mythresh = cpd.settings[UO_align_assign_thresh].n; } pc = align_assign(chunk_get_next_ncnl(pc), myspan, mythresh); if (pc != NULL) { /* do a rough count of the number of lines just spanned */ as.NewLines(pc->orig_line - tmp); vdas.NewLines(pc->orig_line - tmp); } continue; } if (chunk_is_newline(pc)) { as.NewLines(pc->nl_count); vdas.NewLines(pc->nl_count); var_def_cnt = 0; equ_count = 0; } else if ((pc->flags & PCF_VAR_DEF) != 0) { var_def_cnt++; } else if (var_def_cnt > 1) { /* we hit the second variable def - don't look for assigns */ } else if ((equ_count == 0) && (pc->type == CT_ASSIGN)) { //fprintf(stderr, "%s: ** %s level=%d line=%d col=%d prev=%d count=%d\n", // __func__, pc->str, pc->level, pc->orig_line, pc->orig_col, prev_equ_type, // equ_count); equ_count++; if (var_def_cnt != 0) { vdas.Add(pc); } else { as.Add(pc); } } pc = chunk_get_next(pc); } as.End(); vdas.End(); if (pc != NULL) { LOG_FMT(LALASS, "%s: done on %.*s on line %d\n", __func__, pc->len, pc->str, pc->orig_line); } else { LOG_FMT(LALASS, "%s: done on NULL\n", __func__); } return(pc); }