static void append_tag_name(unc_text &txt, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *tmp = pc; /* step backwards over all a::b stuff */ while ((tmp = chunk_get_prev_ncnl(tmp)) != NULL) { if ((tmp->type != CT_DC_MEMBER) && (tmp->type != CT_MEMBER)) { break; } tmp = chunk_get_prev_ncnl(tmp); pc = tmp; if (!chunk_is_word(tmp)) { break; } } txt += pc->str; while ((pc = chunk_get_next_ncnl(pc)) != NULL) { if ((pc->type != CT_DC_MEMBER) && (pc->type != CT_MEMBER)) { break; } txt += pc->str; pc = chunk_get_next_ncnl(pc); if (pc) { txt += pc->str; } } }
static void mod_case_brace(void) { LOG_FUNC_ENTRY(); chunk_t *pc = chunk_get_head(); while (pc != NULL) { chunk_t *next = chunk_get_next_ncnl(pc, CNAV_PREPROC); if (next == NULL) { return; } if ((cpd.settings[UO_mod_case_brace].a == AV_REMOVE) && (pc->type == CT_BRACE_OPEN) && (pc->parent_type == CT_CASE)) { pc = mod_case_brace_remove(pc); } else if ((cpd.settings[UO_mod_case_brace].a & AV_ADD) && (pc->type == CT_CASE_COLON) && (next->type != CT_BRACE_OPEN) && (next->type != CT_BRACE_CLOSE) && (next->type != CT_CASE)) { pc = mod_case_brace_add(pc); } else { pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); } } }
/** * Remove the case brace, if allowable. */ static chunk_t *mod_case_brace_remove(chunk_t *br_open) { LOG_FUNC_ENTRY(); chunk_t *pc; chunk_t *br_close; chunk_t *next = chunk_get_next_ncnl(br_open, CNAV_PREPROC); LOG_FMT(LMCB, "%s: line %lu", __func__, br_open->orig_line); /* Find the matching brace close */ br_close = chunk_get_next_type(br_open, CT_BRACE_CLOSE, br_open->level, CNAV_PREPROC); if (br_close == NULL) { LOG_FMT(LMCB, " - no close\n"); return(next); } /* Make sure 'break', 'return', 'goto', 'case' or '}' is after the close brace */ pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC); if ((pc == NULL) || ((pc->type != CT_BREAK) && (pc->type != CT_RETURN) && (pc->type != CT_CASE) && (pc->type != CT_GOTO) && (pc->type != CT_BRACE_CLOSE))) { LOG_FMT(LMCB, " - after '%s'\n", (pc == NULL) ? "<null>" : get_token_name(pc->type)); return(next); } /* scan to make sure there are no definitions at brace level between braces */ for (pc = br_open; pc != br_close; pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) { if ((pc->level == (br_open->level + 1)) && (pc->flags & PCF_VAR_DEF)) { LOG_FMT(LMCB, " - vardef on line %lu: '%s'\n", pc->orig_line, pc->text()); return(next); } } LOG_FMT(LMCB, " - removing braces on lines %lu and %lu\n", br_open->orig_line, br_close->orig_line); for (pc = br_open; pc != br_close; pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) { pc->brace_level--; pc->level--; } next = chunk_get_prev(br_open, CNAV_PREPROC); chunk_del(br_open); chunk_del(br_close); return(chunk_get_next(next, CNAV_PREPROC)); } // mod_case_brace_remove
/** * Add an open paren after first and add a close paren before the last */ static void add_parens_between(chunk_t *first, chunk_t *last) { chunk_t pc; chunk_t *first_n; chunk_t *last_p; chunk_t *tmp; LOG_FMT(LPARADD, "%s: line %d between %.*s [lvl=%d] and %.*s [lvl=%d]\n", __func__, first->orig_line, first->len, first->str, first->level, last->len, last->str, last->level); /* Don't do anything if we have a bad sequence, ie "&& )" */ first_n = chunk_get_next_ncnl(first); if (first_n == last) { return; } memset(&pc, 0, sizeof(pc)); pc.type = CT_PAREN_OPEN; pc.str = "("; pc.len = 1; pc.flags = first_n->flags & PCF_COPY_FLAGS; pc.level = first_n->level; pc.pp_level = first_n->pp_level; pc.brace_level = first_n->brace_level; chunk_add_before(&pc, first_n); last_p = chunk_get_prev_ncnl(last, CNAV_PREPROC); pc.type = CT_PAREN_CLOSE; pc.str = ")"; pc.flags = last_p->flags & PCF_COPY_FLAGS; pc.level = last_p->level; pc.pp_level = last_p->pp_level; pc.brace_level = last_p->brace_level; chunk_add_after(&pc, last_p); for (tmp = first_n; tmp != last_p; tmp = chunk_get_next_ncnl(tmp)) { tmp->level++; } last_p->level++; }
/** * Splits the parameters at every comma that is at the fparen level. * * @param start the offending token */ static void split_fcn_params_full(chunk_t *start) { LOG_FMT(LSPLIT, "%s", __func__); chunk_t *fpo; chunk_t *pc; /* Find the opening fparen */ fpo = start; while (((fpo = chunk_get_prev(fpo)) != NULL) && (fpo->type != CT_FPAREN_OPEN)) { /* do nothing */ } /* Now break after every comma */ pc = fpo; while ((pc = chunk_get_next_ncnl(pc)) != NULL) { if (pc->level <= fpo->level) { break; } if ((pc->level == (fpo->level + 1)) && (pc->type == CT_COMMA)) { split_before_chunk(chunk_get_next(pc)); } } }
/** * Convert '>' + '>' into '>>' * If we only have a single '>', then change it to CT_COMPARE. */ static chunk_t *handle_double_angle_close(chunk_t *pc) { chunk_t *next = chunk_get_next(pc); if (next) { if ((pc->type == CT_ANGLE_CLOSE) && (next->type == CT_ANGLE_CLOSE) && (pc->parent_type == CT_NONE) && ((pc->orig_col_end + 1) == next->orig_col) && (next->parent_type == CT_NONE)) { pc->str.append('>'); set_chunk_type(pc, CT_ARITH); pc->orig_col_end = next->orig_col_end; chunk_t *tmp = chunk_get_next_ncnl(next); chunk_del(next); next = tmp; } else { // bug #663 set_chunk_type(pc, CT_COMPARE); } } return(next); }
void do_parens(void) { LOG_FUNC_ENTRY(); if (cpd.settings[UO_mod_full_paren_if_bool].b) { chunk_t *pc = chunk_get_head(); while ((pc = chunk_get_next_ncnl(pc)) != nullptr) { if ( pc->type != CT_SPAREN_OPEN || ( pc->parent_type != CT_IF && pc->parent_type != CT_ELSEIF && pc->parent_type != CT_SWITCH)) { continue; } // Grab the close sparen chunk_t *pclose = chunk_get_next_type(pc, CT_SPAREN_CLOSE, pc->level, scope_e::PREPROC); if (pclose != nullptr) { check_bool_parens(pc, pclose, 0); pc = pclose; } } } }
/** * Convert '>' + '>' into '>>' * If we only have a single '>', then change it to CT_COMPARE. */ static chunk_t *handle_double_angle_close(chunk_t *pc) { chunk_t *next = chunk_get_next(pc); if (next != NULL) { if ((pc->type == CT_ANGLE_CLOSE) && (next->type == CT_ANGLE_CLOSE) && (pc->parent_type == CT_NONE) && (memcmp(pc->str, ">>", 2) == 0) && (next->parent_type == CT_NONE)) { pc->len++; pc->type = CT_ARITH; pc->orig_col_end = next->orig_col_end; chunk_t *tmp = chunk_get_next_ncnl(next); chunk_del(next); next = tmp; } else { pc->type = CT_COMPARE; } } return(next); }
static size_t preproc_start(parse_frame_t *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *next; size_t pp_level = cpd.pp_level; // Get the type of preprocessor and handle it next = chunk_get_next_ncnl(pc); if (next != nullptr) { cpd.in_preproc = next->type; // If we are in a define, push the frame stack. if (cpd.in_preproc == CT_PP_DEFINE) { pf_push(frm); // a preproc body starts a new, blank frame memset(frm, 0, sizeof(*frm)); frm->level = 1; frm->brace_level = 1; // TODO: not sure about the next 3 lines frm->pse_tos = 1; frm->pse[frm->pse_tos].type = CT_PP_DEFINE; frm->pse[frm->pse_tos].stage = brace_stage_e::NONE; } else { // Check for #if, #else, #endif, etc pp_level = pf_check(frm, pc); } } return(pp_level); }
void do_parens(void) { LOG_FUNC_ENTRY(); chunk_t *pc; chunk_t *pclose; if (cpd.settings[UO_mod_full_paren_if_bool].b) { pc = chunk_get_head(); while ((pc = chunk_get_next_ncnl(pc)) != NULL) { if ((pc->type != CT_SPAREN_OPEN) || ((pc->parent_type != CT_IF) && (pc->parent_type != CT_ELSEIF) && (pc->parent_type != CT_SWITCH))) { continue; } /* Grab the close sparen */ pclose = chunk_get_next_type(pc, CT_SPAREN_CLOSE, pc->level, CNAV_PREPROC); if (pclose != NULL) { check_bool_parens(pc, pclose, 0); pc = pclose; } } } }
static void split_fcn_params_full(chunk_t *start) { LOG_FUNC_ENTRY(); LOG_FMT(LSPLIT, "%s(%d): %s\n", __func__, __LINE__, start->text()); // Find the opening function parenthesis chunk_t *fpo = start; LOG_FMT(LSPLIT, " %s(%d): Find the opening function parenthesis\n", __func__, __LINE__); while ((fpo = chunk_get_prev(fpo)) != nullptr) { LOG_FMT(LSPLIT, "%s(%d): %s, orig_col is %zu, level is %zu\n", __func__, __LINE__, fpo->text(), fpo->orig_col, fpo->level); if (fpo->type == CT_FPAREN_OPEN && (fpo->level == start->level - 1)) { break; // opening parenthesis found. Issue #1020 } } // Now break after every comma chunk_t *pc = fpo; while ((pc = chunk_get_next_ncnl(pc)) != nullptr) { if (pc->level <= fpo->level) { break; } if ((pc->level == (fpo->level + 1)) && pc->type == CT_COMMA) { split_before_chunk(chunk_get_next(pc)); } } }
/** * 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) { 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->type == CT_BOOL) || (pc->type == CT_QUESTION) || (pc->type == CT_COND_COLON)) { LOG_FMT(LPARADD2, " -- %s [%.*s] at line %d col %d, level %d\n", get_token_name(pc->type), pc->len, pc->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->len, pc->str, pc->orig_line, pc->orig_col, pc->level); hit_compare = true; } else if (chunk_is_paren_open(pc)) { next = chunk_get_next_type(pc, (c_token_t)(pc->type + 1), pc->level); 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_get_next_type(pc, (c_token_t)(pc->type + 1), pc->level); } } if (hit_compare && (ref != popen)) { add_parens_between(ref, pclose); } }
/** * Removes superfluous semicolons: * - after brace close whose parent is IF, ELSE, SWITCH, WHILE, FOR, NAMESPACE * - after another semicolon where parent is not FOR * - (D) after brace close whose parent is ENUM/STRUCT/UNION * - after an open brace * - when not in a #DEFINE */ void remove_extra_semicolons(void) { chunk_t *pc; chunk_t *next; chunk_t *prev; pc = chunk_get_head(); while (pc != NULL) { next = chunk_get_next_ncnl(pc); if ((pc->type == CT_SEMICOLON) && !(pc->flags & PCF_IN_PREPROC) && ((prev = chunk_get_prev_ncnl(pc)) != NULL)) { LOG_FMT(LSCANSEMI, "Semi on %d:%d, prev = '%s' [%s/%s]\n", pc->orig_line, pc->orig_col, prev->str.c_str(), get_token_name(prev->type), get_token_name(prev->parent_type)); if ((prev->type == CT_BRACE_CLOSE) && ((prev->parent_type == CT_IF) || (prev->parent_type == CT_ELSEIF) || (prev->parent_type == CT_ELSE) || (prev->parent_type == CT_SWITCH) || (prev->parent_type == CT_WHILE) || (prev->parent_type == CT_USING_STMT) || (prev->parent_type == CT_FOR) || (prev->parent_type == CT_FUNC_DEF) || (prev->parent_type == CT_OC_MSG_DECL) || (prev->parent_type == CT_FUNC_CLASS) || (prev->parent_type == CT_NAMESPACE))) { remove_semicolon(pc); } else if ((prev->type == CT_BRACE_CLOSE) && (prev->parent_type == CT_NONE)) { check_unknown_brace_close(pc, prev); } else if ((prev->type == CT_SEMICOLON) && (prev->parent_type != CT_FOR)) { remove_semicolon(pc); } else if ((cpd.lang_flags & LANG_D) && ((prev->parent_type == CT_ENUM) || (prev->parent_type == CT_UNION) || (prev->parent_type == CT_STRUCT))) { remove_semicolon(pc); } else if (prev->type == CT_BRACE_OPEN) { remove_semicolon(pc); } } pc = next; } }
/** * Aligns an OC message * * @param so the square open of the message * @param span the span value */ static void align_oc_msg_colon(chunk_t *so) { int span = cpd.settings[UO_align_oc_msg_colon_span].n; chunk_t *pc; chunk_t *tmp; AlignStack cas; /* for the colons */ AlignStack nas; /* for the parameter tag */ int level; bool did_line; int lcnt; /* line count with no colon for span */ bool has_colon; nas.Reset(); nas.m_right_align = true; cas.Start(span); level = so->level; pc = chunk_get_next_ncnl(so, CNAV_PREPROC); did_line = false; has_colon = false; lcnt = 0; while ((pc != NULL) && (pc->level > level)) { if (pc->level > (level + 1)) { /* do nothing */ } else if (chunk_is_newline(pc)) { if (!has_colon) { ++lcnt; } did_line = false; has_colon = !has_colon; } else if (!did_line && (lcnt - 1 < span) && (pc->type == CT_OC_COLON)) { has_colon = true; cas.Add(pc); tmp = chunk_get_prev(pc); if ((tmp != NULL) && ((tmp->type == CT_OC_MSG_FUNC) || (tmp->type == CT_OC_MSG_NAME))) { nas.Add(tmp); } did_line = true; } pc = chunk_get_next(pc, CNAV_PREPROC); } nas.End(); cas.End(); }
static void add_parens_between(chunk_t *first, chunk_t *last) { LOG_FUNC_ENTRY(); LOG_FMT(LPARADD, "%s: line %zu between %s [lvl=%zu] and %s [lvl=%zu]\n", __func__, first->orig_line, first->text(), first->level, last->text(), last->level); // Don't do anything if we have a bad sequence, ie "&& )" chunk_t *first_n = chunk_get_next_ncnl(first); if (first_n == last) { return; } chunk_t pc; pc.type = CT_PAREN_OPEN; pc.str = "("; pc.flags = first_n->flags & PCF_COPY_FLAGS; pc.level = first_n->level; pc.pp_level = first_n->pp_level; pc.brace_level = first_n->brace_level; chunk_add_before(&pc, first_n); chunk_t *last_p = chunk_get_prev_ncnl(last, scope_e::PREPROC); pc.type = CT_PAREN_CLOSE; pc.str = ")"; pc.flags = last_p->flags & PCF_COPY_FLAGS; pc.level = last_p->level; pc.pp_level = last_p->pp_level; pc.brace_level = last_p->brace_level; chunk_add_after(&pc, last_p); for (chunk_t *tmp = first_n; tmp != last_p; tmp = chunk_get_next_ncnl(tmp)) { tmp->level++; } last_p->level++; } // add_parens_between
static void move_case_break(void) { LOG_FUNC_ENTRY(); chunk_t *prev = NULL; for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next_ncnl(pc)) { if ((pc->type == CT_BREAK) && (prev != NULL) && (prev->type == CT_BRACE_CLOSE) && (prev->parent_type == CT_CASE)) { if (chunk_is_newline(chunk_get_prev(pc)) && chunk_is_newline(chunk_get_prev(prev))) { chunk_swap_lines(prev, pc); } } prev = pc; } }
static int preproc_start(struct parse_frame *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *next; int pp_level = cpd.pp_level; /* Get the type of preprocessor and handle it */ next = chunk_get_next_ncnl(pc); if (next != NULL) { cpd.in_preproc = next->type; /** * If we are in a define, push the frame stack. */ if (cpd.in_preproc == CT_PP_DEFINE) { pf_push(frm); /* a preproc body starts a new, blank frame */ memset(frm, 0, sizeof(*frm)); frm->level = 1; frm->brace_level = 1; /*TODO: not sure about the next 3 lines */ frm->pse_tos = 1; frm->pse[frm->pse_tos].type = CT_PP_DEFINE; frm->pse[frm->pse_tos].stage = BS_NONE; } else { /* Check for #if, #else, #endif, etc */ pp_level = pf_check(frm, pc); } } return(pp_level); }
/** * Handles a close paren or brace - just progress the stage, if the end * of the statement is hit, call close_statement() * * @param frm The parse frame * @param pc The current chunk * @return true - done with this chunk, false - keep processing */ static bool handle_complex_close(struct parse_frame *frm, chunk_t *pc) { chunk_t *next; if (frm->pse[frm->pse_tos].stage == BS_PAREN1) { /* PAREN1 always => BRACE2 */ frm->pse[frm->pse_tos].stage = BS_BRACE2; } else if (frm->pse[frm->pse_tos].stage == BS_BRACE2) { /* BRACE2: IF => ELSE, anyting else => close */ if ((frm->pse[frm->pse_tos].type == CT_IF) || (frm->pse[frm->pse_tos].type == CT_ELSEIF)) { frm->pse[frm->pse_tos].stage = BS_ELSE; /* If the next chunk isn't CT_ELSE, close the statement */ next = chunk_get_next_ncnl(pc); if ((next != NULL) && (next->type != CT_ELSE)) { frm->pse_tos--; print_stack(LBCSPOP, "-IF-HCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } } else if ((frm->pse[frm->pse_tos].type == CT_TRY) || (frm->pse[frm->pse_tos].type == CT_CATCH)) { frm->pse[frm->pse_tos].stage = BS_CATCH; /* If the next chunk isn't CT_CATCH or CT_FINALLY, close the statement */ next = chunk_get_next_ncnl(pc); if ((next != NULL) && (next->type != CT_CATCH) && (next->type != CT_FINALLY)) { frm->pse_tos--; print_stack(LBCSPOP, "-TRY-HCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } } else { LOG_FMT(LNOTE, "%s: close_statement on %s BS_BRACE2\n", __func__, get_token_name(frm->pse[frm->pse_tos].type)); frm->pse_tos--; print_stack(LBCSPOP, "-HCC B2 ", frm, pc); if (close_statement(frm, pc)) { return(true); } } } else if (frm->pse[frm->pse_tos].stage == BS_BRACE_DO) { frm->pse[frm->pse_tos].stage = BS_WHILE; } else if (frm->pse[frm->pse_tos].stage == BS_WOD_PAREN) { LOG_FMT(LNOTE, "%s: close_statement on %s BS_WOD_PAREN\n", __func__, get_token_name(frm->pse[frm->pse_tos].type)); frm->pse[frm->pse_tos].stage = BS_WOD_SEMI; print_stack(LBCSPOP, "-HCC WoDP ", frm, pc); } else if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI) { LOG_FMT(LNOTE, "%s: close_statement on %s BS_WOD_SEMI\n", __func__, get_token_name(frm->pse[frm->pse_tos].type)); frm->pse_tos--; print_stack(LBCSPOP, "-HCC WoDS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } else { /* PROBLEM */ LOG_FMT(LWARN, "%s:%d Error: TOS.type='%s' TOS.stage=%d\n", cpd.filename, pc->orig_line, get_token_name(frm->pse[frm->pse_tos].type), frm->pse[frm->pse_tos].stage); cpd.error_count++; } return(false); }
/** * At the heart of this algorithm are two stacks. * There is the Paren Stack (PS) and the Frame stack. * * The PS (pse in the code) keeps track of braces, parens, * if/else/switch/do/while/etc items -- anything that is nestable. * Complex statements go through stages. * Take this simple if statement as an example: * if ( x ) { x--; } * * The stack would change like so: 'token' stack afterwards * 'if' [IF - 1] * '(' [IF - 1] [PAREN OPEN] * 'x' [IF - 1] [PAREN OPEN] * ')' [IF - 2] <- note that the state was incremented * '{' [IF - 2] [BRACE OPEN] * 'x' [IF - 2] [BRACE OPEN] * '--' [IF - 2] [BRACE OPEN] * ';' [IF - 2] [BRACE OPEN] * '}' [IF - 3] * <- lack of else kills the IF, closes statement * * Virtual braces example: * if ( x ) x--; else x++; * * 'if' [IF - 1] * '(' [IF - 1] [PAREN OPEN] * 'x' [IF - 1] [PAREN OPEN] * ')' [IF - 2] * 'x' [IF - 2] [VBRACE OPEN] <- VBrace open inserted before because '{' was not next * '--' [IF - 2] [VBRACE OPEN] * ';' [IF - 3] <- VBrace close inserted after semicolon * 'else' [ELSE - 0] <- IF changed into ELSE * 'x' [ELSE - 0] [VBRACE OPEN] <- lack of '{' -> VBrace * '++' [ELSE - 0] [VBRACE OPEN] * ';' [ELSE - 0] <- VBrace close inserted after semicolon * <- ELSE removed after statement close * * The pse stack is kept on a frame stack. * The frame stack is need for languages that support preprocessors (C, C++, C#) * that can arbitrarily change code flow. It also isolates #define macros so * that they are indented independently and do not affect the rest of the program. * * When an #if is hit, a copy of the current frame is push on the frame stack. * When an #else/#elif is hit, a copy of the current stack is pushed under the * #if frame and the original (pre-#if) frame is copied to the current frame. * When #endif is hit, the top frame is popped. * This has the following effects: * - a simple #if / #endif does not affect program flow * - #if / #else /#endif - continues from the #if clause * * When a #define is entered, the current frame is pushed and cleared. * When a #define is exited, the frame is popped. */ static void parse_cleanup(struct parse_frame *frm, chunk_t *pc) { c_token_t parent = CT_NONE; chunk_t *prev; LOG_FMT(LTOK, "%s:%d] %16s - tos:%d/%16s stg:%d\n", __func__, pc->orig_line, get_token_name(pc->type), frm->pse_tos, get_token_name(frm->pse[frm->pse_tos].type), frm->pse[frm->pse_tos].stage); /* Mark statement starts */ if (((frm->stmt_count == 0) || (frm->expr_count == 0)) && !chunk_is_semicolon(pc) && (pc->type != CT_BRACE_CLOSE) && (pc->type != CT_VBRACE_CLOSE) && !chunk_is_str(pc, ")", 1) && !chunk_is_str(pc, "]", 1)) { pc->flags |= PCF_EXPR_START; pc->flags |= (frm->stmt_count == 0) ? PCF_STMT_START : 0; LOG_FMT(LSTMT, "%d] 1.marked %s as %s start st:%d ex:%d\n", pc->orig_line, pc->str.c_str(), (pc->flags &PCF_STMT_START) ? "stmt" : "expr", frm->stmt_count, frm->expr_count); } frm->stmt_count++; frm->expr_count++; if (frm->sparen_count > 0) { int tmp; pc->flags |= PCF_IN_SPAREN; /* Mark everything in the a for statement */ for (tmp = frm->pse_tos - 1; tmp >= 0; tmp--) { if (frm->pse[tmp].type == CT_FOR) { pc->flags |= PCF_IN_FOR; break; } } /* Mark the parent on semicolons in for() stmts */ if ((pc->type == CT_SEMICOLON) && (frm->pse_tos > 1) && (frm->pse[frm->pse_tos - 1].type == CT_FOR)) { pc->parent_type = CT_FOR; } } /* Check the progression of complex statements */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { if (check_complex_statements(frm, pc)) { return; } } /** * Check for a virtual brace statement close due to a semicolon. * The virtual brace will get handled the next time through. * The semicolon isn't handled at all. * TODO: may need to float VBRACE past comments until newline? */ if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN) { if (chunk_is_semicolon(pc)) { cpd.consumed = true; close_statement(frm, pc); } else if ((cpd.lang_flags & LANG_PAWN) != 0) { if (pc->type == CT_BRACE_CLOSE) { close_statement(frm, pc); } } } /* Handle close paren, vbrace, brace, and square */ if ((pc->type == CT_PAREN_CLOSE) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_VBRACE_CLOSE) || (pc->type == CT_ANGLE_CLOSE) || (pc->type == CT_MACRO_CLOSE) || (pc->type == CT_SQUARE_CLOSE)) { /* Change CT_PAREN_CLOSE into CT_SPAREN_CLOSE or CT_FPAREN_CLOSE */ if ((pc->type == CT_PAREN_CLOSE) && ((frm->pse[frm->pse_tos].type == CT_FPAREN_OPEN) || (frm->pse[frm->pse_tos].type == CT_SPAREN_OPEN))) { pc->type = (c_token_t)(frm->pse[frm->pse_tos].type + 1); if (pc->type == CT_SPAREN_CLOSE) { frm->sparen_count--; pc->flags &= ~PCF_IN_SPAREN; } } /* Make sure the open / close match */ if (pc->type != (frm->pse[frm->pse_tos].type + 1)) { if ((frm->pse[frm->pse_tos].type != CT_NONE) && (frm->pse[frm->pse_tos].type != CT_PP_DEFINE)) { LOG_FMT(LWARN, "%s:%d Error: Unexpected '%s' for '%s', which was on line %d\n", cpd.filename, pc->orig_line, pc->str.c_str(), get_token_name(frm->pse[frm->pse_tos].pc->type), frm->pse[frm->pse_tos].pc->orig_line); print_stack(LBCSPOP, "=Error ", frm, pc); cpd.error_count++; } } else { cpd.consumed = true; /* Copy the parent, update the paren/brace levels */ pc->parent_type = frm->pse[frm->pse_tos].parent; frm->level--; if ((pc->type == CT_BRACE_CLOSE) || (pc->type == CT_VBRACE_CLOSE) || (pc->type == CT_MACRO_CLOSE)) { frm->brace_level--; } pc->level = frm->level; pc->brace_level = frm->brace_level; /* Pop the entry */ frm->pse_tos--; print_stack(LBCSPOP, "-Close ", frm, pc); /* See if we are in a complex statement */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { handle_complex_close(frm, pc); } } } /* In this state, we expect a semicolon, but we'll also hit the closing * sparen, so we need to check cpd.consumed to see if the close sparen was * aleady handled. */ if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI) { chunk_t *tmp = pc; if (cpd.consumed) { /* If consumed, then we are on the close sparen. * PAWN: Check the next chunk for a semicolon. If it isn't, then * add a virtual semicolon, which will get handled on the next pass. */ if (cpd.lang_flags & LANG_PAWN) { tmp = chunk_get_next_ncnl(pc); if ((tmp->type != CT_SEMICOLON) && (tmp->type != CT_VSEMICOLON)) { pawn_add_vsemi_after(pc); } } } else { /* Complain if this ISN'T a semicolon, but close out WHILE_OF_DO anyway */ if ((pc->type == CT_SEMICOLON) || (pc->type == CT_VSEMICOLON)) { cpd.consumed = true; pc->parent_type = CT_WHILE_OF_DO; } else { LOG_FMT(LWARN, "%s:%d: Error: Expected a semicolon for WHILE_OF_DO, but got '%s'\n", cpd.filename, pc->orig_line, get_token_name(pc->type)); cpd.error_count++; } handle_complex_close(frm, pc); } } /* Get the parent type for brace and paren open */ parent = pc->parent_type; if ((pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN) || (pc->type == CT_BRACE_OPEN)) { prev = chunk_get_prev_ncnl(pc); if (prev != NULL) { if ((pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN)) { /* Set the parent for parens and change paren type */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { pc->type = CT_SPAREN_OPEN; parent = frm->pse[frm->pse_tos].type; frm->sparen_count++; } else if (prev->type == CT_FUNCTION) { pc->type = CT_FPAREN_OPEN; parent = CT_FUNCTION; } else { /* no need to set parent */ } } else /* must be CT_BRACE_OPEN */ { /* Set the parent for open braces */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { parent = frm->pse[frm->pse_tos].type; } else if ((prev->type == CT_ASSIGN) && (prev->str[0] == '=')) { parent = CT_ASSIGN; } else if (prev->type == CT_FPAREN_CLOSE) { parent = CT_FUNCTION; } else { /* no need to set parent */ } } } } /** * Adjust the level for opens & create a stack entry * Note that CT_VBRACE_OPEN has already been handled. */ if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN) || (pc->type == CT_ANGLE_OPEN) || (pc->type == CT_MACRO_OPEN) || (pc->type == CT_SQUARE_OPEN)) { frm->level++; if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_MACRO_OPEN)) { frm->brace_level++; } push_fmr_pse(frm, pc, BS_NONE, "+Open "); frm->pse[frm->pse_tos].parent = parent; pc->parent_type = parent; } pattern_class patcls = get_token_pattern_class(pc->type); /** Create a stack entry for complex statements IF/DO/FOR/WHILE/SWITCH */ if (patcls == PATCLS_BRACED) { push_fmr_pse(frm, pc, (pc->type == CT_DO) ? BS_BRACE_DO : BS_BRACE2, "+ComplexBraced"); } else if (patcls == PATCLS_PBRACED) { brstage_e bs = BS_PAREN1; if ((pc->type == CT_WHILE) && maybe_while_of_do(pc)) { pc->type = CT_WHILE_OF_DO; bs = BS_WOD_PAREN; } push_fmr_pse(frm, pc, bs, "+ComplexParenBraced"); } else if (patcls == PATCLS_OPBRACED) { push_fmr_pse(frm, pc, BS_OP_PAREN1, "+ComplexOpParenBraced"); } else if (patcls == PATCLS_ELSE) { push_fmr_pse(frm, pc, BS_ELSEIF, "+ComplexElse"); } /* Mark simple statement/expression starts * - after { or } * - after ';', but not if the paren stack top is a paren * - after '(' that has a parent type of CT_FOR */ if ((pc->type == CT_SQUARE_OPEN) || ((pc->type == CT_BRACE_OPEN) && (pc->parent_type != CT_ASSIGN)) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_VBRACE_CLOSE) || ((pc->type == CT_SPAREN_OPEN) && (pc->parent_type == CT_FOR)) || (chunk_is_semicolon(pc) && (frm->pse[frm->pse_tos].type != CT_PAREN_OPEN) && (frm->pse[frm->pse_tos].type != CT_FPAREN_OPEN) && (frm->pse[frm->pse_tos].type != CT_SPAREN_OPEN))) { LOG_FMT(LSTMT, "%s: %d> reset1 stmt on %s\n", __func__, pc->orig_line, pc->str.c_str()); frm->stmt_count = 0; frm->expr_count = 0; } /* Mark expression starts */ chunk_t *tmp = chunk_get_next_ncnl(pc); if ((pc->type == CT_ARITH) || (pc->type == CT_ASSIGN) || (pc->type == CT_CASE) || (pc->type == CT_COMPARE) || ((pc->type == CT_STAR) && tmp && (tmp->type != CT_STAR)) || (pc->type == CT_BOOL) || (pc->type == CT_MINUS) || (pc->type == CT_PLUS) || (pc->type == CT_ANGLE_OPEN) || (pc->type == CT_ANGLE_CLOSE) || (pc->type == CT_RETURN) || (pc->type == CT_GOTO) || (pc->type == CT_CONTINUE) || (pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN) || (pc->type == CT_BRACE_OPEN) || chunk_is_semicolon(pc) || (pc->type == CT_COMMA) || (pc->type == CT_NOT) || (pc->type == CT_INV) || (pc->type == CT_COLON) || (pc->type == CT_QUESTION)) { frm->expr_count = 0; LOG_FMT(LSTMT, "%s: %d> reset expr on %s\n", __func__, pc->orig_line, pc->str.c_str()); } }
void tokenize_cleanup(void) { LOG_FUNC_ENTRY(); chunk_t *pc = chunk_get_head(); chunk_t *prev = NULL; chunk_t *next; chunk_t *tmp; chunk_t *tmp2; bool in_type_cast = false; cpd.unc_stage = US_TOKENIZE_CLEANUP; /* Since [] is expected to be TSQUARE for the 'operator', we need to make * this change in the first pass. */ for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next_ncnl(pc)) { if (pc->type == CT_SQUARE_OPEN) { next = chunk_get_next_ncnl(pc); if (chunk_is_token(next, CT_SQUARE_CLOSE)) { /* Change '[' + ']' into '[]' */ set_chunk_type(pc, CT_TSQUARE); pc->str = "[]"; // bug # 664 // The original orig_col_end of CT_SQUARE_CLOSE is stored at orig_col_end of CT_TSQUARE. // pc->orig_col_end += 1; pc->orig_col_end = next->orig_col_end; chunk_del(next); } } if ((pc->type == CT_SEMICOLON) && (pc->flags & PCF_IN_PREPROC) && !chunk_get_next_ncnl(pc, CNAV_PREPROC)) { LOG_FMT(LNOTE, "%s:%d Detected a macro that ends with a semicolon. Possible failures if used.\n", cpd.filename, pc->orig_line); } } /* We can handle everything else in the second pass */ pc = chunk_get_head(); next = chunk_get_next_ncnl(pc); while ((pc != NULL) && (next != NULL)) { if ((pc->type == CT_DOT) && (cpd.lang_flags & LANG_ALLC)) { set_chunk_type(pc, CT_MEMBER); } if ((pc->type == CT_NULLCOND) && (cpd.lang_flags & LANG_CS)) { set_chunk_type(pc, CT_MEMBER); } /* Determine the version stuff (D only) */ if (pc->type == CT_D_VERSION) { if (next->type == CT_PAREN_OPEN) { set_chunk_type(pc, CT_D_VERSION_IF); } else { if (next->type != CT_ASSIGN) { LOG_FMT(LERR, "%s:%d %s: version: Unexpected token %s\n", cpd.filename, pc->orig_line, __func__, get_token_name(next->type)); cpd.error_count++; } set_chunk_type(pc, CT_WORD); } } /* Determine the scope stuff (D only) */ if (pc->type == CT_D_SCOPE) { if (next->type == CT_PAREN_OPEN) { set_chunk_type(pc, CT_D_SCOPE_IF); } else { set_chunk_type(pc, CT_TYPE); } } /** * Change CT_BASE before CT_PAREN_OPEN to CT_WORD. * public myclass() : base() { * } */ if ((pc->type == CT_BASE) && (next->type == CT_PAREN_OPEN)) { set_chunk_type(pc, CT_WORD); } if ((pc->type == CT_ENUM) && (next->type == CT_CLASS)) { set_chunk_type(next, CT_ENUM_CLASS); } /** * Change CT_WORD after CT_ENUM, CT_UNION, or CT_STRUCT to CT_TYPE * Change CT_WORD before CT_WORD to CT_TYPE */ if (next->type == CT_WORD) { if ((pc->type == CT_ENUM) || (pc->type == CT_ENUM_CLASS) || (pc->type == CT_UNION) || (pc->type == CT_STRUCT)) { set_chunk_type(next, CT_TYPE); } if (pc->type == CT_WORD) { set_chunk_type(pc, CT_TYPE); } } /* change extern to qualifier if extern isn't followed by a string or * an open paren */ if (pc->type == CT_EXTERN) { if (next->type == CT_STRING) { /* Probably 'extern "C"' */ } else if (next->type == CT_PAREN_OPEN) { /* Probably 'extern (C)' */ } else { /* Something else followed by a open brace */ tmp = chunk_get_next_ncnl(next); if ((tmp == NULL) || (tmp->type != CT_BRACE_OPEN)) { set_chunk_type(pc, CT_QUALIFIER); } } } /** * Change CT_STAR to CT_PTR_TYPE if preceded by CT_TYPE, * CT_QUALIFIER, or CT_PTR_TYPE. */ if ((next->type == CT_STAR) && ((pc->type == CT_TYPE) || (pc->type == CT_QUALIFIER) || (pc->type == CT_PTR_TYPE))) { set_chunk_type(next, CT_PTR_TYPE); } if ((pc->type == CT_TYPE_CAST) && (next->type == CT_ANGLE_OPEN)) { set_chunk_parent(next, CT_TYPE_CAST); in_type_cast = true; } /** * Change angle open/close to CT_COMPARE, if not a template thingy */ if ((pc->type == CT_ANGLE_OPEN) && (pc->parent_type != CT_TYPE_CAST)) { /* pretty much all languages except C use <> for something other than * comparisons. "#include<xxx>" is handled elsewhere. */ if (cpd.lang_flags & (LANG_CPP | LANG_CS | LANG_JAVA | LANG_VALA | LANG_OC)) { // bug #663 check_template(pc); } else { /* convert CT_ANGLE_OPEN to CT_COMPARE */ set_chunk_type(pc, CT_COMPARE); } } if ((pc->type == CT_ANGLE_CLOSE) && (pc->parent_type != CT_TEMPLATE)) { if (in_type_cast) { in_type_cast = false; set_chunk_parent(pc, CT_TYPE_CAST); } else { next = handle_double_angle_close(pc); } } if (cpd.lang_flags & LANG_D) { /* Check for the D string concat symbol '~' */ if ((pc->type == CT_INV) && ((prev->type == CT_STRING) || (prev->type == CT_WORD) || (next->type == CT_STRING))) { set_chunk_type(pc, CT_CONCAT); } /* Check for the D template symbol '!' (word + '!' + word or '(') */ if ((pc->type == CT_NOT) && (prev->type == CT_WORD) && ((next->type == CT_PAREN_OPEN) || (next->type == CT_WORD) || (next->type == CT_TYPE))) { set_chunk_type(pc, CT_D_TEMPLATE); } /* handle "version(unittest) { }" vs "unittest { }" */ if (prev && (pc->type == CT_UNITTEST) && (prev->type == CT_PAREN_OPEN)) { set_chunk_type(pc, CT_WORD); } /* handle 'static if' and merge the tokens */ if (prev && (pc->type == CT_IF) && chunk_is_str(prev, "static", 6)) { /* delete PREV and merge with IF */ pc->str.insert(0, ' '); pc->str.insert(0, prev->str); pc->orig_col = prev->orig_col; pc->orig_line = prev->orig_line; chunk_t *to_be_deleted = prev; prev = chunk_get_prev_ncnl(prev); chunk_del(to_be_deleted); } } if (cpd.lang_flags & LANG_CPP) { /* Change Word before '::' into a type */ if ((pc->type == CT_WORD) && (next->type == CT_DC_MEMBER)) { set_chunk_type(pc, CT_TYPE); } } /* Change get/set to CT_WORD if not followed by a brace open */ if ((pc->type == CT_GETSET) && (next->type != CT_BRACE_OPEN)) { if ((next->type == CT_SEMICOLON) && ((prev->type == CT_BRACE_CLOSE) || (prev->type == CT_BRACE_OPEN) || (prev->type == CT_SEMICOLON))) { set_chunk_type(pc, CT_GETSET_EMPTY); set_chunk_parent(next, CT_GETSET); } else { set_chunk_type(pc, CT_WORD); } } /* Interface is only a keyword in MS land if followed by 'class' or 'struct' * likewise, 'class' may be a member name in Java. */ if ((pc->type == CT_CLASS) && !CharTable::IsKw1(next->str[0])) { set_chunk_type(pc, CT_WORD); } /* Change item after operator (>=, ==, etc) to a CT_OPERATOR_VAL * Usually the next item is part of the operator. * In a few cases the next few tokens are part of it: * operator + - common case * operator >> - need to combine '>' and '>' * operator () * operator [] - already converted to TSQUARE * operator new [] * operator delete [] * operator const char * * operator const B& * operator std::allocator<U> * * In all cases except the last, this will put the entire operator value * in one chunk. */ if (pc->type == CT_OPERATOR) { tmp2 = chunk_get_next(next); /* Handle special case of () operator -- [] already handled */ if (next->type == CT_PAREN_OPEN) { tmp = chunk_get_next(next); if ((tmp != NULL) && (tmp->type == CT_PAREN_CLOSE)) { next->str = "()"; set_chunk_type(next, CT_OPERATOR_VAL); chunk_del(tmp); next->orig_col_end += 1; } } else if ((next->type == CT_ANGLE_CLOSE) && tmp2 && (tmp2->type == CT_ANGLE_CLOSE) && (tmp2->orig_col == next->orig_col_end)) { next->str.append('>'); next->orig_col_end++; set_chunk_type(next, CT_OPERATOR_VAL); chunk_del(tmp2); } else if (next->flags & PCF_PUNCTUATOR) { set_chunk_type(next, CT_OPERATOR_VAL); } else { set_chunk_type(next, CT_TYPE); /* Replace next with a collection of all tokens that are part of * the type. */ tmp2 = next; while ((tmp = chunk_get_next(tmp2)) != NULL) { if ((tmp->type != CT_WORD) && (tmp->type != CT_TYPE) && (tmp->type != CT_QUALIFIER) && (tmp->type != CT_STAR) && (tmp->type != CT_CARET) && (tmp->type != CT_AMP) && (tmp->type != CT_TSQUARE)) { break; } /* Change tmp into a type so that space_needed() works right */ make_type(tmp); int num_sp = space_needed(tmp2, tmp); while (num_sp-- > 0) { next->str.append(" "); } next->str.append(tmp->str); tmp2 = tmp; } while ((tmp2 = chunk_get_next(next)) != tmp) { chunk_del(tmp2); } set_chunk_type(next, CT_OPERATOR_VAL); next->orig_col_end = next->orig_col + next->len(); } set_chunk_parent(next, CT_OPERATOR); LOG_FMT(LOPERATOR, "%s: %d:%d operator '%s'\n", __func__, pc->orig_line, pc->orig_col, next->text()); } /* Change private, public, protected into either a qualifier or label */ if (pc->type == CT_PRIVATE) { /* Handle Qt slots - maybe should just check for a CT_WORD? */ if (chunk_is_str(next, "slots", 5) || chunk_is_str(next, "Q_SLOTS", 7)) { tmp = chunk_get_next(next); if ((tmp != NULL) && (tmp->type == CT_COLON)) { next = tmp; } } if (next->type == CT_COLON) { set_chunk_type(next, CT_PRIVATE_COLON); if ((tmp = chunk_get_next_ncnl(next)) != NULL) { chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START); } } else { set_chunk_type(pc, (chunk_is_str(pc, "signals", 7) || chunk_is_str(pc, "Q_SIGNALS", 9)) ? CT_WORD : CT_QUALIFIER); } } /* Look for <newline> 'EXEC' 'SQL' */ if ((chunk_is_str(pc, "EXEC", 4) && chunk_is_str(next, "SQL", 3)) || ((*pc->str == '$') && (pc->type != CT_SQL_WORD))) { tmp = chunk_get_prev(pc); if (chunk_is_newline(tmp)) { if (*pc->str == '$') { set_chunk_type(pc, CT_SQL_EXEC); if (pc->len() > 1) { /* SPLIT OFF '$' */ chunk_t nc; nc = *pc; pc->str.resize(1); pc->orig_col_end = pc->orig_col + 1; nc.type = CT_SQL_WORD; nc.str.pop_front(); nc.orig_col++; nc.column++; chunk_add_after(&nc, pc); next = chunk_get_next(pc); } } tmp = chunk_get_next(next); if (chunk_is_str_case(tmp, "BEGIN", 5)) { set_chunk_type(pc, CT_SQL_BEGIN); } else if (chunk_is_str_case(tmp, "END", 3)) { set_chunk_type(pc, CT_SQL_END); } else { set_chunk_type(pc, CT_SQL_EXEC); } /* Change words into CT_SQL_WORD until CT_SEMICOLON */ while (tmp != NULL) { if (tmp->type == CT_SEMICOLON) { break; } if ((tmp->len() > 0) && (unc_isalpha(*tmp->str) || (*tmp->str == '$'))) { set_chunk_type(tmp, CT_SQL_WORD); } tmp = chunk_get_next_ncnl(tmp); } } } /* handle MS abomination 'for each' */ if ((pc->type == CT_FOR) && chunk_is_str(next, "each", 4) && (next == chunk_get_next(pc))) { /* merge the two with a space between */ pc->str.append(' '); pc->str += next->str; pc->orig_col_end = next->orig_col_end; chunk_del(next); next = chunk_get_next_ncnl(pc); /* label the 'in' */ if (next && (next->type == CT_PAREN_OPEN)) { tmp = chunk_get_next_ncnl(next); while (tmp && (tmp->type != CT_PAREN_CLOSE)) { if (chunk_is_str(tmp, "in", 2)) { set_chunk_type(tmp, CT_IN); break; } tmp = chunk_get_next_ncnl(tmp); } } } /* ObjectiveC allows keywords to be used as identifiers in some situations * This is a dirty hack to allow some of the more common situations. */ if (cpd.lang_flags & LANG_OC) { if (((pc->type == CT_IF) || (pc->type == CT_FOR) || (pc->type == CT_WHILE)) && !chunk_is_token(next, CT_PAREN_OPEN)) { set_chunk_type(pc, CT_WORD); } if ((pc->type == CT_DO) && (chunk_is_token(prev, CT_MINUS) || chunk_is_token(next, CT_SQUARE_CLOSE))) { set_chunk_type(pc, CT_WORD); } } /* Another hack to clean up more keyword abuse */ if ((pc->type == CT_CLASS) && (chunk_is_token(prev, CT_DOT) || chunk_is_token(next, CT_DOT))) { set_chunk_type(pc, CT_WORD); } /* Detect Objective C class name */ if ((pc->type == CT_OC_IMPL) || (pc->type == CT_OC_INTF) || (pc->type == CT_OC_PROTOCOL)) { if (next->type != CT_PAREN_OPEN) { set_chunk_type(next, CT_OC_CLASS); } set_chunk_parent(next, pc->type); tmp = chunk_get_next_ncnl(next); if (tmp != NULL) { chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START); } tmp = chunk_get_next_type(pc, CT_OC_END, pc->level); if (tmp != NULL) { set_chunk_parent(tmp, pc->type); } } if (pc->type == CT_OC_INTF) { tmp = chunk_get_next_ncnl(pc, CNAV_PREPROC); while ((tmp != NULL) && (tmp->type != CT_OC_END)) { if (get_token_pattern_class(tmp->type) != PATCLS_NONE) { LOG_FMT(LOBJCWORD, "@interface %d:%d change '%s' (%s) to CT_WORD\n", pc->orig_line, pc->orig_col, tmp->text(), get_token_name(tmp->type)); set_chunk_type(tmp, CT_WORD); } tmp = chunk_get_next_ncnl(tmp, CNAV_PREPROC); } } /* Detect Objective-C categories and class extensions */ /* @interface ClassName (CategoryName) */ /* @implementation ClassName (CategoryName) */ /* @interface ClassName () */ /* @implementation ClassName () */ if (((pc->parent_type == CT_OC_IMPL) || (pc->parent_type == CT_OC_INTF) || (pc->type == CT_OC_CLASS)) && (next->type == CT_PAREN_OPEN)) { set_chunk_parent(next, pc->parent_type); tmp = chunk_get_next(next); if ((tmp != NULL) && (tmp->next != NULL)) { if (tmp->type == CT_PAREN_CLOSE) { //set_chunk_type(tmp, CT_OC_CLASS_EXT); set_chunk_parent(tmp, pc->parent_type); } else { set_chunk_type(tmp, CT_OC_CATEGORY); set_chunk_parent(tmp, pc->parent_type); } } tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level); if (tmp != NULL) { set_chunk_parent(tmp, pc->parent_type); } } /* Detect Objective C @property * @property NSString *stringProperty; * @property(nonatomic, retain) NSMutableDictionary *shareWith; */ if (pc->type == CT_OC_PROPERTY) { if (next->type != CT_PAREN_OPEN) { chunk_flags_set(next, PCF_STMT_START | PCF_EXPR_START); } else { set_chunk_parent(next, pc->type); tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level); if (tmp != NULL) { set_chunk_parent(tmp, pc->type); tmp = chunk_get_next_ncnl(tmp); if (tmp != NULL) { chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START); tmp = chunk_get_next_type(tmp, CT_SEMICOLON, pc->level); if (tmp != NULL) { set_chunk_parent(tmp, pc->type); } } } } } /* Detect Objective C @selector * @selector(msgNameWithNoArg) * @selector(msgNameWith1Arg:) * @selector(msgNameWith2Args:arg2Name:) */ if ((pc->type == CT_OC_SEL) && (next->type == CT_PAREN_OPEN)) { set_chunk_parent(next, pc->type); tmp = chunk_get_next(next); if (tmp != NULL) { set_chunk_type(tmp, CT_OC_SEL_NAME); set_chunk_parent(tmp, pc->type); while ((tmp = chunk_get_next_ncnl(tmp)) != NULL) { if (tmp->type == CT_PAREN_CLOSE) { set_chunk_parent(tmp, CT_OC_SEL); break; } set_chunk_type(tmp, CT_OC_SEL_NAME); set_chunk_parent(tmp, pc->type); } } } /* Handle special preprocessor junk */ if (pc->type == CT_PREPROC) { set_chunk_parent(pc, next->type); } /* Detect "pragma region" and "pragma endregion" */ if ((pc->type == CT_PP_PRAGMA) && (next->type == CT_PREPROC_BODY)) { if ((memcmp(next->str, "region", 6) == 0) || (memcmp(next->str, "endregion", 9) == 0)) { set_chunk_type(pc, (*next->str == 'r') ? CT_PP_REGION : CT_PP_ENDREGION); set_chunk_parent(prev, pc->type); } } /* Check for C# nullable types '?' is in next */ if ((cpd.lang_flags & LANG_CS) && (next->type == CT_QUESTION) && (next->orig_col == (pc->orig_col + pc->len()))) { tmp = chunk_get_next_ncnl(next); if (tmp != NULL) { bool doit = ((tmp->type == CT_PAREN_CLOSE) || (tmp->type == CT_ANGLE_CLOSE)); if (tmp->type == CT_WORD) { tmp2 = chunk_get_next_ncnl(tmp); if ((tmp2 != NULL) && ((tmp2->type == CT_SEMICOLON) || (tmp2->type == CT_ASSIGN) || (tmp2->type == CT_COMMA) || (tmp2->type == CT_BRACE_OPEN))) { doit = true; } } if (doit) { pc->str += next->str; pc->orig_col_end = next->orig_col_end; chunk_del(next); next = tmp; } } } /* Change 'default(' into a sizeof-like statement */ if ((cpd.lang_flags & LANG_CS) && (pc->type == CT_DEFAULT) && (next->type == CT_PAREN_OPEN)) { set_chunk_type(pc, CT_SIZEOF); } if ((pc->type == CT_UNSAFE) && (next->type != CT_BRACE_OPEN)) { set_chunk_type(pc, CT_QUALIFIER); } if (((pc->type == CT_USING) || ((pc->type == CT_TRY) && (cpd.lang_flags & LANG_JAVA))) && (next->type == CT_PAREN_OPEN)) { set_chunk_type(pc, CT_USING_STMT); } /* Add minimal support for C++0x rvalue references */ if ((pc->type == CT_BOOL) && chunk_is_str(pc, "&&", 2)) { if (prev->type == CT_TYPE) { set_chunk_type(pc, CT_BYREF); } } /* HACK: treat try followed by a colon as a qualifier to handle this: * A::A(int) try : B() { } catch (...) { } */ if ((pc->type == CT_TRY) && chunk_is_str(pc, "try", 3) && (next != NULL) && (next->type == CT_COLON)) { set_chunk_type(pc, CT_QUALIFIER); } /* If Java's 'synchronized' is in a method declaration, it should be * a qualifier. */ if ((cpd.lang_flags & LANG_JAVA) && (pc->type == CT_SYNCHRONIZED) && (next->type != CT_PAREN_OPEN)) { set_chunk_type(pc, CT_QUALIFIER); } // guy 2015-11-05 // change CT_DC_MEMBER + CT_FOR into CT_DC_MEMBER + CT_FUNC_CALL if ((pc->type == CT_FOR) && (pc->prev->type == CT_DC_MEMBER)) { set_chunk_type(pc, CT_FUNC_CALL); } /* TODO: determine other stuff here */ prev = pc; pc = next; next = chunk_get_next_ncnl(pc); } } // tokenize_cleanup
static chunk_t *pawn_process_func_def(chunk_t *pc) { /* We are on a function definition */ chunk_t *clp; chunk_t *last; chunk_t *next; pc->type = CT_FUNC_DEF; /* If we don't have a brace open right after the close fparen, then * we need to add virtual braces around the function body. */ clp = chunk_get_next_str(pc, ")", 1, 0); last = chunk_get_next_ncnl(clp); if (last != NULL) { LOG_FMT(LPFUNC, "%s: %d] last is '%s' [%s]\n", __func__, last->orig_line, last->str.c_str(), get_token_name(last->type)); } /* See if there is a state clause after the function */ if ((last != NULL) && chunk_is_str(last, "<", 1)) { LOG_FMT(LPFUNC, "%s: %d] '%s' has state angle open %s\n", __func__, pc->orig_line, pc->str.c_str(), get_token_name(last->type)); last->type = CT_ANGLE_OPEN; last->parent_type = CT_FUNC_DEF; while (((last = chunk_get_next(last)) != NULL) && !chunk_is_str(last, ">", 1)) { } if (last != NULL) { LOG_FMT(LPFUNC, "%s: %d] '%s' has state angle close %s\n", __func__, pc->orig_line, pc->str.c_str(), get_token_name(last->type)); last->type = CT_ANGLE_CLOSE; last->parent_type = CT_FUNC_DEF; } last = chunk_get_next_ncnl(last); } if (last == NULL) { return(last); } if (last->type == CT_BRACE_OPEN) { last->parent_type = CT_FUNC_DEF; last = chunk_get_next_type(last, CT_BRACE_CLOSE, last->level); if (last != NULL) { last->parent_type = CT_FUNC_DEF; } } else { LOG_FMT(LPFUNC, "%s: %d] '%s' fdef: expected brace open: %s\n", __func__, pc->orig_line, pc->str.c_str(), get_token_name(last->type)); chunk_t chunk; chunk = *last; chunk.str.clear(); chunk.type = CT_VBRACE_OPEN; chunk.parent_type = CT_FUNC_DEF; chunk_t *prev = chunk_add_before(&chunk, last); last = prev; /* find the next newline at level 0 */ prev = chunk_get_next_ncnl(prev); do { LOG_FMT(LPFUNC, "%s:%d] check %s, level %d\n", __func__, prev->orig_line, get_token_name(prev->type), prev->level); if ((prev->type == CT_NEWLINE) && (prev->level == 0)) { next = chunk_get_next_ncnl(prev); if ((next != NULL) && (next->type != CT_ELSE) && (next->type != CT_WHILE_OF_DO)) { break; } } prev->level++; prev->brace_level++; last = prev; } while ((prev = chunk_get_next(prev)) != NULL); if (last != NULL) { LOG_FMT(LPFUNC, "%s:%d] ended on %s, level %d\n", __func__, last->orig_line, get_token_name(last->type), last->level); } chunk = *last; chunk.str.clear(); chunk.column += last->len(); chunk.type = CT_VBRACE_CLOSE; chunk.level = 0; chunk.brace_level = 0; chunk.parent_type = CT_FUNC_DEF; last = chunk_add_after(&chunk, last); } return(last); }
/** * Decides how to change inter-chunk spacing. * Note that the order of the if statements is VERY important. * * @param first The first chunk * @param second The second chunk * @return AV_IGNORE, AV_ADD, AV_REMOVE or AV_FORCE */ argval_t do_space(chunk_t *first, chunk_t *second, bool complete = true) { int idx; argval_t arg; chunk_t *next; if ((first->type == CT_IGNORED) || (second->type == CT_IGNORED)) { log_rule("IGNORED"); return(AV_REMOVE); } if ((first->type == CT_PP) || (second->type == CT_PP)) { log_rule("sp_pp_concat"); return(cpd.settings[UO_sp_pp_concat].a); } if (first->type == CT_POUND) { log_rule("sp_pp_stringify"); return(cpd.settings[UO_sp_pp_stringify].a); } if ((first->type == CT_SPACE) || (second->type == CT_SPACE)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((second->type == CT_NEWLINE) || (second->type == CT_VBRACE_OPEN)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_VBRACE_OPEN) && (second->type != CT_NL_CONT)) { log_rule("ADD"); return(AV_ADD); } if ((first->type == CT_VBRACE_CLOSE) && (second->type != CT_NL_CONT)) { log_rule("REMOVE"); return(AV_REMOVE); } if (second->type == CT_VSEMICOLON) { log_rule("REMOVE"); return(AV_REMOVE); } if (first->type == CT_MACRO_FUNC) { log_rule("REMOVE"); return(AV_REMOVE); } if (second->type == CT_NL_CONT) { log_rule("sp_before_nl_cont"); return(cpd.settings[UO_sp_before_nl_cont].a); } if ((first->type == CT_D_ARRAY_COLON) || (second->type == CT_D_ARRAY_COLON)) { log_rule("sp_d_array_colon"); return(cpd.settings[UO_sp_d_array_colon].a); } if ((first->type == CT_CASE) && CharTable::IsKw1(second->str[0])) { log_rule("sp_case_label"); return(argval_t(cpd.settings[UO_sp_case_label].a | AV_ADD)); } if ((first->type == CT_QUESTION) || (second->type == CT_QUESTION)) { if (cpd.settings[UO_sp_cond_question].a != AV_IGNORE) { return(cpd.settings[UO_sp_cond_question].a); } } if ((first->type == CT_COND_COLON) || (second->type == CT_COND_COLON)) { if (cpd.settings[UO_sp_cond_colon].a != AV_IGNORE) { return(cpd.settings[UO_sp_cond_colon].a); } } if ((first->type == CT_RANGE) || (second->type == CT_RANGE)) { return(cpd.settings[UO_sp_range].a); } if ((first->type == CT_COLON) && (first->parent_type == CT_SQL_EXEC)) { log_rule("REMOVE"); return(AV_REMOVE); } /* Macro stuff can only return IGNORE, ADD, or FORCE */ if (first->type == CT_MACRO) { log_rule("sp_macro"); arg = cpd.settings[UO_sp_macro].a; return((argval_t)(arg | ((arg != AV_IGNORE) ? AV_ADD : AV_IGNORE))); } if ((first->type == CT_FPAREN_CLOSE) && (first->parent_type == CT_MACRO_FUNC)) { log_rule("sp_macro_func"); arg = cpd.settings[UO_sp_macro_func].a; return((argval_t)(arg | ((arg != AV_IGNORE) ? AV_ADD : AV_IGNORE))); } if (first->type == CT_PREPROC) { /* Remove spaces, unless we are ignoring. See indent_preproc() */ if (cpd.settings[UO_pp_space].a == AV_IGNORE) { log_rule("IGNORE"); return(AV_IGNORE); } log_rule("REMOVE"); return(AV_REMOVE); } if (second->type == CT_SEMICOLON) { if (second->parent_type == CT_FOR) { if ((cpd.settings[UO_sp_before_semi_for_empty].a != AV_IGNORE) && ((first->type == CT_SPAREN_OPEN) || (first->type == CT_SEMICOLON))) { log_rule("sp_before_semi_for_empty"); return(cpd.settings[UO_sp_before_semi_for_empty].a); } if (cpd.settings[UO_sp_before_semi_for].a != AV_IGNORE) { log_rule("sp_before_semi_for"); return(cpd.settings[UO_sp_before_semi_for].a); } } arg = cpd.settings[UO_sp_before_semi].a; log_rule("sp_before_semi"); if ((first->type == CT_SPAREN_CLOSE) && (first->parent_type != CT_WHILE_OF_DO)) { log_rule("sp_special_semi"); arg = (argval_t)(arg | cpd.settings[UO_sp_special_semi].a); } return(arg); } /* "for (;;)" vs "for (;; )" and "for (a;b;c)" vs "for (a; b; c)" */ if (first->type == CT_SEMICOLON) { if (first->parent_type == CT_FOR) { if ((cpd.settings[UO_sp_after_semi_for_empty].a != AV_IGNORE) && (second->type == CT_SPAREN_CLOSE)) { log_rule("sp_after_semi_for_empty"); return(cpd.settings[UO_sp_after_semi_for_empty].a); } if (cpd.settings[UO_sp_after_semi_for].a != AV_IGNORE) { log_rule("sp_after_semi_for"); return(cpd.settings[UO_sp_after_semi_for].a); } } else if (!chunk_is_comment(second)) { log_rule("sp_after_semi"); return(cpd.settings[UO_sp_after_semi].a); } /* Let the comment spacing rules handle this */ } if (((first->type == CT_NEG) || (first->type == CT_POS) || (first->type == CT_ARITH)) && ((second->type == CT_NEG) || (second->type == CT_POS) || (second->type == CT_ARITH))) { log_rule("ADD"); return(AV_ADD); } /* "return(a);" vs "return (foo_t)a + 3;" vs "return a;" vs "return;" */ if (first->type == CT_RETURN) { if ((second->type == CT_PAREN_OPEN) && (second->parent_type == CT_RETURN)) { log_rule("sp_return_paren"); return(cpd.settings[UO_sp_return_paren].a); } /* everything else requires a space */ log_rule("FORCE"); return(AV_FORCE); } /* "sizeof(foo_t)" vs "sizeof foo_t" */ if (first->type == CT_SIZEOF) { if (second->type == CT_PAREN_OPEN) { log_rule("sp_sizeof_paren"); return(cpd.settings[UO_sp_sizeof_paren].a); } log_rule("FORCE"); return(AV_FORCE); } /* handle '::' */ if (first->type == CT_DC_MEMBER) { log_rule("sp_after_dc"); return(cpd.settings[UO_sp_after_dc].a); } if ((second->type == CT_DC_MEMBER) && ((first->type == CT_WORD) || (first->type == CT_TYPE) || CharTable::IsKw1(first->str[0]))) { log_rule("sp_before_dc"); return(cpd.settings[UO_sp_before_dc].a); } /* "a,b" vs "a, b" */ if (first->type == CT_COMMA) { log_rule("sp_after_comma"); return(cpd.settings[UO_sp_after_comma].a); } if (second->type == CT_COMMA) { if ((first->type == CT_PAREN_OPEN) && (cpd.settings[UO_sp_paren_comma].a != AV_IGNORE)) { log_rule("sp_paren_comma"); return(cpd.settings[UO_sp_paren_comma].a); } log_rule("sp_before_comma"); return(cpd.settings[UO_sp_before_comma].a); } if (second->type == CT_ELLIPSIS) { /* non-punc followed by a ellipsis */ if (((first->flags & PCF_PUNCTUATOR) == 0) && (cpd.settings[UO_sp_before_ellipsis].a != AV_IGNORE)) { log_rule("sp_before_ellipsis"); return(cpd.settings[UO_sp_before_ellipsis].a); } if (first->type == CT_TAG_COLON) { log_rule("FORCE"); return(AV_FORCE); } } if ((first->type == CT_ELLIPSIS) && CharTable::IsKw1(second->str[0])) { log_rule("FORCE"); return(AV_FORCE); } if (first->type == CT_TAG_COLON) { log_rule("sp_after_tag"); return(cpd.settings[UO_sp_after_tag].a); } if (second->type == CT_TAG_COLON) { log_rule("REMOVE"); return(AV_REMOVE); } /* handle '~' */ if (first->type == CT_DESTRUCTOR) { log_rule("REMOVE"); return(AV_REMOVE); } /* "((" vs "( (" */ if ((chunk_is_str(first, "(", 1) && chunk_is_str(second, "(", 1)) || (chunk_is_str(first, ")", 1) && chunk_is_str(second, ")", 1))) { log_rule("sp_paren_paren"); return(cpd.settings[UO_sp_paren_paren].a); } /* "if (" vs "if(" */ if (second->type == CT_SPAREN_OPEN) { log_rule("sp_before_sparen"); return(cpd.settings[UO_sp_before_sparen].a); } if ((first->type == CT_LAMBDA) || (second->type == CT_LAMBDA)) { log_rule("sp_assign (lambda)"); return(cpd.settings[UO_sp_assign].a); } if (second->type == CT_OC_BLOCK_CARET) { log_rule("sp_before_oc_block_caret"); return(cpd.settings[UO_sp_before_oc_block_caret].a); } if (first->type == CT_OC_BLOCK_CARET) { log_rule("sp_after_oc_block_caret"); return(cpd.settings[UO_sp_after_oc_block_caret].a); } if (second->type == CT_ASSIGN) { if (second->flags & PCF_IN_ENUM) { if (cpd.settings[UO_sp_enum_before_assign].a != AV_IGNORE) { log_rule("sp_enum_before_assign"); return(cpd.settings[UO_sp_enum_before_assign].a); } log_rule("sp_enum_assign"); return(cpd.settings[UO_sp_enum_assign].a); } if ((cpd.settings[UO_sp_assign_default].a != AV_IGNORE) && (second->parent_type == CT_FUNC_PROTO)) { log_rule("sp_assign_default"); return(cpd.settings[UO_sp_assign_default].a); } if (cpd.settings[UO_sp_before_assign].a != AV_IGNORE) { log_rule("sp_before_assign"); return(cpd.settings[UO_sp_before_assign].a); } log_rule("sp_assign"); return(cpd.settings[UO_sp_assign].a); } if (first->type == CT_ASSIGN) { if (first->flags & PCF_IN_ENUM) { if (cpd.settings[UO_sp_enum_after_assign].a != AV_IGNORE) { log_rule("sp_enum_after_assign"); return(cpd.settings[UO_sp_enum_after_assign].a); } log_rule("sp_enum_assign"); return(cpd.settings[UO_sp_enum_assign].a); } if ((cpd.settings[UO_sp_assign_default].a != AV_IGNORE) && (first->parent_type == CT_FUNC_PROTO)) { log_rule("sp_assign_default"); return(cpd.settings[UO_sp_assign_default].a); } if (cpd.settings[UO_sp_after_assign].a != AV_IGNORE) { log_rule("sp_after_assign"); return(cpd.settings[UO_sp_after_assign].a); } log_rule("sp_assign"); return(cpd.settings[UO_sp_assign].a); } /* "a [x]" vs "a[x]" */ if ((second->type == CT_SQUARE_OPEN) && (second->parent_type != CT_OC_MSG)) { log_rule("sp_before_square"); return(cpd.settings[UO_sp_before_square].a); } /* "byte[]" vs "byte []" */ if (second->type == CT_TSQUARE) { log_rule("sp_before_squares"); return(cpd.settings[UO_sp_before_squares].a); } if ((cpd.settings[UO_sp_angle_shift].a != AV_IGNORE) && (first->type == CT_ANGLE_CLOSE) && (second->type == CT_ANGLE_CLOSE)) { log_rule("sp_angle_shift"); return(cpd.settings[UO_sp_angle_shift].a); } /* spacing around template < > stuff */ if ((first->type == CT_ANGLE_OPEN) || (second->type == CT_ANGLE_CLOSE)) { log_rule("sp_inside_angle"); return(cpd.settings[UO_sp_inside_angle].a); } if (second->type == CT_ANGLE_OPEN) { if ((first->type == CT_TEMPLATE) && (cpd.settings[UO_sp_template_angle].a != AV_IGNORE)) { log_rule("sp_template_angle"); return(cpd.settings[UO_sp_template_angle].a); } log_rule("sp_before_angle"); return(cpd.settings[UO_sp_before_angle].a); } if (first->type == CT_ANGLE_CLOSE) { if ((second->type == CT_WORD) || CharTable::IsKw1(second->str[0])) { if (cpd.settings[UO_sp_angle_word].a != AV_IGNORE) { log_rule("sp_angle_word"); return(cpd.settings[UO_sp_angle_word].a); } } if ((second->type == CT_FPAREN_OPEN) || (second->type == CT_PAREN_OPEN)) { log_rule("sp_angle_paren"); return(cpd.settings[UO_sp_angle_paren].a); } if (second->type == CT_DC_MEMBER) { log_rule("sp_before_dc"); return(cpd.settings[UO_sp_before_dc].a); } if ((second->type != CT_BYREF) && (second->type != CT_PTR_TYPE)) { log_rule("sp_after_angle"); return(cpd.settings[UO_sp_after_angle].a); } } if ((first->type == CT_BYREF) && (cpd.settings[UO_sp_after_byref_func].a != AV_IGNORE) && ((first->parent_type == CT_FUNC_DEF) || (first->parent_type == CT_FUNC_PROTO))) { log_rule("sp_after_byref_func"); return(cpd.settings[UO_sp_after_byref_func].a); } if ((first->type == CT_BYREF) && CharTable::IsKw1(second->str[0])) { log_rule("sp_after_byref"); return(cpd.settings[UO_sp_after_byref].a); } if (second->type == CT_BYREF) { if (cpd.settings[UO_sp_before_byref_func].a != AV_IGNORE) { next = chunk_get_next(second); if ((next != NULL) && ((next->type == CT_FUNC_DEF) || (next->type == CT_FUNC_PROTO))) { return(cpd.settings[UO_sp_before_byref_func].a); } } if (cpd.settings[UO_sp_before_unnamed_byref].a != AV_IGNORE) { next = chunk_get_next_nc(second); if ((next != NULL) && (next->type != CT_WORD)) { log_rule("sp_before_unnamed_byref"); return(cpd.settings[UO_sp_before_unnamed_byref].a); } } log_rule("sp_before_byref"); return(cpd.settings[UO_sp_before_byref].a); } if (first->type == CT_SPAREN_CLOSE) { if ((second->type == CT_BRACE_OPEN) && (cpd.settings[UO_sp_sparen_brace].a != AV_IGNORE)) { log_rule("sp_sparen_brace"); return(cpd.settings[UO_sp_sparen_brace].a); } if (!chunk_is_comment(second) && (cpd.settings[UO_sp_after_sparen].a != AV_IGNORE)) { log_rule("sp_after_sparen"); return(cpd.settings[UO_sp_after_sparen].a); } } if ((second->type == CT_FPAREN_OPEN) && (first->parent_type == CT_OPERATOR) && (cpd.settings[UO_sp_after_operator_sym].a != AV_IGNORE)) { log_rule("sp_after_operator_sym"); return(cpd.settings[UO_sp_after_operator_sym].a); } /* spaces between function and open paren */ if ((first->type == CT_FUNC_CALL) || (first->type == CT_FUNC_CTOR_VAR)) { if ((cpd.settings[UO_sp_func_call_paren_empty].a != AV_IGNORE) && (second->type == CT_FPAREN_OPEN)) { next = chunk_get_next_ncnl(second); if (next && (next->type == CT_FPAREN_CLOSE)) { log_rule("sp_func_call_paren_empty"); return(cpd.settings[UO_sp_func_call_paren_empty].a); } } log_rule("sp_func_call_paren"); return(cpd.settings[UO_sp_func_call_paren].a); } if (first->type == CT_FUNC_CALL_USER) { log_rule("sp_func_call_user_paren"); return(cpd.settings[UO_sp_func_call_user_paren].a); } if (first->type == CT_ATTRIBUTE) { log_rule("sp_attribute_paren"); return(cpd.settings[UO_sp_attribute_paren].a); } if (first->type == CT_FUNC_DEF) { log_rule("sp_func_def_paren"); return(cpd.settings[UO_sp_func_def_paren].a); } if ((first->type == CT_CPP_CAST) || (first->type == CT_TYPE_WRAP)) { log_rule("sp_cpp_cast_paren"); return(cpd.settings[UO_sp_cpp_cast_paren].a); } if ((first->type == CT_PAREN_CLOSE) && ((second->type == CT_PAREN_OPEN) || (second->type == CT_FPAREN_OPEN))) { /* "(int)a" vs "(int) a" or "cast(int)a" vs "cast(int) a" */ if ((first->parent_type == CT_C_CAST) || (first->parent_type == CT_D_CAST)) { log_rule("sp_after_cast"); return(cpd.settings[UO_sp_after_cast].a); } /* Must be an indirect/chained function call? */ log_rule("REMOVE"); return(AV_REMOVE); /* TODO: make this configurable? */ } if ((first->type == CT_FUNC_PROTO) || ((second->type == CT_FPAREN_OPEN) && (second->parent_type == CT_FUNC_PROTO))) { log_rule("sp_func_proto_paren"); return(cpd.settings[UO_sp_func_proto_paren].a); } if (first->type == CT_FUNC_CLASS) { log_rule("sp_func_class_paren"); return(cpd.settings[UO_sp_func_class_paren].a); } if ((first->type == CT_CLASS) && (first->parent_type != CT_OC_MSG)) { log_rule("FORCE"); return(AV_FORCE); } if ((first->type == CT_BRACE_OPEN) && (second->type == CT_BRACE_CLOSE)) { log_rule("sp_inside_braces_empty"); return(cpd.settings[UO_sp_inside_braces_empty].a); } if (second->type == CT_BRACE_CLOSE) { if (second->parent_type == CT_ENUM) { log_rule("sp_inside_braces_enum"); return(cpd.settings[UO_sp_inside_braces_enum].a); } if ((second->parent_type == CT_STRUCT) || (second->parent_type == CT_UNION)) { log_rule("sp_inside_braces_struct"); return(cpd.settings[UO_sp_inside_braces_struct].a); } log_rule("sp_inside_braces"); return(cpd.settings[UO_sp_inside_braces].a); } if (first->type == CT_D_CAST) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_PP_DEFINED) && (second->type == CT_PAREN_OPEN)) { log_rule("sp_defined_paren"); return(cpd.settings[UO_sp_defined_paren].a); } if ((first->type == CT_THROW) && (second->type == CT_PAREN_OPEN)) { log_rule("sp_throw_paren"); return(cpd.settings[UO_sp_throw_paren].a); } if ((first->type == CT_THIS) && (second->type == CT_PAREN_OPEN)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_STATE) && (second->type == CT_PAREN_OPEN)) { log_rule("ADD"); return(AV_ADD); } if ((first->type == CT_DELEGATE) && (second->type == CT_PAREN_OPEN)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_MEMBER) || (second->type == CT_MEMBER)) { log_rule("sp_member"); return(cpd.settings[UO_sp_member].a); } if (first->type == CT_C99_MEMBER) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_SUPER) && (second->type == CT_PAREN_OPEN)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_FPAREN_CLOSE) && (second->type == CT_BRACE_OPEN)) { log_rule("sp_fparen_brace"); return(cpd.settings[UO_sp_fparen_brace].a); } if ((first->type == CT_D_TEMPLATE) || (second->type == CT_D_TEMPLATE)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_ELSE) && (second->type == CT_BRACE_OPEN)) { log_rule("sp_else_brace"); return(cpd.settings[UO_sp_else_brace].a); } if ((first->type == CT_ELSE) && (second->type == CT_ELSEIF)) { log_rule("FORCE"); return(AV_FORCE); } if ((first->type == CT_CATCH) && (second->type == CT_BRACE_OPEN)) { log_rule("sp_catch_brace"); return(cpd.settings[UO_sp_catch_brace].a); } if ((first->type == CT_FINALLY) && (second->type == CT_BRACE_OPEN)) { log_rule("sp_finally_brace"); return(cpd.settings[UO_sp_finally_brace].a); } if ((first->type == CT_TRY) && (second->type == CT_BRACE_OPEN)) { log_rule("sp_try_brace"); return(cpd.settings[UO_sp_try_brace].a); } if ((first->type == CT_GETSET) && (second->type == CT_BRACE_OPEN)) { log_rule("sp_getset_brace"); return(cpd.settings[UO_sp_getset_brace].a); } if ((second->type == CT_PAREN_OPEN) && (second->parent_type == CT_INVARIANT)) { log_rule("sp_invariant_paren"); return(cpd.settings[UO_sp_invariant_paren].a); } if (first->type == CT_PAREN_CLOSE) { if (first->parent_type == CT_D_TEMPLATE) { log_rule("FORCE"); return(AV_FORCE); } if (first->parent_type == CT_INVARIANT) { log_rule("sp_after_invariant_paren"); return(cpd.settings[UO_sp_after_invariant_paren].a); } /* Arith after a cast comes first */ if (second->type == CT_ARITH) { log_rule("sp_arith"); return(cpd.settings[UO_sp_arith].a); } /* "(struct foo) {...}" vs "(struct foo){...}" */ if (second->type == CT_BRACE_OPEN) { log_rule("sp_paren_brace"); return(cpd.settings[UO_sp_paren_brace].a); } /* D-specific: "delegate(some thing) dg */ if (first->parent_type == CT_DELEGATE) { log_rule("ADD"); return(AV_ADD); } /* PAWN-specific: "state (condition) next" */ if (first->parent_type == CT_STATE) { log_rule("ADD"); return(AV_ADD); } } /* "foo(...)" vs "foo( ... )" */ if ((first->type == CT_FPAREN_OPEN) || (second->type == CT_FPAREN_CLOSE)) { if ((first->type == CT_FPAREN_OPEN) && (second->type == CT_FPAREN_CLOSE)) { log_rule("sp_inside_fparens"); return(cpd.settings[UO_sp_inside_fparens].a); } log_rule("sp_inside_fparen"); return(cpd.settings[UO_sp_inside_fparen].a); } if (first->type == CT_PAREN_CLOSE) { if (first->parent_type == CT_OC_RTYPE) { log_rule("sp_after_oc_return_type"); return(cpd.settings[UO_sp_after_oc_return_type].a); } else if ((first->parent_type == CT_OC_MSG_SPEC) || (first->parent_type == CT_OC_MSG_DECL)) { log_rule("sp_after_oc_type"); return(cpd.settings[UO_sp_after_oc_type].a); } else if ((first->parent_type == CT_OC_SEL) && (second->type != CT_SQUARE_CLOSE)) { log_rule("sp_after_oc_at_sel_parens"); return(cpd.settings[UO_sp_after_oc_at_sel_parens].a); } } if (cpd.settings[UO_sp_inside_oc_at_sel_parens].a != AV_IGNORE) { if (((first->type == CT_PAREN_OPEN) && ((first->parent_type == CT_OC_SEL) || (first->parent_type == CT_OC_PROTOCOL))) || ((second->type == CT_PAREN_CLOSE) && ((second->parent_type == CT_OC_SEL) || (second->parent_type == CT_OC_PROTOCOL)))) { log_rule("sp_inside_oc_at_sel_parens"); return(cpd.settings[UO_sp_inside_oc_at_sel_parens].a); } } if ((second->type == CT_PAREN_OPEN) && ((first->type == CT_OC_SEL) || (first->type == CT_OC_PROTOCOL))) { log_rule("sp_after_oc_at_sel"); return(cpd.settings[UO_sp_after_oc_at_sel].a); } /* C cast: "(int)" vs "( int )" * D cast: "cast(int)" vs "cast( int )" * CPP cast: "int(a + 3)" vs "int( a + 3 )" */ if (first->type == CT_PAREN_OPEN) { if ((first->parent_type == CT_C_CAST) || (first->parent_type == CT_CPP_CAST) || (first->parent_type == CT_D_CAST)) { log_rule("sp_inside_paren_cast"); return(cpd.settings[UO_sp_inside_paren_cast].a); } log_rule("sp_inside_paren"); return(cpd.settings[UO_sp_inside_paren].a); } if (second->type == CT_PAREN_CLOSE) { if ((second->parent_type == CT_C_CAST) || (second->parent_type == CT_CPP_CAST) || (second->parent_type == CT_D_CAST)) { log_rule("sp_inside_paren_cast"); return(cpd.settings[UO_sp_inside_paren_cast].a); } log_rule("sp_inside_paren"); return(cpd.settings[UO_sp_inside_paren].a); } /* "[3]" vs "[ 3 ]" */ if ((first->type == CT_SQUARE_OPEN) || (second->type == CT_SQUARE_CLOSE)) { log_rule("sp_inside_square"); return(cpd.settings[UO_sp_inside_square].a); } if ((first->type == CT_SQUARE_CLOSE) && (second->type == CT_FPAREN_OPEN)) { log_rule("sp_square_fparen"); return(cpd.settings[UO_sp_square_fparen].a); } /* "if(...)" vs "if( ... )" */ if ((second->type == CT_SPAREN_CLOSE) && (cpd.settings[UO_sp_inside_sparen_close].a != AV_IGNORE)) { log_rule("sp_inside_sparen_close"); return(cpd.settings[UO_sp_inside_sparen_close].a); } if ((first->type == CT_SPAREN_OPEN) || (second->type == CT_SPAREN_CLOSE)) { log_rule("sp_inside_sparen"); return(cpd.settings[UO_sp_inside_sparen].a); } if ((cpd.settings[UO_sp_after_class_colon].a != AV_IGNORE) && (first->type == CT_CLASS_COLON)) { log_rule("sp_after_class_colon"); return(cpd.settings[UO_sp_after_class_colon].a); } if ((cpd.settings[UO_sp_before_class_colon].a != AV_IGNORE) && (second->type == CT_CLASS_COLON)) { log_rule("sp_before_class_colon"); return(cpd.settings[UO_sp_before_class_colon].a); } if ((cpd.settings[UO_sp_before_case_colon].a != AV_IGNORE) && (second->type == CT_CASE_COLON)) { log_rule("sp_before_case_colon"); return(cpd.settings[UO_sp_before_case_colon].a); } if (first->type == CT_DOT) { log_rule("REMOVE"); return(AV_REMOVE); } if (second->type == CT_DOT) { log_rule("ADD"); return(AV_ADD); } if ((first->type == CT_ARITH) || (second->type == CT_ARITH)) { log_rule("sp_arith"); return(cpd.settings[UO_sp_arith].a); } if ((first->type == CT_BOOL) || (second->type == CT_BOOL)) { arg = cpd.settings[UO_sp_bool].a; if ((cpd.settings[UO_pos_bool].tp != TP_IGNORE) && (first->orig_line != second->orig_line) && (arg != AV_REMOVE)) { arg = (argval_t)(arg | AV_ADD); } log_rule("sp_bool"); return(arg); } if ((first->type == CT_COMPARE) || (second->type == CT_COMPARE)) { log_rule("sp_compare"); return(cpd.settings[UO_sp_compare].a); } if ((first->type == CT_PAREN_OPEN) && (second->type == CT_PTR_TYPE)) { log_rule("REMOVE"); return(AV_REMOVE); } if ((first->type == CT_PTR_TYPE) && (second->type == CT_PTR_TYPE) && (cpd.settings[UO_sp_between_ptr_star].a != AV_IGNORE)) { log_rule("sp_between_ptr_star"); return(cpd.settings[UO_sp_between_ptr_star].a); } if ((first->type == CT_PTR_TYPE) && (cpd.settings[UO_sp_after_ptr_star_func].a != AV_IGNORE) && ((first->parent_type == CT_FUNC_DEF) || (first->parent_type == CT_FUNC_PROTO))) { log_rule("sp_after_ptr_star_func"); return(cpd.settings[UO_sp_after_ptr_star_func].a); } if ((first->type == CT_PTR_TYPE) && (cpd.settings[UO_sp_after_ptr_star].a != AV_IGNORE) && CharTable::IsKw1(second->str[0])) { log_rule("sp_after_ptr_star"); return(cpd.settings[UO_sp_after_ptr_star].a); } if (second->type == CT_PTR_TYPE) { if (cpd.settings[UO_sp_before_ptr_star_func].a != AV_IGNORE) { /* Find the next non-'*' chunk */ next = second; do { next = chunk_get_next(next); } while ((next != NULL) && (next->type == CT_PTR_TYPE)); if ((next != NULL) && ((next->type == CT_FUNC_DEF) || (next->type == CT_FUNC_PROTO))) { return(cpd.settings[UO_sp_before_ptr_star_func].a); } } if (cpd.settings[UO_sp_before_unnamed_ptr_star].a != AV_IGNORE) { next = chunk_get_next_nc(second); while ((next != NULL) && (next->type == CT_PTR_TYPE)) { next = chunk_get_next_nc(next); } if ((next != NULL) && (next->type != CT_WORD)) { log_rule("sp_before_unnamed_ptr_star"); return(cpd.settings[UO_sp_before_unnamed_ptr_star].a); } } if (cpd.settings[UO_sp_before_ptr_star].a != AV_IGNORE) { log_rule("sp_before_ptr_star"); return(cpd.settings[UO_sp_before_ptr_star].a); } } if (first->type == CT_OPERATOR) { log_rule("sp_after_operator"); return(cpd.settings[UO_sp_after_operator].a); } if ((second->type == CT_FUNC_PROTO) || (second->type == CT_FUNC_DEF)) { if (first->type != CT_PTR_TYPE) { log_rule("sp_type_func|ADD"); return((argval_t)(cpd.settings[UO_sp_type_func].a | AV_ADD)); } log_rule("sp_type_func"); return(cpd.settings[UO_sp_type_func].a); } /* "(int)a" vs "(int) a" or "cast(int)a" vs "cast(int) a" */ if ((first->parent_type == CT_C_CAST) || (first->parent_type == CT_D_CAST)) { log_rule("sp_after_cast"); return(cpd.settings[UO_sp_after_cast].a); } if (first->type == CT_BRACE_CLOSE) { if (second->type == CT_ELSE) { log_rule("sp_brace_else"); return(cpd.settings[UO_sp_brace_else].a); } else if (second->type == CT_CATCH) { log_rule("sp_brace_catch"); return(cpd.settings[UO_sp_brace_catch].a); } else if (second->type == CT_FINALLY) { log_rule("sp_brace_finally"); return(cpd.settings[UO_sp_brace_finally].a); } } if (first->type == CT_BRACE_OPEN) { if (first->parent_type == CT_ENUM) { log_rule("sp_inside_braces_enum"); return(cpd.settings[UO_sp_inside_braces_enum].a); } else if ((first->parent_type == CT_UNION) || (first->parent_type == CT_STRUCT)) { log_rule("sp_inside_braces_struct"); return(cpd.settings[UO_sp_inside_braces_struct].a); } else if (!chunk_is_comment(second)) { log_rule("sp_inside_braces"); return(cpd.settings[UO_sp_inside_braces].a); } } if (second->type == CT_BRACE_CLOSE) { if (second->parent_type == CT_ENUM) { log_rule("sp_inside_braces_enum"); return(cpd.settings[UO_sp_inside_braces_enum].a); } else if ((second->parent_type == CT_UNION) || (second->parent_type == CT_STRUCT)) { log_rule("sp_inside_braces_struct"); return(cpd.settings[UO_sp_inside_braces_struct].a); } log_rule("sp_inside_braces"); return(cpd.settings[UO_sp_inside_braces].a); } if ((first->type == CT_BRACE_CLOSE) && (first->flags & PCF_IN_TYPEDEF) && ((first->parent_type == CT_ENUM) || (first->parent_type == CT_STRUCT) || (first->parent_type == CT_UNION))) { log_rule("sp_brace_typedef"); return(cpd.settings[UO_sp_brace_typedef].a); } if (second->type == CT_SPAREN_OPEN) { log_rule("sp_before_sparen"); return(cpd.settings[UO_sp_before_sparen].a); } if ((second->type != CT_PTR_TYPE) && ((first->type == CT_QUALIFIER) || (first->type == CT_TYPE))) { arg = cpd.settings[UO_sp_after_type].a; log_rule("sp_after_type"); return((arg != AV_REMOVE) ? arg : AV_FORCE); } if ((first->type == CT_MACRO_OPEN) || (first->type == CT_MACRO_CLOSE) || (first->type == CT_MACRO_ELSE)) { if (second->type == CT_PAREN_OPEN) { log_rule("sp_func_call_paren"); return(cpd.settings[UO_sp_func_call_paren].a); } log_rule("IGNORE"); return(AV_IGNORE); } /* If nothing claimed the PTR_TYPE, then return ignore */ if ((first->type == CT_PTR_TYPE) || (second->type == CT_PTR_TYPE)) { log_rule("IGNORE"); return(AV_IGNORE); } if (first->type == CT_NOT) { log_rule("sp_not"); return(cpd.settings[UO_sp_not].a); } if (first->type == CT_INV) { log_rule("sp_inv"); return(cpd.settings[UO_sp_inv].a); } if (first->type == CT_ADDR) { log_rule("sp_addr"); return(cpd.settings[UO_sp_addr].a); } if (first->type == CT_DEREF) { log_rule("sp_deref"); return(cpd.settings[UO_sp_deref].a); } if ((first->type == CT_POS) || (first->type == CT_NEG)) { log_rule("sp_sign"); return(cpd.settings[UO_sp_sign].a); } if ((first->type == CT_INCDEC_BEFORE) || (second->type == CT_INCDEC_AFTER)) { log_rule("sp_incdec"); return(cpd.settings[UO_sp_incdec].a); } if (second->type == CT_CS_SQ_COLON) { log_rule("REMOVE"); return(AV_REMOVE); } if (first->type == CT_CS_SQ_COLON) { log_rule("FORCE"); return(AV_FORCE); } if (first->type == CT_OC_SCOPE) { log_rule("sp_after_oc_scope"); return(cpd.settings[UO_sp_after_oc_scope].a); } if (first->type == CT_OC_COLON) { if (first->parent_type == CT_OC_MSG) { log_rule("sp_after_send_oc_colon"); return(cpd.settings[UO_sp_after_send_oc_colon].a); } else { log_rule("sp_after_oc_colon"); return(cpd.settings[UO_sp_after_oc_colon].a); } } if (second->type == CT_OC_COLON) { if ((first->parent_type == CT_OC_MSG) && ((first->type == CT_OC_MSG_FUNC) || (first->type == CT_OC_MSG_NAME))) { log_rule("sp_before_send_oc_colon"); return(cpd.settings[UO_sp_before_send_oc_colon].a); } else { log_rule("sp_before_oc_colon"); return(cpd.settings[UO_sp_before_oc_colon].a); } } if ((second->type == CT_COMMENT) && (second->parent_type == CT_COMMENT_EMBED)) { log_rule("FORCE"); return(AV_FORCE); } if ((second->type == CT_COMMENT) && ((first->type == CT_PP_ELSE) || (first->type == CT_PP_ENDIF))) { if (cpd.settings[UO_sp_endif_cmt].a != AV_IGNORE) { second->type = CT_COMMENT_ENDIF; log_rule("sp_endif_cmt"); return(cpd.settings[UO_sp_endif_cmt].a); } } if (chunk_is_comment(second)) { log_rule("IGNORE"); return(AV_IGNORE); } if (first->type == CT_COMMENT) { log_rule("FORCE"); return(AV_FORCE); } for (idx = 0; idx < (int)ARRAY_SIZE(no_space_table); idx++) { if (((no_space_table[idx].first == CT_UNKNOWN) || (no_space_table[idx].first == first->type)) && ((no_space_table[idx].second == CT_UNKNOWN) || (no_space_table[idx].second == second->type))) { log_rule("REMOVE"); return(AV_REMOVE); } } log_rule("ADD"); return(AV_ADD); }
/** * 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) { 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, was_preproc = false; int indent_column; int cout_col = 0; // for aligning << stuff int cout_level = 0; // for aligning << stuff int parent_token_indent = 0; memset(&frm, 0, sizeof(frm)); /* dummy top-level entry */ frm.pse[0].indent = 1; frm.pse[0].indent_tmp = 1; frm.pse[0].type = CT_EOF; pc = chunk_get_head(); while (pc != NULL) { /* Handle proprocessor transitions */ was_preproc = in_preproc; in_preproc = (pc->flags & PCF_IN_PREPROC) != 0; if (cpd.settings[UO_indent_brace_parent].b) parent_token_indent = token_indent(pc->parent_type); /* Clean up after a #define */ if (!in_preproc) while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc) indent_pse_pop(frm, pc); else { pf_check(&frm, pc); if (!was_preproc) { /* Transition into a preproc by creating a dummy indent */ frm.level++; indent_pse_push(frm, pc); frm.pse[frm.pse_tos].indent = 1 + indent_size; frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent; } } if ((cout_col > 0) && (chunk_is_semicolon(pc) || (pc->level < cout_level))) { cout_col = 0; cout_level = 0; } /** * Handle non-brace closures */ int old_pse_tos; do { old_pse_tos = frm.pse_tos; /* End anything that drops a level * REVISIT: not sure about the preproc check */ if (!chunk_is_newline(pc) && !chunk_is_comment(pc) && ((pc->flags & PCF_IN_PREPROC) == 0) && (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); } /* End any assign operations with a semicolon on the same level */ if ((frm.pse[frm.pse_tos].type == CT_ASSIGN) && (chunk_is_semicolon(pc) || (pc->type == CT_COMMA) || (pc->type == CT_BRACE_OPEN))) indent_pse_pop(frm, pc); /* End any CPP class colon crap */ if ((frm.pse[frm.pse_tos].type == CT_CLASS_COLON) && ((pc->type == CT_BRACE_OPEN) || 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 return is ended with a semicolon */ if ((frm.pse[frm.pse_tos].type == CT_RETURN) && 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 = frm.pse[frm.pse_tos].indent_tmp; if (!chunk_is_newline(pc) && !chunk_is_comment(pc)) { LOG_FMT(LINDPC, " -=[ %.*s ]=- top=%d %s %d/%d\n", pc->len, pc->str, frm.pse_tos, get_token_name(frm.pse[frm.pse_tos].type), frm.pse[frm.pse_tos].indent_tmp, frm.pse[frm.pse_tos].indent); } /** * 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 */ if (pc->type == CT_BRACE_CLOSE) { if (frm.pse[frm.pse_tos].type == CT_BRACE_OPEN) { indent_pse_pop(frm, pc); frm.level--; /* Update the indent_column if needed */ if (!cpd.settings[UO_indent_braces].b && (parent_token_indent == 0)) indent_column = frm.pse[frm.pse_tos].indent_tmp; if ((pc->parent_type == CT_IF) || (pc->parent_type == CT_ELSE) || (pc->parent_type == CT_ELSEIF) || (pc->parent_type == CT_DO) || (pc->parent_type == CT_WHILE) || (pc->parent_type == CT_SWITCH) || (pc->parent_type == CT_FOR)) indent_column += cpd.settings[UO_indent_brace].n; } } 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; /* Always indent on virtual braces */ indent_column = frm.pse[frm.pse_tos].indent_tmp; } else if (pc->type == CT_BRACE_OPEN) { frm.level++; indent_pse_push(frm, pc); if (frm.paren_count != 0) /* 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_DO) || (pc->parent_type == CT_WHILE) || (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 += cpd.settings[UO_indent_brace].n; } } else if (pc->parent_type == CT_CASE) { /* The indent_case_brace setting affects the parent CT_CASE */ frm.pse[frm.pse_tos].indent_tmp += cpd.settings[UO_indent_case_brace].n; frm.pse[frm.pse_tos].indent += cpd.settings[UO_indent_case_brace].n; } 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) && !cpd.settings[UO_indent_namespace].b) frm.pse[frm.pse_tos].indent -= indent_size; } if ((pc->flags & PCF_DONT_INDENT) != 0) { frm.pse[frm.pse_tos].indent = pc->column; indent_column = 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 (cpd.settings[UO_indent_braces].n || (parent_token_indent != 0)) indent_column = frm.pse[frm.pse_tos].indent_tmp; } } 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; /* Always set on case statements */ indent_column = frm.pse[frm.pse_tos].indent_tmp; } 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 = cpd.settings[UO_indent_label].n; else indent_column = frm.pse[frm.pse_tos].indent + cpd.settings[UO_indent_label].n; } else if (pc->type == CT_CLASS_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; indent_column = frm.pse[frm.pse_tos].indent_tmp; if (cpd.settings[UO_indent_class_colon].b) { prev = chunk_get_prev(pc); if (chunk_is_newline(prev)) frm.pse[frm.pse_tos].indent += 2; /* don't change indent of current line */ } } 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 */ indent_pse_push(frm, pc); frm.pse[frm.pse_tos].indent = pc->column + pc->len; if (cpd.settings[UO_indent_func_call_param].b && (pc->type == CT_FPAREN_OPEN) && (pc->parent_type == CT_FUNC_CALL)) frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size; if ((chunk_is_str(pc, "(", 1) && !cpd.settings[UO_indent_paren_nl].b) || (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) sub = 2; frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - sub].indent + indent_size; } } frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent; frm.paren_count++; } else if (pc->type == CT_ASSIGN) { /** * if there is a newline after the '=', just indent one level, * otherwise align on the '='. * Never update indent_column. */ next = chunk_get_next(pc); if (next != NULL) { indent_pse_push(frm, pc); if (chunk_is_newline(next)) frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size; 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) { /* don't count returns inside a () or [] */ if (pc->level == pc->brace_level) { indent_pse_push(frm, pc); 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 (chunk_is_str(pc, "<<", 2)) { if (cout_col == 0) { cout_col = pc->column; cout_level = pc->level; } } else { /* anything else? */ } /** * Indent the line if needed */ if (did_newline && !chunk_is_newline(pc) && (pc->len != 0)) { /** * 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); if ((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 (chunk_is_str(pc, "<<", 2) && (cout_col > 0)) { LOG_FMT(LINDENT, "%s: %d] cout_col => %d\n", __func__, pc->orig_line, cout_col); reindent_line(pc, cout_col); } else if ((vardefcol > 0) && (pc->type == CT_WORD) && ((pc->flags & PCF_VAR_DEF) != 0) && (prev != NULL) && (prev->type == CT_COMMA)) { LOG_FMT(LINDENT, "%s: %d] Vardefcol => %d\n", __func__, pc->orig_line, vardefcol); reindent_line(pc, vardefcol); } else if ((pc->type == CT_STRING) && (prev->type == CT_STRING) && cpd.settings[UO_indent_align_string].b) { LOG_FMT(LINDENT, "%s: %d] String => %d\n", __func__, pc->orig_line, prev->column); reindent_line(pc, prev->column); } 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) { /* Preprocs are always in column 1. See indent_preproc() */ if (pc->column != 1) reindent_line(pc, 1); } else { if (pc->column != indent_column) { LOG_FMT(LINDENT, "%s: %d] indent => %d [%.*s]\n", __func__, pc->orig_line, indent_column, pc->len, pc->str); reindent_line(pc, indent_column); } } did_newline = false; } /** * Handle variable definition continuation indenting */ if ((pc->type == CT_WORD) && ((pc->flags & PCF_IN_FCN_DEF) == 0) && ((pc->flags & PCF_VAR_1ST_DEF) == PCF_VAR_1ST_DEF)) vardefcol = pc->column; if (chunk_is_semicolon(pc) || ((pc->type == CT_BRACE_OPEN) && (pc->parent_type == CT_FUNCTION))) vardefcol = 0; /* 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; } if (!chunk_is_comment(pc) && !chunk_is_newline(pc)) prev = pc; pc = chunk_get_next(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); 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++; } }
/** * Figures out where to split a function def/proto/call * * For fcn protos and defs. Also fcn calls where level == brace_level: * - find the open fparen * + if it doesn't have a newline right after it * * see if all parameters will fit individually after the paren * * if not, throw a newline after the open paren & return * - scan backwards to the open fparen or comma * + if there isn't a newline after that item, add one & return * + otherwise, add a newline before the start token * * @param start the offending token * @return the token that should have a newline * inserted before it */ static void split_fcn_params(chunk_t *start) { LOG_FUNC_ENTRY(); LOG_FMT(LSPLIT, " %s: ", __func__); chunk_t *prev; chunk_t *fpo; chunk_t *pc; int cur_width = 0; int last_col = -1; int min_col; /* Find the opening fparen */ fpo = start; while (((fpo = chunk_get_prev(fpo)) != NULL) && (fpo->type != CT_FPAREN_OPEN)) { /* do nothing */ } pc = chunk_get_next_ncnl(fpo); min_col = pc->column; LOG_FMT(LSPLIT, " mincol=%d, max_width=%d ", min_col, cpd.settings[UO_code_width].n - min_col); while (pc != NULL) { if (chunk_is_newline(pc)) { cur_width = 0; last_col = -1; } else { if (last_col < 0) { last_col = pc->column; } cur_width += (pc->column - last_col) + pc->len(); last_col = pc->column + pc->len(); if ((pc->type == CT_COMMA) || (pc->type == CT_FPAREN_CLOSE)) { cur_width--; LOG_FMT(LSPLIT, " width=%d ", cur_width); if (((last_col - 1) > cpd.settings[UO_code_width].n) || (pc->type == CT_FPAREN_CLOSE)) { break; } } } pc = chunk_get_next(pc); } /* back up until the prev is a comma */ prev = pc; while ((prev = chunk_get_prev(prev)) != NULL) { if (chunk_is_newline(prev) || (prev->type == CT_COMMA)) { break; } last_col -= pc->len(); if (prev->type == CT_FPAREN_OPEN) { pc = chunk_get_next(prev); if (!cpd.settings[UO_indent_paren_nl].b) { min_col = pc->brace_level * cpd.settings[UO_indent_columns].n + 1; if (cpd.settings[UO_indent_continue].n == 0) { min_col += cpd.settings[UO_indent_columns].n; } else { min_col += abs(cpd.settings[UO_indent_continue].n); } } /* Don't split "()" */ if (pc->type != c_token_t(prev->type + 1)) { break; } } } if ((prev != NULL) && !chunk_is_newline(prev)) { LOG_FMT(LSPLIT, " -- ended on [%s] --\n", get_token_name(prev->type)); pc = chunk_get_next(prev); newline_add_before(pc); reindent_line(pc, min_col); cpd.changes++; } } // split_fcn_params
void remove_extra_semicolons(void) { LOG_FUNC_ENTRY(); chunk_t *pc = chunk_get_head(); while (pc != nullptr) { chunk_t *next = chunk_get_next_ncnl(pc); chunk_t *prev; if ( pc->type == CT_SEMICOLON && !(pc->flags & PCF_IN_PREPROC) && (prev = chunk_get_prev_ncnl(pc)) != nullptr) { LOG_FMT(LSCANSEMI, "Semi on %zu:%zu parent=%s, prev = '%s' [%s/%s]\n", pc->orig_line, pc->orig_col, get_token_name(pc->parent_type), prev->text(), get_token_name(prev->type), get_token_name(prev->parent_type)); if (pc->parent_type == CT_TYPEDEF) { // keep it } else if ( prev->type == CT_BRACE_CLOSE && ( prev->parent_type == CT_IF || prev->parent_type == CT_ELSEIF || prev->parent_type == CT_ELSE || prev->parent_type == CT_SWITCH || prev->parent_type == CT_WHILE || prev->parent_type == CT_USING_STMT || prev->parent_type == CT_FOR || prev->parent_type == CT_FUNC_DEF || prev->parent_type == CT_OC_MSG_DECL || prev->parent_type == CT_FUNC_CLASS_DEF || prev->parent_type == CT_NAMESPACE)) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if ( prev->type == CT_BRACE_CLOSE && prev->parent_type == CT_NONE) { check_unknown_brace_close(pc, prev); } else if (prev->type == CT_SEMICOLON && prev->parent_type != CT_FOR) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if ( (cpd.lang_flags & LANG_D) && ( prev->parent_type == CT_ENUM || prev->parent_type == CT_UNION || prev->parent_type == CT_STRUCT)) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if ( (cpd.lang_flags & LANG_JAVA) && prev->parent_type == CT_SYNCHRONIZED) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if (prev->type == CT_BRACE_OPEN) { LOG_FUNC_CALL(); remove_semicolon(pc); } } pc = next; } } // remove_extra_semicolons
static void split_fcn_params(chunk_t *start) { LOG_FUNC_ENTRY(); LOG_FMT(LSPLIT, "%s(%d): '%s'\n", __func__, __LINE__, start->text()); // Find the opening function parenthesis chunk_t *fpo = start; LOG_FMT(LSPLIT, "%s(%d): Find the opening function parenthesis\n", __func__, __LINE__); while ( ((fpo = chunk_get_prev(fpo)) != nullptr) && fpo->type != CT_FPAREN_OPEN) { // do nothing LOG_FMT(LSPLIT, "%s(%d): '%s', orig_col is %zu, level is %zu\n", __func__, __LINE__, fpo->text(), fpo->orig_col, fpo->level); } chunk_t *pc = chunk_get_next_ncnl(fpo); size_t min_col = pc->column; LOG_FMT(LSPLIT, " mincol is %zu, max_width is %zu\n", min_col, cpd.settings[UO_code_width].u - min_col); int cur_width = 0; int last_col = -1; LOG_FMT(LSPLIT, "%s(%d):look forward until CT_COMMA or CT_FPAREN_CLOSE\n", __func__, __LINE__); while (pc != nullptr) { LOG_FMT(LSPLIT, "%s(%d): pc->text() '%s', type is %s\n", __func__, __LINE__, pc->text(), get_token_name(pc->type)); if (chunk_is_newline(pc)) { cur_width = 0; last_col = -1; } else { if (last_col < 0) { last_col = pc->column; LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", __func__, __LINE__, last_col); } cur_width += (pc->column - last_col) + pc->len(); last_col = pc->column + pc->len(); LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", __func__, __LINE__, last_col); if (pc->type == CT_COMMA || pc->type == CT_FPAREN_CLOSE) { cur_width--; LOG_FMT(LSPLIT, "%s(%d): cur_width is %d\n", __func__, __LINE__, cur_width); if ( ((last_col - 1) > static_cast<int>(cpd.settings[UO_code_width].u)) || pc->type == CT_FPAREN_CLOSE) { break; } } } pc = chunk_get_next(pc); } // back up until the prev is a comma chunk_t *prev = pc; LOG_FMT(LSPLIT, " %s(%d): back up until the prev is a comma\n", __func__, __LINE__); while ((prev = chunk_get_prev(prev)) != nullptr) { LOG_FMT(LSPLIT, "%s(%d): pc '%s', pc->level is %zu, prev '%s', prev->type is %s\n", __func__, __LINE__, pc->text(), pc->level, prev->text(), get_token_name(prev->type)); if (chunk_is_newline(prev) || prev->type == CT_COMMA) { LOG_FMT(LSPLIT, "%s(%d): found at %zu\n", __func__, __LINE__, prev->orig_col); break; } LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", __func__, __LINE__, last_col); last_col -= pc->len(); LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", __func__, __LINE__, last_col); if (prev->type == CT_FPAREN_OPEN) { pc = chunk_get_next(prev); if (!cpd.settings[UO_indent_paren_nl].b) { min_col = pc->brace_level * cpd.settings[UO_indent_columns].u + 1; LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n", __func__, __LINE__, min_col); if (cpd.settings[UO_indent_continue].n == 0) { min_col += cpd.settings[UO_indent_columns].u; } else { min_col += abs(cpd.settings[UO_indent_continue].n); } LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n", __func__, __LINE__, min_col); } // Don't split "()" if (pc->type != c_token_t(prev->type + 1)) { break; } } } if (prev != nullptr && !chunk_is_newline(prev)) { LOG_FMT(LSPLIT, "%s(%d): -- ended on [%s] --\n", __func__, __LINE__, get_token_name(prev->type)); LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n", __func__, __LINE__, min_col); pc = chunk_get_next(prev); newline_add_before(pc); reindent_line(pc, min_col); cpd.changes++; } } // split_fcn_params
void tokenize_cleanup(void) { chunk_t *pc = chunk_get_head(); chunk_t *prev = NULL; chunk_t *next; chunk_t *tmp; chunk_t *tmp2; bool in_type_cast = false; pc = chunk_get_head(); next = chunk_get_next_ncnl(pc); while ((pc != NULL) && (next != NULL)) { /* Change '[' + ']' into '[]' */ if ((pc->type == CT_SQUARE_OPEN) && (next->type == CT_SQUARE_CLOSE)) { pc->type = CT_TSQUARE; pc->str = "[]"; pc->len = 2; chunk_del(next); pc->orig_col_end += 1; next = chunk_get_next_ncnl(pc); } if ((pc->type == CT_DOT) && ((cpd.lang_flags & LANG_ALLC) != 0)) { pc->type = CT_MEMBER; } /* Determine the version stuff (D only) */ if (pc->type == CT_VERSION) { if (next->type == CT_PAREN_OPEN) { pc->type = CT_IF; } else { if (next->type != CT_ASSIGN) { LOG_FMT(LERR, "%s:%d %s: version: Unexpected token %s\n", cpd.filename, pc->orig_line, __func__, get_token_name(next->type)); cpd.error_count++; } pc->type = CT_WORD; } } /** * Change CT_BASE before CT_PAREN_OPEN to CT_WORD. * public myclass() : base() { * } */ if ((pc->type == CT_BASE) && (next->type == CT_PAREN_OPEN)) { pc->type = CT_WORD; } /** * Change CT_WORD after CT_ENUM, CT_UNION, or CT_STRUCT to CT_TYPE * Change CT_WORD before CT_WORD to CT_TYPE */ if (next->type == CT_WORD) { if ((pc->type == CT_ENUM) || (pc->type == CT_UNION) || (pc->type == CT_STRUCT)) { next->type = CT_TYPE; } if (pc->type == CT_WORD) { pc->type = CT_TYPE; } } /* change extern to qualifier if extern isn't followed by a string or * an open paren */ if (pc->type == CT_EXTERN) { if (next->type == CT_STRING) { /* Probably 'extern "C"' */ } else if (next->type == CT_PAREN_OPEN) { /* Probably 'extern (C)' */ } else { /* Something else followed by a open brace */ tmp = chunk_get_next_ncnl(next); if ((tmp != NULL) || (tmp->type != CT_BRACE_OPEN)) { pc->type = CT_QUALIFIER; } } } /** * Change CT_STAR to CT_PTR_TYPE if preceded by CT_TYPE, * CT_QUALIFIER, or CT_PTR_TYPE. */ if ((next->type == CT_STAR) && ((pc->type == CT_TYPE) || (pc->type == CT_QUALIFIER) || (pc->type == CT_PTR_TYPE))) { next->type = CT_PTR_TYPE; } if ((pc->type == CT_TYPE_CAST) && (next->type == CT_ANGLE_OPEN)) { next->parent_type = CT_TYPE_CAST; in_type_cast = true; } /** * Change angle open/close to CT_COMPARE, if not a template thingy */ if ((pc->type == CT_ANGLE_OPEN) && (pc->parent_type != CT_TYPE_CAST)) { check_template(pc); } if ((pc->type == CT_ANGLE_CLOSE) && (pc->parent_type != CT_TEMPLATE)) { if (in_type_cast) { in_type_cast = false; pc->parent_type = CT_TYPE_CAST; } else { pc->type = CT_COMPARE; } } if ((cpd.lang_flags & LANG_D) != 0) { /* Check for the D string concat symbol '~' */ if ((pc->type == CT_INV) && ((prev->type == CT_STRING) || (prev->type == CT_WORD) || (next->type == CT_STRING))) { pc->type = CT_CONCAT; } /* Check for the D template symbol '!' */ if ((pc->type == CT_NOT) && (prev->type == CT_WORD) && (next->type == CT_PAREN_OPEN)) { pc->type = CT_D_TEMPLATE; } } if ((cpd.lang_flags & LANG_CPP) != 0) { /* Change Word before '::' into a type */ if ((pc->type == CT_WORD) && (next->type == CT_DC_MEMBER)) { pc->type = CT_TYPE; } } /* Change get/set to CT_WORD if not followed by a brace open */ if ((pc->type == CT_GETSET) && (next->type != CT_BRACE_OPEN)) { if ((next->type == CT_SEMICOLON) && ((prev->type == CT_BRACE_CLOSE) || (prev->type == CT_BRACE_OPEN) || (prev->type == CT_SEMICOLON))) { pc->type = CT_GETSET_EMPTY; next->parent_type = CT_GETSET; } else { pc->type = CT_WORD; } } /* Change item after operator (>=, ==, etc) to a CT_OPERATOR_VAL * Usually the next item is part of the operator. * In a few cases the next few tokens are part of it: * operator + - common case * operator () * operator [] - already converted to TSQUARE * operator new [] * operator delete [] * operator const char * * This will put the entire operator value in one chunk. */ if (pc->type == CT_OPERATOR) { /* Handle special case of () operator -- [] already handled */ if (next->type == CT_PAREN_OPEN) { tmp = chunk_get_next(next); if ((tmp != NULL) && (tmp->type == CT_PAREN_CLOSE)) { next->str = "()"; next->len = 2; next->type = CT_OPERATOR_VAL; chunk_del(tmp); next->orig_col_end += 1; } } else if (next->flags & PCF_PUNCTUATOR) { next->type = CT_OPERATOR_VAL; } else { next->type = CT_TYPE; /* Replace next with a collection of all tokens that are part of * the type. */ char opbuf[256]; int len; len = snprintf(opbuf, sizeof(opbuf), "%.*s", next->len, next->str); tmp2 = next; while ((tmp = chunk_get_next(tmp2)) != NULL) { if ((tmp->type != CT_WORD) && (tmp->type != CT_TYPE) && (tmp->type != CT_QUALIFIER) && (tmp->type != CT_STAR) && (tmp->type != CT_AMP) && (tmp->type != CT_TSQUARE)) { break; } len += snprintf(opbuf + len, sizeof(opbuf) - len, "%s%.*s", space_needed(tmp2, tmp) ? " " : "", tmp->len, tmp->str); tmp2 = tmp; } while ((tmp2 = chunk_get_next(next)) != tmp) { chunk_del(tmp2); } next->str = strdup(opbuf); next->len = len; next->flags |= PCF_OWN_STR; next->type = CT_OPERATOR_VAL; next->orig_col_end = next->orig_col + next->len; } next->parent_type = CT_OPERATOR; LOG_FMT(LOPERATOR, "%s: %d:%d operator '%.*s'\n", __func__, pc->orig_line, pc->orig_col, next->len, next->str); } /* Change private, public, protected into either a qualifier or label */ if (pc->type == CT_PRIVATE) { /* Handle Qt slots - maybe should just check for a CT_WORD? */ if (chunk_is_str(next, "slots", 5)) { tmp = chunk_get_next(next); if ((tmp != NULL) && (tmp->type == CT_COLON)) { next = tmp; } } if (next->type == CT_COLON) { next->type = CT_PRIVATE_COLON; if ((tmp = chunk_get_next_ncnl(next)) != NULL) { tmp->flags |= PCF_STMT_START | PCF_EXPR_START; } } else { pc->type = chunk_is_str(pc, "signals", 7) ? CT_WORD : CT_QUALIFIER; } } /* Look for <newline> 'EXEC' 'SQL' */ if (chunk_is_str(pc, "EXEC", 4) && chunk_is_str(next, "SQL", 3)) { tmp = chunk_get_prev(pc); if (chunk_is_newline(tmp)) { tmp = chunk_get_next(next); if (chunk_is_str_case(tmp, "BEGIN", 5)) { pc->type = CT_SQL_BEGIN; } else if (chunk_is_str_case(tmp, "END", 3)) { pc->type = CT_SQL_END; } else { pc->type = CT_SQL_EXEC; } /* Change words into CT_SQL_WORD until CT_SEMICOLON */ while (tmp != NULL) { if (tmp->type == CT_SEMICOLON) { break; } if ((tmp->len > 0) && isalpha(*tmp->str)) { tmp->type = CT_SQL_WORD; } tmp = chunk_get_next_ncnl(tmp); } } } /* Detect Objective C class name */ if ((pc->type == CT_OC_IMPL) || (pc->type == CT_OC_INTF)) { next->type = CT_OC_CLASS; next->parent_type = pc->type; tmp = chunk_get_next_ncnl(next); if (tmp != NULL) { tmp->flags |= PCF_STMT_START | PCF_EXPR_START; } tmp = chunk_get_next_type(pc, CT_OC_END, pc->level); if (tmp != NULL) { tmp->parent_type = pc->type; } } /* Detect Objective-C categories and class extensions */ /* @interface ClassName (CategoryName) */ /* @implementation ClassName (CategoryName) */ /* @interface ClassName () */ /* @implementation ClassName () */ if (((pc->parent_type == CT_OC_IMPL) || (pc->parent_type == CT_OC_INTF) || (pc->type == CT_OC_CLASS)) && (next->type == CT_PAREN_OPEN)) { next->parent_type = pc->parent_type; tmp = chunk_get_next(next); if ((tmp != NULL) && (tmp->next != NULL)) { if (tmp->type == CT_PAREN_CLOSE) { tmp->type = CT_OC_CLASS_EXT; tmp->parent_type = pc->parent_type; } else { tmp->type = CT_OC_CATEGORY; tmp->parent_type = pc->parent_type; } } tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level); if (tmp != NULL) { tmp->parent_type = pc->parent_type; } } /** * Objective C @dynamic and @synthesize * @dynamic xxx, yyy; * @synthesize xxx, yyy; * Just find the semicolon and mark it. */ if (pc->type == CT_OC_DYNAMIC) { tmp = chunk_get_next_type(pc, CT_SEMICOLON, pc->level); if (tmp != NULL) { tmp->parent_type = pc->type; } } /* Detect Objective C @property * @property NSString *stringProperty; * @property(nonatomic, retain) NSMutableDictionary *shareWith; */ if (pc->type == CT_OC_PROPERTY) { if (next->type != CT_PAREN_OPEN) { next->flags |= PCF_STMT_START | PCF_EXPR_START; } else { next->parent_type = pc->type; tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level); if (tmp != NULL) { tmp->parent_type = pc->type; tmp = chunk_get_next_ncnl(tmp); if (tmp != NULL) { tmp->flags |= PCF_STMT_START | PCF_EXPR_START; tmp = chunk_get_next_type(tmp, CT_SEMICOLON, pc->level); if (tmp != NULL) { tmp->parent_type = pc->type; } } } } } /* Detect Objective C @selector * @selector(msgNameWithNoArg) * @selector(msgNameWith1Arg:) * @selector(msgNameWith2Args:arg2Name:) */ if ((pc->type == CT_OC_SEL) && (next->type == CT_PAREN_OPEN)) { next->parent_type = pc->type; tmp = chunk_get_next(next); if (tmp != NULL) { tmp->type = CT_OC_SEL_NAME; tmp->parent_type = pc->type; while ((tmp = chunk_get_next_ncnl(tmp)) != NULL) { if (tmp->type == CT_PAREN_CLOSE) { tmp->parent_type = CT_OC_SEL; break; } tmp->type = CT_OC_SEL_NAME; tmp->parent_type = pc->type; } } } /* Mark Objective-C blocks (aka lambdas or closures) * The syntax and usage is exactly like C function pointers with two exceptions: * Instead of an asterisk they have a caret as pointer symbol. * In method declarations which take a block as parameter, there can be anonymous blocks, e.g.: (^) * 1. block literal: ^{ ... }; * 2. block declaration: return_t (^name) (int arg1, int arg2, ...) NB: return_t is optional and name can be optional if found as param in a method declaration. * 3. block expression: ^ return_t (int arg) { ... }; NB: return_t is optional * * See http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Blocks for more info... */ if ((cpd.lang_flags & LANG_OC) && (pc->type == CT_ARITH) && (chunk_is_str(pc, "^", 1)) && (prev->type != CT_NUMBER) && (prev->type != CT_NUMBER_FP)) { /* mark objc blocks caret so that we can process it later*/ pc->type = CT_OC_BLOCK_CARET; if (prev->type == CT_PAREN_OPEN) { /* block declaration */ pc->parent_type = CT_OC_BLOCK_TYPE; } else if ((next->type == CT_PAREN_OPEN) || (next->type == CT_BRACE_OPEN)) { /* block expression without return type */ /* block literal */ pc->parent_type = CT_OC_BLOCK_EXPR; } else { /* block expression with return type (seldomly used) */ if (prev->type == CT_ASSIGN) { /* shortcut to spare the peeking below * the XOR operator wouldn't be used directly * after an assign all by itself */ pc->parent_type = CT_OC_BLOCK_EXPR; } else { /* this ones tricky because we don't know how many * stars the return type has - if there even is one */ tmp = pc; while ((tmp = chunk_get_next(tmp)) != NULL) { /* we just peek ahead and see if the line contains * an open brace somewhere. * FIXME: this check needs to be more thorough. */ if (tmp->type == CT_BRACE_OPEN) { pc->parent_type = CT_OC_BLOCK_EXPR; break; } } } } } /* Handle special preprocessor junk */ if (pc->type == CT_PREPROC) { pc->parent_type = next->type; } /* Detect "pragma region" and "pragma endregion" */ if ((pc->type == CT_PP_PRAGMA) && (next->type == CT_PREPROC_BODY)) { if ((memcmp(next->str, "region", 6) == 0) || (memcmp(next->str, "endregion", 9) == 0)) { pc->type = (*next->str == 'r') ? CT_PP_REGION : CT_PP_ENDREGION; prev->parent_type = pc->type; } } /* Check for C# nullable types '?' is in next */ if ((cpd.lang_flags & LANG_CS) && (next->type == CT_QUESTION) && (next->orig_col == (pc->orig_col + pc->len))) { tmp = chunk_get_next_ncnl(next); if (tmp != NULL) { bool doit = ((tmp->type == CT_PAREN_CLOSE) || (tmp->type == CT_ANGLE_CLOSE)); if (tmp->type == CT_WORD) { tmp2 = chunk_get_next_ncnl(tmp); if ((tmp2 != NULL) && ((tmp2->type == CT_SEMICOLON) || (tmp2->type == CT_ASSIGN) || (tmp2->type == CT_COMMA))) { doit = true; } } if (doit) { pc->len++; chunk_del(next); next = tmp; } } } /* Convert '>' + '>' into '>>' */ if ((cpd.lang_flags & LANG_CS) && (pc->type == CT_ANGLE_CLOSE) && (next->type == CT_ANGLE_CLOSE) && (pc->parent_type == CT_NONE) && ((pc->orig_col + pc->len) == next->orig_col) && (next->parent_type == CT_NONE)) { pc->len++; pc->type = CT_ARITH; tmp = chunk_get_next_ncnl(next); chunk_del(next); next = tmp; } /* Change 'default(' into a sizeof-like statement */ if ((cpd.lang_flags & LANG_CS) && (pc->type == CT_DEFAULT) && (next->type == CT_PAREN_OPEN)) { pc->type = CT_SIZEOF; } if ((pc->type == CT_UNSAFE) && (next->type != CT_BRACE_OPEN)) { pc->type = CT_QUALIFIER; } /* TODO: determine other stuff here */ prev = pc; pc = next; next = chunk_get_next_ncnl(pc); } }
/* * See also it's preprocessor counterpart * add_long_preprocessor_conditional_block_comment * in defines.cpp */ void add_long_closebrace_comment(void) { LOG_FUNC_ENTRY(); chunk_t *br_close; chunk_t *fcn_pc = NULL; chunk_t *sw_pc = NULL; chunk_t *ns_pc = NULL; chunk_t *cl_pc = NULL; chunk_t *cl_semi_pc = NULL; unc_text xstr; for (chunk_t *pc = chunk_get_head(); pc; pc = chunk_get_next_ncnl(pc)) { if ((pc->type == CT_FUNC_DEF) || (pc->type == CT_OC_MSG_DECL)) { fcn_pc = pc; } else if (pc->type == CT_SWITCH) { /* kinda pointless, since it always has the text "switch" */ sw_pc = pc; } else if (pc->type == CT_NAMESPACE) { ns_pc = pc; } else if (pc->type == CT_CLASS) { cl_pc = pc; } if ((pc->type != CT_BRACE_OPEN) || (pc->flags & PCF_IN_PREPROC)) { continue; } chunk_t *br_open = pc; size_t nl_count = 0; chunk_t *tmp = pc; while ((tmp = chunk_get_next(tmp)) != NULL) { if (chunk_is_newline(tmp)) { nl_count += tmp->nl_count; } else if ((tmp->level == br_open->level) && (tmp->type == CT_BRACE_CLOSE)) { br_close = tmp; //LOG_FMT(LSYS, "found brace pair on lines %d and %d, nl_count=%d\n", // br_open->orig_line, br_close->orig_line, nl_count); /* Found the matching close brace - make sure a newline is next */ tmp = chunk_get_next(tmp); // Check for end of class if (tmp != NULL && tmp->parent_type == CT_CLASS && tmp->type == CT_SEMICOLON) { cl_semi_pc = tmp; tmp = chunk_get_next(tmp); if (tmp != NULL && !chunk_is_newline(tmp)) { tmp = cl_semi_pc; cl_semi_pc = NULL; } } if ((tmp == NULL) || chunk_is_newline(tmp)) { size_t nl_min = 0; chunk_t *tag_pc = NULL; if (br_open->parent_type == CT_SWITCH) { nl_min = cpd.settings[UO_mod_add_long_switch_closebrace_comment].u; tag_pc = sw_pc; xstr = sw_pc ? sw_pc->str : NULL; /* \todo NULL is no unc_text structure */ } else if ((br_open->parent_type == CT_FUNC_DEF) || (br_open->parent_type == CT_OC_MSG_DECL)) { nl_min = cpd.settings[UO_mod_add_long_function_closebrace_comment].u; // 76006 Explicit null dereferenced, 2016-03-17 tag_pc = fcn_pc; xstr.clear(); append_tag_name(xstr, tag_pc); } else if (br_open->parent_type == CT_NAMESPACE) { nl_min = cpd.settings[UO_mod_add_long_namespace_closebrace_comment].u; // 76007 Explicit null dereferenced, 2016-03-17 tag_pc = ns_pc; /* obtain the next chunck, normally this is the name of the namespace * and append it to generate "namespace xyz" */ xstr = ns_pc->str; xstr.append(" "); append_tag_name(xstr, chunk_get_next(ns_pc)); } else if (br_open->parent_type == CT_CLASS && cl_semi_pc && cl_pc) { nl_min = cpd.settings[UO_mod_add_long_class_closebrace_comment].u; tag_pc = cl_pc; xstr = tag_pc->str; xstr.append(" "); append_tag_name(xstr, chunk_get_next(cl_pc)); br_close = cl_semi_pc; cl_semi_pc = NULL; cl_pc = NULL; } if ((nl_min > 0) && (nl_count >= nl_min) && (tag_pc != NULL)) { /* determine the added comment style */ c_token_t style = (cpd.lang_flags & (LANG_CPP | LANG_CS)) ? CT_COMMENT_CPP : CT_COMMENT; /* Add a comment after the close brace */ insert_comment_after(br_close, style, xstr); } } break; } } } } // add_long_closebrace_comment
/** * If there is nothing but CT_WORD and CT_MEMBER, then it's probably a * template thingy. Otherwise, it's likely a comparison. */ static void check_template(chunk_t *start) { chunk_t *pc; chunk_t *end; chunk_t *prev; chunk_t *next; bool in_if = false; LOG_FMT(LTEMPL, "%s: Line %d, col %d:", __func__, start->orig_line, start->orig_col); prev = chunk_get_prev_ncnl(start, CNAV_PREPROC); if (prev == NULL) { return; } if (prev->type == CT_TEMPLATE) { LOG_FMT(LTEMPL, " CT_TEMPLATE:"); /* We have: "template< ... >", which is a template declaration */ int level = 1; for (pc = chunk_get_next_ncnl(start, CNAV_PREPROC); pc != NULL; pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) { LOG_FMT(LTEMPL, " [%s,%d]", get_token_name(pc->type), level); if (chunk_is_str(pc, "<", 1)) { level++; } else if (chunk_is_str(pc, ">", 1)) { level--; if (level == 0) { break; } } } end = pc; } else { /* We may have something like "a< ... >", which is a template use * '...' may consist of anything except braces {}, a semicolon, and * unbalanced parens. * if we are inside an 'if' statement and hit a CT_BOOL, then it isn't a * template. */ /* A template requires a word/type right before the open angle */ if ((prev->type != CT_WORD) && (prev->type != CT_TYPE) && (prev->type != CT_OPERATOR_VAL) && (prev->parent_type != CT_OPERATOR)) { LOG_FMT(LTEMPL, " - after %s + ( - Not a template\n", get_token_name(prev->type)); start->type = CT_COMPARE; return; } LOG_FMT(LTEMPL, " - prev %s -", get_token_name(prev->type)); /* Scan back and make sure we aren't inside square parens */ pc = start; while ((pc = chunk_get_prev_ncnl(pc, CNAV_PREPROC)) != NULL) { if ((pc->type == CT_SEMICOLON) || (pc->type == CT_BRACE_OPEN) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_SQUARE_CLOSE) || (pc->type == CT_SEMICOLON)) { break; } if (pc->type == CT_IF) { in_if = true; break; } if (pc->type == CT_SQUARE_OPEN) { LOG_FMT(LTEMPL, " - Not a template: after a square open\n"); start->type = CT_COMPARE; return; } } /* Scan forward to the angle close * If we have a comparison in there, then it can't be a template. */ c_token_t tokens[16]; int num_tokens = 1; tokens[0] = CT_ANGLE_OPEN; for (pc = chunk_get_next_ncnl(start, CNAV_PREPROC); pc != NULL; pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) { LOG_FMT(LTEMPL, " [%s,%d]", get_token_name(pc->type), num_tokens); if (chunk_is_str(pc, "<", 1)) { tokens[num_tokens++] = CT_ANGLE_OPEN; } else if (chunk_is_str(pc, ">", 1)) { if (--num_tokens <= 0) { break; } if (tokens[num_tokens] != CT_ANGLE_OPEN) { /* unbalanced parens */ break; } } else if (in_if && ((pc->type == CT_BOOL) || (pc->type == CT_COMPARE))) { break; } else if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_SEMICOLON)) { break; } else if (pc->type == CT_PAREN_OPEN) { if (num_tokens >= (int)(ARRAY_SIZE(tokens) - 1)) { break; } tokens[num_tokens++] = pc->type; } else if (pc->type == CT_PAREN_CLOSE) { num_tokens--; if (tokens[num_tokens] != (pc->type - 1)) { /* unbalanced parens */ break; } } } end = pc; } if ((end != NULL) && (end->type == CT_ANGLE_CLOSE)) { pc = chunk_get_next_ncnl(end, CNAV_PREPROC); if ((pc != NULL) && (pc->type != CT_NUMBER)) { LOG_FMT(LTEMPL, " - Template Detected\n"); start->parent_type = CT_TEMPLATE; pc = start; while (pc != end) { next = chunk_get_next_ncnl(pc, CNAV_PREPROC); pc->flags |= PCF_IN_TEMPLATE; if (next->type != CT_PAREN_OPEN) { make_type(pc); } pc = next; } end->parent_type = CT_TEMPLATE; end->flags |= PCF_IN_TEMPLATE; return; } } LOG_FMT(LTEMPL, " - Not a template: end = %s\n", (end != NULL) ? get_token_name(end->type) : "<null>"); start->type = CT_COMPARE; }
static chunk_t *mod_case_brace_add(chunk_t *cl_colon) { LOG_FUNC_ENTRY(); chunk_t *pc = cl_colon; chunk_t *last = NULL; chunk_t *next = chunk_get_next_ncnl(cl_colon, CNAV_PREPROC); LOG_FMT(LMCB, "%s: line %zu", __func__, pc->orig_line); while ((pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) != NULL) { if (pc->level < cl_colon->level) { LOG_FMT(LMCB, " - level drop\n"); return(next); } if ((pc->level == cl_colon->level) && ((pc->type == CT_CASE) || (pc->type == CT_BREAK))) { last = pc; //if (pc->type == CT_BREAK) //{ // /* Step past the semicolon */ // last = chunk_get_next_ncnl(chunk_get_next_ncnl(last)); //} break; } } if (last == NULL) { LOG_FMT(LMCB, " - NULL last\n"); return(next); } LOG_FMT(LMCB, " - adding before '%s' on line %zu\n", last->text(), last->orig_line); chunk_t chunk; chunk.type = CT_BRACE_OPEN; chunk.orig_line = cl_colon->orig_line; chunk.parent_type = CT_CASE; chunk.level = cl_colon->level; chunk.brace_level = cl_colon->brace_level; chunk.flags = pc->flags & PCF_COPY_FLAGS; chunk.str = "{"; chunk_t *br_open = chunk_add_after(&chunk, cl_colon); chunk.type = CT_BRACE_CLOSE; chunk.orig_line = last->orig_line; chunk.str = "}"; chunk_t *br_close = chunk_add_before(&chunk, last); newline_add_before(last); for (pc = chunk_get_next(br_open, CNAV_PREPROC); pc != br_close; pc = chunk_get_next(pc, CNAV_PREPROC)) { pc->level++; pc->brace_level++; } return(br_open); } // mod_case_brace_add