summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/src/combine_fix_mark.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.74.0/src/combine_fix_mark.cpp')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.74.0/src/combine_fix_mark.cpp2584
1 files changed, 2584 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/src/combine_fix_mark.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/src/combine_fix_mark.cpp
new file mode 100644
index 00000000..6213e509
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.74.0/src/combine_fix_mark.cpp
@@ -0,0 +1,2584 @@
+/**
+ * @file combine_fix_mark.cpp
+ *
+ * @author Guy Maurel
+ * @license GPL v2+
+ * extract fom combine.cpp
+ */
+
+#include "combine_fix_mark.h"
+
+#include "combine_skip.h"
+#include "combine_tools.h"
+#include "flag_parens.h"
+#include "log_rules.h"
+
+constexpr static auto LCURRENT = LCOMBINE;
+
+
+void fix_casts(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *pc;
+ chunk_t *prev;
+ chunk_t *first;
+ chunk_t *after;
+ chunk_t *last = nullptr;
+ chunk_t *paren_close;
+ const char *verb = "likely";
+ const char *detail = "";
+ size_t count = 0;
+ int word_count = 0;
+ bool nope;
+ bool doubtful_cast = false;
+
+
+ LOG_FMT(LCASTS, "%s(%d): start->text() is '%s', orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, start->text(), start->orig_line, start->orig_col);
+
+ prev = chunk_get_prev_ncnnlni(start); // Issue #2279
+
+ if (prev == nullptr)
+ {
+ return;
+ }
+
+ if (chunk_is_token(prev, CT_PP_DEFINED))
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast - after defined\n",
+ __func__, __LINE__);
+ return;
+ }
+
+ if (chunk_is_token(prev, CT_ANGLE_CLOSE))
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast - after > (template)\n",
+ __func__, __LINE__);
+ return;
+ }
+ // Make sure there is only WORD, TYPE, and '*' or '^' before the close paren
+ pc = chunk_get_next_ncnnl(start);
+ first = pc;
+
+ while ( pc != nullptr
+ && ( chunk_is_type(pc)
+ || chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, CT_QUALIFIER)
+ || chunk_is_token(pc, CT_DC_MEMBER)
+ || chunk_is_token(pc, CT_PP)
+ || chunk_is_token(pc, CT_STAR)
+ || chunk_is_token(pc, CT_QUESTION)
+ || chunk_is_token(pc, CT_CARET)
+ || chunk_is_token(pc, CT_TSQUARE)
+ || ( ( chunk_is_token(pc, CT_ANGLE_OPEN)
+ || chunk_is_token(pc, CT_ANGLE_CLOSE))
+ && language_is_set(LANG_OC | LANG_JAVA))
+ || ( ( chunk_is_token(pc, CT_QUESTION)
+ || chunk_is_token(pc, CT_COMMA)
+ || chunk_is_token(pc, CT_MEMBER))
+ && language_is_set(LANG_JAVA))
+ || chunk_is_token(pc, CT_AMP)))
+ {
+ LOG_FMT(LCASTS, "%s(%d): pc->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col, get_token_name(pc->type));
+
+ if ( chunk_is_token(pc, CT_WORD)
+ || ( chunk_is_token(last, CT_ANGLE_CLOSE)
+ && chunk_is_token(pc, CT_DC_MEMBER)))
+ {
+ word_count++;
+ }
+ else if ( chunk_is_token(pc, CT_DC_MEMBER)
+ || chunk_is_token(pc, CT_MEMBER)
+ || chunk_is_token(pc, CT_PP))
+ {
+ // might be negativ, such as with:
+ // a = val + (CFoo::bar_t)7;
+ word_count--;
+ }
+ last = pc;
+ pc = chunk_get_next_ncnnl(pc);
+ count++;
+ }
+
+ if ( pc == nullptr
+ || chunk_is_not_token(pc, CT_PAREN_CLOSE)
+ || chunk_is_token(prev, CT_OC_CLASS))
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast, hit type is %s\n",
+ __func__, __LINE__, pc == nullptr ? "NULL" : get_token_name(pc->type));
+ return;
+ }
+
+ if (word_count > 1)
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- too many words: %d\n",
+ __func__, __LINE__, word_count);
+ return;
+ }
+ paren_close = pc;
+
+ // If last is a type or star/caret, we have a cast for sure
+ if ( chunk_is_token(last, CT_STAR)
+ || chunk_is_token(last, CT_CARET)
+ || chunk_is_token(last, CT_PTR_TYPE)
+ || chunk_is_token(last, CT_TYPE)
+ || ( chunk_is_token(last, CT_ANGLE_CLOSE)
+ && language_is_set(LANG_OC | LANG_JAVA)))
+ {
+ verb = "for sure";
+ }
+ else if (count == 1)
+ {
+ /*
+ * We are on a potential cast of the form "(word)".
+ * We don't know if the word is a type. So lets guess based on some
+ * simple rules:
+ * - if all caps, likely a type
+ * - if it ends in _t, likely a type
+ * - if it's objective-c and the type is id, likely valid
+ */
+ verb = "guessed";
+
+ if ( (last->len() > 3)
+ && (last->str[last->len() - 2] == '_')
+ && (last->str[last->len() - 1] == 't'))
+ {
+ detail = " -- '_t'";
+ }
+ else if (is_ucase_str(last->text(), last->len()))
+ {
+ detail = " -- upper case";
+ }
+ else if ( language_is_set(LANG_OC)
+ && chunk_is_str(last, "id", 2))
+ {
+ detail = " -- Objective-C id";
+ }
+ else
+ {
+ // If we can't tell for sure whether this is a cast, decide against it
+ detail = " -- mixed case";
+ doubtful_cast = true;
+ }
+ /*
+ * If the next item is a * or &, the next item after that can't be a
+ * number or string.
+ *
+ * If the next item is a +, the next item has to be a number.
+ *
+ * If the next item is a -, the next item can't be a string.
+ *
+ * For this to be a cast, the close paren must be followed by:
+ * - constant (number or string)
+ * - paren open
+ * - word
+ *
+ * Find the next non-open paren item.
+ */
+ pc = chunk_get_next_ncnnl(paren_close);
+ after = pc;
+
+ do
+ {
+ after = chunk_get_next_ncnnl(after);
+ } while (chunk_is_token(after, CT_PAREN_OPEN));
+
+ if (after == nullptr)
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast - hit NULL\n",
+ __func__, __LINE__);
+ return;
+ }
+ nope = false;
+
+ if (chunk_is_ptr_operator(pc))
+ {
+ // star (*) and address (&) are ambiguous
+ if ( chunk_is_token(after, CT_NUMBER_FP)
+ || chunk_is_token(after, CT_NUMBER)
+ || chunk_is_token(after, CT_STRING)
+ || doubtful_cast)
+ {
+ nope = true;
+ }
+ }
+ else if (chunk_is_token(pc, CT_MINUS))
+ {
+ // (UINT8)-1 or (foo)-1 or (FOO)-'a'
+ if ( chunk_is_token(after, CT_STRING)
+ || doubtful_cast)
+ {
+ nope = true;
+ }
+ }
+ else if (chunk_is_token(pc, CT_PLUS))
+ {
+ // (UINT8)+1 or (foo)+1
+ if ( ( chunk_is_not_token(after, CT_NUMBER)
+ && chunk_is_not_token(after, CT_NUMBER_FP))
+ || doubtful_cast)
+ {
+ nope = true;
+ }
+ }
+ else if ( chunk_is_not_token(pc, CT_NUMBER_FP)
+ && chunk_is_not_token(pc, CT_NUMBER)
+ && chunk_is_not_token(pc, CT_WORD)
+ && chunk_is_not_token(pc, CT_THIS)
+ && chunk_is_not_token(pc, CT_TYPE)
+ && chunk_is_not_token(pc, CT_PAREN_OPEN)
+ && chunk_is_not_token(pc, CT_STRING)
+ && chunk_is_not_token(pc, CT_DECLTYPE)
+ && chunk_is_not_token(pc, CT_SIZEOF)
+ && get_chunk_parent_type(pc) != CT_SIZEOF
+ && chunk_is_not_token(pc, CT_FUNC_CALL)
+ && chunk_is_not_token(pc, CT_FUNC_CALL_USER)
+ && chunk_is_not_token(pc, CT_FUNCTION)
+ && chunk_is_not_token(pc, CT_BRACE_OPEN)
+ && (!( chunk_is_token(pc, CT_SQUARE_OPEN)
+ && language_is_set(LANG_OC))))
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast - followed by text() '%s', type is %s\n",
+ __func__, __LINE__, pc->text(), get_token_name(pc->type));
+ return;
+ }
+
+ if (nope)
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast - text() '%s' followed by type %s\n",
+ __func__, __LINE__, pc->text(), get_token_name(after->type));
+ return;
+ }
+ }
+ // if the 'cast' is followed by a semicolon, comma, bool or close parenthesis, it isn't
+ pc = chunk_get_next_ncnnl(paren_close);
+
+ if (pc == nullptr)
+ {
+ return;
+ }
+
+ if ( chunk_is_semicolon(pc)
+ || chunk_is_token(pc, CT_COMMA)
+ || chunk_is_token(pc, CT_BOOL) // Issue #2151
+ || chunk_is_paren_close(pc))
+ {
+ LOG_FMT(LCASTS, "%s(%d): -- not a cast - followed by type %s\n",
+ __func__, __LINE__, get_token_name(pc->type));
+ return;
+ }
+ set_chunk_parent(start, CT_C_CAST);
+ set_chunk_parent(paren_close, CT_C_CAST);
+
+ LOG_FMT(LCASTS, "%s(%d): -- %s c-cast: (",
+ __func__, __LINE__, verb);
+
+ for (pc = first;
+ pc != nullptr && pc != paren_close;
+ pc = chunk_get_next_ncnnl(pc))
+ {
+ set_chunk_parent(pc, CT_C_CAST);
+ make_type(pc);
+ LOG_FMT(LCASTS, " %s", pc->text());
+ }
+
+ LOG_FMT(LCASTS, " )%s\n", detail);
+
+ // Mark the next item as an expression start
+ pc = chunk_get_next_ncnnl(paren_close);
+
+ if (pc != nullptr)
+ {
+ chunk_flags_set(pc, PCF_EXPR_START);
+
+ if (chunk_is_opening_brace(pc))
+ {
+ set_paren_parent(pc, get_chunk_parent_type(start));
+ }
+ }
+} // fix_casts
+
+
+void fix_fcn_def_params(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+
+ if (start == nullptr)
+ {
+ return;
+ }
+ LOG_FMT(LFCNP, "%s(%d): text() '%s', type is %s, on orig_line %zu, level is %zu\n",
+ __func__, __LINE__, start->text(), get_token_name(start->type), start->orig_line, start->level);
+
+ while ( start != nullptr
+ && !chunk_is_paren_open(start))
+ {
+ start = chunk_get_next_ncnnl(start);
+ }
+
+ if (start == nullptr)// Coverity CID 76003, 1100782
+ {
+ return;
+ }
+ // ensure start chunk holds a single '(' character
+ assert( (start->len() == 1)
+ && (start->str[0] == '('));
+
+ ChunkStack cs;
+ size_t level = start->level + 1;
+ chunk_t *pc = start;
+
+ while ((pc = chunk_get_next_ncnnl(pc)) != nullptr)
+ {
+ if ( ( (start->len() == 1)
+ && (start->str[0] == ')'))
+ || pc->level < level)
+ {
+ LOG_FMT(LFCNP, "%s(%d): bailed on text() '%s', on orig_line %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line);
+ break;
+ }
+ LOG_FMT(LFCNP, "%s(%d): %s, text() '%s' on orig_line %zu, level %zu\n",
+ __func__, __LINE__, (pc->level > level) ? "skipping" : "looking at",
+ pc->text(), pc->orig_line, pc->level);
+
+ if (pc->level > level)
+ {
+ continue;
+ }
+
+ if ( chunk_is_star(pc)
+ || chunk_is_msref(pc)
+ || chunk_is_nullable(pc))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ cs.Push_Back(pc);
+ }
+ else if ( chunk_is_token(pc, CT_AMP)
+ || ( language_is_set(LANG_CPP)
+ && chunk_is_str(pc, "&&", 2)))
+ {
+ set_chunk_type(pc, CT_BYREF);
+ cs.Push_Back(pc);
+ }
+ else if (chunk_is_token(pc, CT_TYPE_WRAP))
+ {
+ cs.Push_Back(pc);
+ }
+ else if ( chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, CT_TYPE))
+ {
+ cs.Push_Back(pc);
+ }
+ else if ( chunk_is_token(pc, CT_COMMA)
+ || chunk_is_token(pc, CT_ASSIGN))
+ {
+ mark_variable_stack(cs, LFCNP);
+
+ if (chunk_is_token(pc, CT_ASSIGN))
+ {
+ // Mark assignment for default param spacing
+ set_chunk_parent(pc, CT_FUNC_PROTO);
+ }
+ }
+ }
+ mark_variable_stack(cs, LFCNP);
+} // fix_fcn_def_params
+
+
+void fix_type_cast(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *pc;
+
+ pc = chunk_get_next_ncnnl(start);
+
+ if ( pc == nullptr
+ || chunk_is_not_token(pc, CT_ANGLE_OPEN))
+ {
+ return;
+ }
+
+ while ( ((pc = chunk_get_next_ncnnl(pc)) != nullptr)
+ && pc->level >= start->level)
+ {
+ if ( pc->level == start->level
+ && chunk_is_token(pc, CT_ANGLE_CLOSE))
+ {
+ pc = chunk_get_next_ncnnl(pc);
+
+ if (pc == nullptr)
+ {
+ return;
+ }
+
+ if (chunk_is_str(pc, "(", 1))
+ {
+ set_paren_parent(pc, CT_TYPE_CAST);
+ }
+ return;
+ }
+ make_type(pc);
+ }
+} // fix_type_cast
+
+
+void fix_typedef(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+
+ if (start == nullptr)
+ {
+ return;
+ }
+ LOG_FMT(LTYPEDEF, "%s(%d): typedef @ orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, start->orig_line, start->orig_col);
+
+ chunk_t *the_type = nullptr;
+ chunk_t *last_op = nullptr;
+
+ /*
+ * Mark everything in the typedef and scan for ")(", which makes it a
+ * function type
+ */
+ for (chunk_t *next = chunk_get_next_ncnnl(start, scope_e::PREPROC)
+ ; next != nullptr && next->level >= start->level
+ ; next = chunk_get_next_ncnnl(next, scope_e::PREPROC))
+ {
+ chunk_flags_set(next, PCF_IN_TYPEDEF);
+
+ if (start->level == next->level)
+ {
+ if (chunk_is_semicolon(next))
+ {
+ set_chunk_parent(next, CT_TYPEDEF);
+ break;
+ }
+
+ if (chunk_is_token(next, CT_ATTRIBUTE))
+ {
+ break;
+ }
+
+ if ( language_is_set(LANG_D)
+ && chunk_is_token(next, CT_ASSIGN))
+ {
+ set_chunk_parent(next, CT_TYPEDEF);
+ break;
+ }
+ make_type(next);
+
+ if (chunk_is_token(next, CT_TYPE))
+ {
+ the_type = next;
+ }
+ chunk_flags_clr(next, PCF_VAR_1ST_DEF);
+
+ if (*next->str.c_str() == '(')
+ {
+ last_op = next;
+ }
+ }
+ }
+
+ // avoid interpreting typedef NS_ENUM (NSInteger, MyEnum) as a function def
+ if ( last_op != nullptr
+ && !( language_is_set(LANG_OC)
+ && get_chunk_parent_type(last_op) == CT_ENUM))
+ {
+ flag_parens(last_op, PCF_NONE, CT_FPAREN_OPEN, CT_TYPEDEF, false);
+ fix_fcn_def_params(last_op);
+
+ the_type = chunk_get_prev_ncnnlni(last_op, scope_e::PREPROC); // Issue #2279
+
+ if (the_type == nullptr)
+ {
+ return;
+ }
+ chunk_t *open_paren = nullptr;
+
+ if (chunk_is_paren_close(the_type))
+ {
+ open_paren = chunk_skip_to_match_rev(the_type);
+ mark_function_type(the_type);
+ the_type = chunk_get_prev_ncnnlni(the_type, scope_e::PREPROC); // Issue #2279
+
+ if (the_type == nullptr)
+ {
+ return;
+ }
+ }
+ else
+ {
+ // must be: "typedef <return type>func(params);"
+ set_chunk_type(the_type, CT_FUNC_TYPE);
+ }
+ set_chunk_parent(the_type, CT_TYPEDEF);
+
+ LOG_FMT(LTYPEDEF, "%s(%d): fcn typedef text() '%s', on orig_line %zu\n",
+ __func__, __LINE__, the_type->text(), the_type->orig_line);
+
+ // If we are aligning on the open parenthesis, grab that instead
+ log_rule_B("align_typedef_func");
+
+ if ( open_paren != nullptr
+ && options::align_typedef_func() == 1)
+ {
+ the_type = open_paren;
+ }
+ log_rule_B("align_typedef_func");
+
+ if (options::align_typedef_func() != 0)
+ {
+ LOG_FMT(LTYPEDEF, "%s(%d): -- align anchor on text() %s, @ orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, the_type->text(), the_type->orig_line, the_type->orig_col);
+ chunk_flags_set(the_type, PCF_ANCHOR);
+ }
+ // already did everything we need to do
+ return;
+ }
+ /*
+ * Skip over enum/struct/union stuff, as we know it isn't a return type
+ * for a function type
+ */
+ chunk_t *after = chunk_get_next_ncnnl(start, scope_e::PREPROC);
+
+ if (after == nullptr)
+ {
+ return;
+ }
+
+ if ( chunk_is_not_token(after, CT_ENUM)
+ && chunk_is_not_token(after, CT_STRUCT)
+ && chunk_is_not_token(after, CT_UNION))
+ {
+ if (the_type != nullptr)
+ {
+ // We have just a regular typedef
+ LOG_FMT(LTYPEDEF, "%s(%d): regular typedef text() %s, on orig_line %zu\n",
+ __func__, __LINE__, the_type->text(), the_type->orig_line);
+ chunk_flags_set(the_type, PCF_ANCHOR);
+ }
+ return;
+ }
+ // We have a struct/union/enum, next should be either a type or {
+ chunk_t *next = chunk_get_next_ncnnl(after, scope_e::PREPROC);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+
+ if (chunk_is_token(next, CT_TYPE))
+ {
+ next = chunk_get_next_ncnnl(next, scope_e::PREPROC);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ }
+
+ if (chunk_is_token(next, CT_BRACE_OPEN))
+ {
+ // Skip to the closing brace
+ chunk_t *br_c = chunk_get_next_type(next, CT_BRACE_CLOSE, next->level, scope_e::PREPROC);
+
+ if (br_c != nullptr)
+ {
+ const c_token_t tag = after->type;
+ set_chunk_parent(next, tag);
+ set_chunk_parent(br_c, tag);
+
+ if (tag == CT_ENUM)
+ {
+ flag_series(after, br_c, PCF_IN_ENUM);
+ }
+ else if (tag == CT_STRUCT)
+ {
+ flag_series(after, br_c, PCF_IN_STRUCT);
+ }
+ }
+ }
+
+ if (the_type != nullptr)
+ {
+ LOG_FMT(LTYPEDEF, "%s(%d): %s typedef text() %s, on orig_line %zu\n",
+ __func__, __LINE__, get_token_name(after->type), the_type->text(),
+ the_type->orig_line);
+ chunk_flags_set(the_type, PCF_ANCHOR);
+ }
+} // fix_typedef
+
+
+chunk_t *fix_variable_definition(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *pc = start;
+ chunk_t *end;
+ chunk_t *tmp_pc;
+ ChunkStack cs;
+ int idx;
+ int ref_idx;
+
+ LOG_FMT(LFVD, "%s(%d): start at pc->orig_line is %zu, pc->orig_col is %zu\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col);
+
+ // Scan for words and types and stars oh my!
+ while ( chunk_is_token(pc, CT_TYPE)
+ || chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, CT_QUALIFIER)
+ || chunk_is_token(pc, CT_TYPENAME)
+ || chunk_is_token(pc, CT_DC_MEMBER)
+ || chunk_is_token(pc, CT_MEMBER)
+ || chunk_is_token(pc, CT_PP) // Issue #3169
+ || chunk_is_ptr_operator(pc))
+ {
+ LOG_FMT(LFVD, "%s(%d): 1:pc->text() '%s', type is %s\n",
+ __func__, __LINE__, pc->text(), get_token_name(pc->type));
+ cs.Push_Back(pc);
+ pc = chunk_get_next_ncnnl(pc);
+
+ if (pc == nullptr)
+ {
+ LOG_FMT(LFVD, "%s(%d): pc is nullptr\n", __func__, __LINE__);
+ return(nullptr);
+ }
+ LOG_FMT(LFVD, "%s(%d): 2:pc->text() '%s', type is %s\n",
+ __func__, __LINE__, pc->text(), get_token_name(pc->type));
+
+ // Skip templates and attributes
+ pc = skip_template_next(pc);
+
+ if (pc == nullptr)
+ {
+ LOG_FMT(LFVD, "%s(%d): pc is nullptr\n", __func__, __LINE__);
+ return(nullptr);
+ }
+ LOG_FMT(LFVD, "%s(%d): 3:pc->text() '%s', type is %s\n",
+ __func__, __LINE__, pc->text(), get_token_name(pc->type));
+
+ pc = skip_attribute_next(pc);
+
+ if (pc == nullptr)
+ {
+ LOG_FMT(LFVD, "%s(%d): pc is nullptr\n", __func__, __LINE__);
+ return(nullptr);
+ }
+ LOG_FMT(LFVD, "%s(%d): 4:pc->text() '%s', type is %s\n",
+ __func__, __LINE__, pc->text(), get_token_name(pc->type));
+
+ if (language_is_set(LANG_JAVA))
+ {
+ pc = skip_tsquare_next(pc);
+ LOG_FMT(LFVD, "%s(%d): 5:pc->text() '%s', type is %s\n", __func__, __LINE__, pc->text(), get_token_name(pc->type));
+ }
+ }
+ end = pc;
+
+ if (end == nullptr)
+ {
+ LOG_FMT(LFVD, "%s(%d): end is nullptr\n", __func__, __LINE__);
+ return(nullptr);
+ }
+ LOG_FMT(LFVD, "%s(%d): end->type is %s\n", __func__, __LINE__, get_token_name(end->type));
+
+ if (chunk_is_token(end, CT_FUNC_CTOR_VAR)) // Issue #3010
+ {
+ return(end);
+ }
+
+ if ( cs.Len() == 1
+ && chunk_is_token(end, CT_BRACE_OPEN)
+ && get_chunk_parent_type(end) == CT_BRACED_INIT_LIST)
+ {
+ set_chunk_type(cs.Get(0)->m_pc, CT_TYPE);
+ }
+
+ // Function defs are handled elsewhere
+ if ( (cs.Len() <= 1)
+ || chunk_is_token(end, CT_FUNC_DEF)
+ || chunk_is_token(end, CT_FUNC_PROTO)
+ || chunk_is_token(end, CT_FUNC_CLASS_DEF)
+ || chunk_is_token(end, CT_FUNC_CLASS_PROTO)
+ || chunk_is_token(end, CT_OPERATOR))
+ {
+ return(skip_to_next_statement(end));
+ }
+ // ref_idx points to the alignable part of the variable definition
+ ref_idx = cs.Len() - 1;
+
+ // Check for the '::' stuff: "char *Engine::name"
+ if ( (cs.Len() >= 3)
+ && ( (cs.Get(cs.Len() - 2)->m_pc->type == CT_MEMBER)
+ || (cs.Get(cs.Len() - 2)->m_pc->type == CT_DC_MEMBER)))
+ {
+ idx = cs.Len() - 2;
+
+ while (idx > 0)
+ {
+ tmp_pc = cs.Get(idx)->m_pc;
+
+ if ( chunk_is_not_token(tmp_pc, CT_DC_MEMBER)
+ && chunk_is_not_token(tmp_pc, CT_MEMBER))
+ {
+ break;
+ }
+
+ if (idx == 0)
+ {
+ fprintf(stderr, "%s(%d): idx is ZERO, cannot be decremented, at line %zu, column %zu\n",
+ __func__, __LINE__, tmp_pc->orig_line, tmp_pc->orig_col);
+ log_flush(true);
+ exit(EX_SOFTWARE);
+ }
+ idx--;
+ tmp_pc = cs.Get(idx)->m_pc;
+
+ if ( chunk_is_not_token(tmp_pc, CT_WORD)
+ && chunk_is_not_token(tmp_pc, CT_TYPE))
+ {
+ break;
+ }
+ make_type(tmp_pc);
+ idx--;
+ }
+ ref_idx = idx + 1;
+ }
+ tmp_pc = cs.Get(ref_idx)->m_pc;
+ LOG_FMT(LFVD, "%s(%d): ref_idx(%d) is '%s'\n", __func__, __LINE__, ref_idx, tmp_pc->text());
+
+ // No type part found!
+ if (ref_idx <= 0)
+ {
+ return(skip_to_next_statement(end));
+ }
+ LOG_FMT(LFVD2, "%s(%d): orig_line is %zu, TYPE : ", __func__, __LINE__, start->orig_line);
+
+ for (size_t idxForCs = 0; idxForCs < cs.Len() - 1; idxForCs++)
+ {
+ tmp_pc = cs.Get(idxForCs)->m_pc;
+ make_type(tmp_pc);
+ chunk_flags_set(tmp_pc, PCF_VAR_TYPE);
+ LOG_FMT(LFVD2, " text() is '%s', type is %s", tmp_pc->text(), get_token_name(tmp_pc->type));
+ }
+
+ LOG_FMT(LFVD2, "\n");
+
+ // OK we have two or more items, mark types up to the end.
+ LOG_FMT(LFVD, "%s(%d): pc->orig_line is %zu, pc->orig_col is %zu\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col);
+ mark_variable_definition(cs.Get(cs.Len() - 1)->m_pc);
+
+ if (chunk_is_token(end, CT_COMMA))
+ {
+ return(chunk_get_next_ncnnl(end));
+ }
+ return(skip_to_next_statement(end));
+} // fix_variable_definition
+
+
+void mark_cpp_constructor(chunk_t *pc)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *paren_open;
+ chunk_t *tmp;
+ chunk_t *after;
+ chunk_t *var;
+ bool is_destr = false;
+
+ tmp = chunk_get_prev_ncnnlni(pc); // Issue #2279
+
+ if ( chunk_is_token(tmp, CT_INV)
+ || chunk_is_token(tmp, CT_DESTRUCTOR))
+ {
+ set_chunk_type(tmp, CT_DESTRUCTOR);
+ set_chunk_parent(pc, CT_DESTRUCTOR);
+ is_destr = true;
+ }
+ LOG_FMT(LFTOR, "%s(%d): orig_line is %zu, orig_col is %zu, FOUND %sSTRUCTOR for '%s'[%s] prev '%s'[%s]\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col,
+ is_destr ? "DE" : "CON",
+ pc->text(), get_token_name(pc->type),
+ tmp->text(), get_token_name(tmp->type));
+
+ paren_open = skip_template_next(chunk_get_next_ncnnl(pc));
+
+ if (!chunk_is_str(paren_open, "(", 1))
+ {
+ LOG_FMT(LWARN, "%s:%zu Expected '(', got: [%s]\n",
+ cpd.filename.c_str(), paren_open->orig_line,
+ paren_open->text());
+ return;
+ }
+ // Mark parameters
+ fix_fcn_def_params(paren_open);
+ after = flag_parens(paren_open, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_FUNC_CLASS_PROTO, false);
+
+ LOG_FMT(LFTOR, "%s(%d): text() '%s'\n", __func__, __LINE__, after->text());
+
+ // Scan until the brace open, mark everything
+ tmp = paren_open;
+ bool hit_colon = false;
+
+ while ( tmp != nullptr
+ && ( chunk_is_not_token(tmp, CT_BRACE_OPEN)
+ || tmp->level != paren_open->level)
+ && !chunk_is_semicolon(tmp))
+ {
+ LOG_FMT(LFTOR, "%s(%d): tmp is '%s', orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, tmp->text(), tmp->orig_line, tmp->orig_col);
+ chunk_flags_set(tmp, PCF_IN_CONST_ARGS);
+ tmp = chunk_get_next_ncnnl(tmp);
+
+ if ( chunk_is_str(tmp, ":", 1)
+ && tmp->level == paren_open->level)
+ {
+ set_chunk_type(tmp, CT_CONSTR_COLON);
+ hit_colon = true;
+ }
+
+ if ( hit_colon
+ && ( chunk_is_paren_open(tmp)
+ || chunk_is_opening_brace(tmp))
+ && tmp->level == paren_open->level)
+ {
+ var = skip_template_prev(chunk_get_prev_ncnnlni(tmp)); // Issue #2279
+
+ if ( chunk_is_token(var, CT_TYPE)
+ || chunk_is_token(var, CT_WORD))
+ {
+ set_chunk_type(var, CT_FUNC_CTOR_VAR);
+ flag_parens(tmp, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_FUNC_CTOR_VAR, false);
+ }
+ }
+ }
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ set_paren_parent(paren_open, CT_FUNC_CLASS_DEF);
+ set_paren_parent(tmp, CT_FUNC_CLASS_DEF);
+ LOG_FMT(LFCN, "%s(%d): Marked '%s' as FUNC_CLASS_DEF on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ }
+ else
+ {
+ set_chunk_parent(tmp, CT_FUNC_CLASS_PROTO);
+ set_chunk_type(pc, CT_FUNC_CLASS_PROTO);
+ LOG_FMT(LFCN, "%s(%d): Marked '%s' as FUNC_CLASS_PROTO on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ }
+ tmp = chunk_get_prev_ncnnlni(pc); // Issue #2907
+
+ if (chunk_is_token(tmp, CT_DESTRUCTOR))
+ {
+ set_chunk_parent(tmp, pc->type);
+ tmp = chunk_get_prev_ncnnlni(tmp);
+ }
+
+ while (chunk_is_token(tmp, CT_QUALIFIER))
+ {
+ set_chunk_parent(tmp, pc->type);
+ tmp = chunk_get_prev_ncnnlni(tmp);
+ }
+} // mark_cpp_constructor
+
+
+void mark_cpp_lambda(chunk_t *square_open)
+{
+ if ( chunk_is_token(square_open, CT_SQUARE_OPEN)
+ && get_chunk_parent_type(square_open) == CT_CPP_LAMBDA)
+ {
+ auto *brace_close = chunk_get_next_type(square_open, CT_BRACE_CLOSE, square_open->level);
+
+ if (get_chunk_parent_type(brace_close) == CT_CPP_LAMBDA)
+ {
+ for (auto *pc = square_open; pc != brace_close; pc = chunk_get_next_ncnnl(pc))
+ {
+ chunk_flags_set(pc, PCF_IN_LAMBDA);
+ }
+ }
+ }
+} // mark_cpp_lambda
+
+
+void mark_define_expressions(void)
+{
+ LOG_FUNC_ENTRY();
+
+ bool in_define = false;
+ bool first = true;
+ chunk_t *pc = chunk_get_head();
+ chunk_t *prev = pc;
+
+ while (pc != nullptr)
+ {
+ if (!in_define)
+ {
+ if ( chunk_is_token(pc, CT_PP_DEFINE)
+ || chunk_is_token(pc, CT_PP_IF)
+ || chunk_is_token(pc, CT_PP_ELSE))
+ {
+ in_define = true;
+ first = true;
+ }
+ }
+ else
+ {
+ if ( !pc->flags.test(PCF_IN_PREPROC)
+ || chunk_is_token(pc, CT_PREPROC))
+ {
+ in_define = false;
+ }
+ else
+ {
+ if ( chunk_is_not_token(pc, CT_MACRO)
+ && ( first
+ || chunk_is_token(prev, CT_PAREN_OPEN)
+ || chunk_is_token(prev, CT_ARITH)
+ || chunk_is_token(prev, CT_SHIFT)
+ || chunk_is_token(prev, CT_CARET)
+ || chunk_is_token(prev, CT_ASSIGN)
+ || chunk_is_token(prev, CT_COMPARE)
+ || chunk_is_token(prev, CT_RETURN)
+ || chunk_is_token(prev, CT_GOTO)
+ || chunk_is_token(prev, CT_CONTINUE)
+ || chunk_is_token(prev, CT_FPAREN_OPEN)
+ || chunk_is_token(prev, CT_SPAREN_OPEN)
+ || chunk_is_token(prev, CT_BRACE_OPEN)
+ || chunk_is_semicolon(prev)
+ || chunk_is_token(prev, CT_COMMA)
+ || chunk_is_token(prev, CT_COLON)
+ || chunk_is_token(prev, CT_QUESTION)))
+ {
+ chunk_flags_set(pc, PCF_EXPR_START);
+ first = false;
+ }
+ }
+ }
+ prev = pc;
+ pc = chunk_get_next(pc);
+ }
+} // mark_define_expressions
+
+
+void mark_exec_sql(chunk_t *pc)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *tmp;
+
+ // Change CT_WORD to CT_SQL_WORD
+ for (tmp = chunk_get_next(pc); tmp != nullptr; tmp = chunk_get_next(tmp))
+ {
+ set_chunk_parent(tmp, pc->type);
+
+ if (chunk_is_token(tmp, CT_WORD))
+ {
+ set_chunk_type(tmp, CT_SQL_WORD);
+ }
+
+ if (chunk_is_token(tmp, CT_SEMICOLON))
+ {
+ break;
+ }
+ }
+
+ if ( chunk_is_not_token(pc, CT_SQL_BEGIN)
+ || tmp == nullptr
+ || chunk_is_not_token(tmp, CT_SEMICOLON))
+ {
+ return;
+ }
+
+ for (tmp = chunk_get_next(tmp);
+ tmp != nullptr && chunk_is_not_token(tmp, CT_SQL_END);
+ tmp = chunk_get_next(tmp))
+ {
+ tmp->level++;
+ }
+} // mark_exec_sql
+
+
+void mark_function_return_type(chunk_t *fname, chunk_t *start, c_token_t parent_type)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *pc = start;
+
+ if (pc != nullptr)
+ {
+ // Step backwards from pc and mark the parent of the return type
+ LOG_FMT(LFCNR, "%s(%d): (backwards) return type for '%s' @ orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, fname->text(), fname->orig_line, fname->orig_col);
+
+ chunk_t *first = pc;
+
+ while (pc != nullptr)
+ {
+ LOG_FMT(LFCNR, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s', type is %s, ",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text(), get_token_name(pc->type));
+ log_pcf_flags(LFCNR, pc->flags);
+
+ if (chunk_is_token(pc, CT_ANGLE_CLOSE))
+ {
+ pc = skip_template_prev(pc);
+
+ if ( pc == nullptr
+ || chunk_is_token(pc, CT_TEMPLATE))
+ {
+ //either expression is not complete or this is smth like 'template<T> void func()'
+ // - we are not interested in 'template<T>' part
+ break;
+ }
+ else
+ {
+ //this is smth like 'vector<int> func()' and 'pc' is currently on 'vector' - just proceed
+ }
+ }
+
+ if ( ( !chunk_is_type(pc)
+ && chunk_is_not_token(pc, CT_OPERATOR)
+ && chunk_is_not_token(pc, CT_WORD)
+ && chunk_is_not_token(pc, CT_ADDR))
+ || pc->flags.test(PCF_IN_PREPROC))
+ {
+ break;
+ }
+
+ if (!chunk_is_ptr_operator(pc))
+ {
+ first = pc;
+ }
+ pc = chunk_get_prev_ncnnlni(pc); // Issue #2279
+ }
+ LOG_FMT(LFCNR, "%s(%d): marking returns...", __func__, __LINE__);
+
+ // Changing words to types into tuple return types in CS.
+ bool is_return_tuple = false;
+
+ if ( chunk_is_token(pc, CT_PAREN_CLOSE)
+ && !pc->flags.test(PCF_IN_PREPROC))
+ {
+ first = chunk_skip_to_match_rev(pc);
+ is_return_tuple = true;
+ }
+ pc = first;
+
+ while (pc != nullptr)
+ {
+ LOG_FMT(LFCNR, " text() '%s', type is %s", pc->text(), get_token_name(pc->type));
+
+ if (parent_type != CT_NONE)
+ {
+ set_chunk_parent(pc, parent_type);
+ }
+ chunk_t *prev = chunk_get_prev_ncnnlni(pc); // Issue #2279
+
+ if ( !is_return_tuple
+ || chunk_is_not_token(pc, CT_WORD)
+ || ( prev != nullptr
+ && chunk_is_not_token(prev, CT_TYPE)))
+ {
+ make_type(pc);
+ }
+
+ if (pc == start)
+ {
+ break;
+ }
+ pc = chunk_get_next_ncnnl(pc);
+
+ //template angles should keep parent type CT_TEMPLATE
+ if (chunk_is_token(pc, CT_ANGLE_OPEN))
+ {
+ pc = chunk_get_next_type(pc, CT_ANGLE_CLOSE, pc->level);
+
+ if (pc == start)
+ {
+ break;
+ }
+ pc = chunk_get_next_ncnnl(pc);
+ }
+ }
+ LOG_FMT(LFCNR, "\n");
+
+ // Back up and mark parent type on friend declarations
+ if ( parent_type != CT_NONE
+ && first
+ && first->flags.test(PCF_IN_CLASS))
+ {
+ pc = chunk_get_prev_ncnnlni(first); // Issue #2279
+
+ if (chunk_is_token(pc, CT_FRIEND))
+ {
+ LOG_FMT(LFCNR, "%s(%d): marking friend\n", __func__, __LINE__);
+ set_chunk_parent(pc, parent_type);
+ // A friend might be preceded by a template specification, as in:
+ // template <...> friend type func(...);
+ // If so, we need to mark that also
+ pc = chunk_get_prev_ncnnlni(pc); // Issue #2279
+
+ if (chunk_is_token(pc, CT_ANGLE_CLOSE))
+ {
+ pc = skip_template_prev(pc);
+
+ if (chunk_is_token(pc, CT_TEMPLATE))
+ {
+ LOG_FMT(LFCNR, "%s(%d): marking friend template\n",
+ __func__, __LINE__);
+ set_chunk_parent(pc, parent_type);
+ }
+ }
+ }
+ }
+ }
+} // mark_function_return_type
+
+
+void mark_function(chunk_t *pc)
+{
+ LOG_FUNC_ENTRY();
+
+ if (pc == nullptr)
+ {
+ return;
+ }
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ chunk_t *prev = chunk_get_prev_ncnnlni(pc); // Issue #2279
+ chunk_t *next = chunk_get_next_ncnnl_in_pp(pc);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ chunk_t *tmp;
+ chunk_t *semi = nullptr;
+ chunk_t *paren_open;
+ chunk_t *paren_close;
+
+ // Find out what is before the operator
+ if (get_chunk_parent_type(pc) == CT_OPERATOR)
+ {
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ log_pcf_flags(LGUY, pc->flags);
+ chunk_t *pc_op = chunk_get_prev_type(pc, CT_OPERATOR, pc->level);
+
+ if ( pc_op != nullptr
+ && pc_op->flags.test(PCF_EXPR_START))
+ {
+ LOG_FMT(LFCN, "%s(%d): (4) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ }
+
+ if (language_is_set(LANG_CPP))
+ {
+ tmp = pc;
+
+ while ((tmp = chunk_get_prev_ncnnlni(tmp)) != nullptr) // Issue #2279
+ {
+ if ( chunk_is_token(tmp, CT_BRACE_CLOSE)
+ || chunk_is_token(tmp, CT_BRACE_OPEN) // Issue 575
+ || chunk_is_token(tmp, CT_SEMICOLON))
+ {
+ break;
+ }
+
+ if ( chunk_is_paren_open(tmp)
+ && !pc->flags.test(PCF_IN_PREPROC)) // Issue #2703
+ {
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col, tmp->text());
+ LOG_FMT(LFCN, "%s(%d): (5) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ break;
+ }
+
+ if (chunk_is_token(tmp, CT_ASSIGN))
+ {
+ LOG_FMT(LFCN, "%s(%d): (6) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ break;
+ }
+
+ if (chunk_is_token(tmp, CT_TEMPLATE))
+ {
+ LOG_FMT(LFCN, "%s(%d): (7) SET TO CT_FUNC_DEF: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_DEF);
+ break;
+ }
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ if (get_chunk_parent_type(tmp) == CT_FUNC_DEF)
+ {
+ LOG_FMT(LFCN, "%s(%d): (8) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ }
+
+ if ( get_chunk_parent_type(tmp) == CT_CLASS
+ || get_chunk_parent_type(tmp) == CT_STRUCT)
+ {
+ LOG_FMT(LFCN, "%s(%d): (9) SET TO CT_FUNC_DEF: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_DEF);
+ }
+ break;
+ }
+ }
+
+ if ( tmp != nullptr
+ && chunk_is_not_token(pc, CT_FUNC_CALL))
+ {
+ // Mark the return type
+ while ( (tmp = chunk_get_next_ncnnl(tmp)) != pc
+ && tmp != nullptr)
+ {
+ make_type(tmp); // Mark the return type
+ }
+ }
+ }
+ }
+
+ if ( chunk_is_ptr_operator(next)
+ || chunk_is_newline(next))
+ {
+ next = chunk_get_next_ncnnl_in_pp(next);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ }
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s, type is %s, parent_type is %s\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text(),
+ get_token_name(pc->type), get_token_name(get_chunk_parent_type(pc)));
+ LOG_FMT(LFCN, " level is %zu, brace_level is %zu, next->text() '%s', next->type is %s, next->level is %zu\n",
+ pc->level, pc->brace_level,
+ next->text(), get_token_name(next->type), next->level);
+
+ if (pc->flags.test(PCF_IN_CONST_ARGS))
+ {
+ set_chunk_type(pc, CT_FUNC_CTOR_VAR);
+ LOG_FMT(LFCN, "%s(%d): 1) Marked [%s] as FUNC_CTOR_VAR on line %zu col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ next = skip_template_next(next);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, pc->type, true);
+ return;
+ }
+ // Skip over any template and attribute madness
+ next = skip_template_next(next);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ next = skip_attribute_next(next);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ // Find the open and close parenthesis
+ paren_open = chunk_get_next_str(pc, "(", 1, pc->level);
+ paren_close = chunk_get_next_str(paren_open, ")", 1, pc->level);
+
+ if ( paren_open == nullptr
+ || paren_close == nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): No parens found for [%s] on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ return;
+ }
+ /*
+ * This part detects either chained function calls or a function ptr definition.
+ * MYTYPE (*func)(void);
+ * mWriter( "class Clst_"c )( somestr.getText() )( " : Cluster {"c ).newline;
+ *
+ * For it to be a function variable def, there must be a '*' followed by a
+ * single word.
+ *
+ * Otherwise, it must be chained function calls.
+ */
+ tmp = chunk_get_next_ncnnl(paren_close);
+
+ if ( tmp != nullptr
+ && chunk_is_str(tmp, "(", 1))
+ {
+ chunk_t *tmp1;
+ chunk_t *tmp2;
+ chunk_t *tmp3;
+
+ // skip over any leading class/namespace in: "T(F::*A)();"
+ tmp1 = chunk_get_next_ncnnl(next);
+
+ while (tmp1 != nullptr)
+ {
+ tmp2 = chunk_get_next_ncnnl(tmp1);
+
+ if ( !chunk_is_word(tmp1)
+ || chunk_is_not_token(tmp2, CT_DC_MEMBER))
+ {
+ break;
+ }
+ tmp1 = chunk_get_next_ncnnl(tmp2);
+ }
+ tmp2 = chunk_get_next_ncnnl(tmp1);
+
+ if (chunk_is_str(tmp2, ")", 1))
+ {
+ tmp3 = tmp2;
+ tmp2 = nullptr;
+ }
+ else
+ {
+ tmp3 = chunk_get_next_ncnnl(tmp2);
+ }
+ tmp3 = chunk_get_next_ssq(tmp3);
+
+ if ( chunk_is_str(tmp3, ")", 1)
+ && ( chunk_is_star(tmp1)
+ || chunk_is_msref(tmp1)
+ || ( language_is_set(LANG_OC)
+ && chunk_is_token(tmp1, CT_CARET)))
+ && ( tmp2 == nullptr
+ || chunk_is_token(tmp2, CT_WORD)))
+ {
+ if (tmp2)
+ {
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, function variable '%s', changing '%s' into a type\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, tmp2->text(), pc->text());
+ set_chunk_type(tmp2, CT_FUNC_VAR);
+ flag_parens(paren_open, PCF_NONE, CT_PAREN_OPEN, CT_FUNC_VAR, false);
+
+ LOG_FMT(LFCN, "%s(%d): paren open @ orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, paren_open->orig_line, paren_open->orig_col);
+ }
+ else
+ {
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, function type, changing '%s' into a type\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+
+ if (tmp2)
+ {
+ set_chunk_type(tmp2, CT_FUNC_TYPE);
+ }
+ flag_parens(paren_open, PCF_NONE, CT_PAREN_OPEN, CT_FUNC_TYPE, false);
+ }
+ set_chunk_type(pc, CT_TYPE);
+ set_chunk_type(tmp1, CT_PTR_TYPE);
+ chunk_flags_clr(pc, PCF_VAR_1ST_DEF);
+
+ if (tmp2 != nullptr)
+ {
+ chunk_flags_set(tmp2, PCF_VAR_1ST_DEF);
+ }
+ flag_parens(tmp, PCF_NONE, CT_FPAREN_OPEN, CT_FUNC_PROTO, false);
+ fix_fcn_def_params(tmp);
+ return;
+ }
+ LOG_FMT(LFCN, "%s(%d): chained function calls? text() is '%s', orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ }
+
+ // Assume it is a function call if not already labeled
+ if (chunk_is_token(pc, CT_FUNCTION))
+ {
+ LOG_FMT(LFCN, "%s(%d): examine: text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col, get_token_name(pc->type));
+ // look for an assigment. Issue #575
+ chunk_t *temp = chunk_get_next_type(pc, CT_ASSIGN, pc->level);
+
+ if (temp != nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): assigment found, orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, temp->orig_line, temp->orig_col, temp->text());
+ LOG_FMT(LFCN, "%s(%d): (10) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ }
+ else
+ {
+ LOG_FMT(LFCN, "%s(%d): (11) SET TO %s: orig_line is %zu, orig_col is %zu, text() '%s'",
+ __func__, __LINE__, (get_chunk_parent_type(pc) == CT_OPERATOR) ? "CT_FUNC_DEF" : "CT_FUNC_CALL",
+ pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, (get_chunk_parent_type(pc) == CT_OPERATOR) ? CT_FUNC_DEF : CT_FUNC_CALL);
+ }
+ }
+ LOG_FMT(LFCN, "%s(%d): Check for C++ function def, text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col, get_token_name(pc->type));
+
+ if (prev != nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): prev->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, prev->text(), prev->orig_line, prev->orig_col, get_token_name(prev->type));
+ }
+
+ // Check for C++ function def
+ if ( chunk_is_token(pc, CT_FUNC_CLASS_DEF)
+ || ( prev != nullptr
+ && ( chunk_is_token(prev, CT_INV)
+ || chunk_is_token(prev, CT_DC_MEMBER))))
+ {
+ chunk_t *destr = nullptr;
+
+ if (chunk_is_token(prev, CT_INV))
+ {
+ // TODO: do we care that this is the destructor?
+ set_chunk_type(prev, CT_DESTRUCTOR);
+ set_chunk_type(pc, CT_FUNC_CLASS_DEF);
+
+ set_chunk_parent(pc, CT_DESTRUCTOR);
+
+ destr = prev;
+ // Point to the item previous to the class name
+ prev = chunk_get_prev_ncnnlnp(prev);
+ }
+
+ if (chunk_is_token(prev, CT_DC_MEMBER))
+ {
+ prev = chunk_get_prev_ncnnlnp(prev);
+
+ if (prev)
+ {
+ LOG_FMT(LFCN, "%s(%d): prev->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, prev->text(), prev->orig_line, prev->orig_col,
+ get_token_name(prev->type));
+ prev = skip_template_prev(prev);
+ LOG_FMT(LFCN, "%s(%d): prev->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, prev->text(), prev->orig_line, prev->orig_col,
+ get_token_name(prev->type));
+ prev = skip_attribute_prev(prev);
+ LOG_FMT(LFCN, "%s(%d): prev->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, prev->text(), prev->orig_line, prev->orig_col,
+ get_token_name(prev->type));
+ }
+
+ if ( chunk_is_token(prev, CT_WORD)
+ || chunk_is_token(prev, CT_TYPE))
+ {
+ if (pc->str.equals(prev->str))
+ {
+ LOG_FMT(LFCN, "%s(%d): pc->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col,
+ get_token_name(prev->type));
+ set_chunk_type(pc, CT_FUNC_CLASS_DEF);
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu - FOUND %sSTRUCTOR for '%s', type is %s\n",
+ __func__, __LINE__,
+ prev->orig_line, prev->orig_col,
+ (destr != nullptr) ? "DE" : "CON",
+ prev->text(), get_token_name(prev->type));
+
+ mark_cpp_constructor(pc);
+ return;
+ }
+ // Point to the item previous to the class name
+ prev = chunk_get_prev_ncnnlnp(prev);
+ }
+ }
+ }
+
+ /*
+ * Determine if this is a function call or a function def/proto
+ * We check for level==1 to allow the case that a function prototype is
+ * wrapped in a macro: "MACRO(void foo(void));"
+ */
+ if ( chunk_is_token(pc, CT_FUNC_CALL)
+ && ( pc->level == pc->brace_level
+ || pc->level == 1)
+ && !pc->flags.test(PCF_IN_ARRAY_ASSIGN))
+ {
+ bool isa_def = false;
+ bool hit_star = false;
+ LOG_FMT(LFCN, "%s(%d): pc->text() is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col,
+ get_token_name(pc->type));
+
+ if (prev == nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): Checking func call: prev is NULL\n",
+ __func__, __LINE__);
+ }
+ else
+ {
+ LOG_FMT(LFCN, "%s(%d): Checking func call: prev->text() '%s', prev->type is %s\n",
+ __func__, __LINE__, prev->text(), get_token_name(prev->type));
+ }
+ // if (!chunk_ends_type(prev))
+ // {
+ // goto bad_ret_type;
+ // }
+
+ /*
+ * REVISIT:
+ * a function def can only occur at brace level, but not inside an
+ * assignment, structure, enum, or union.
+ * The close paren must be followed by an open brace, with an optional
+ * qualifier (const) in between.
+ * There can be all sorts of template stuff and/or '[]' in the type.
+ * This hack mostly checks that.
+ *
+ * Examples:
+ * foo->bar(maid); -- fcn call
+ * FOO * bar(); -- fcn proto or class variable
+ * FOO foo(); -- fcn proto or class variable
+ * FOO foo(1); -- class variable
+ * a = FOO * bar(); -- fcn call
+ * a.y = foo() * bar(); -- fcn call
+ * static const char * const fizz(); -- fcn def
+ */
+ while (prev != nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): next step with: prev->orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, prev->orig_line, prev->orig_col, prev->text());
+
+ if (get_chunk_parent_type(pc) == CT_FIXED)
+ {
+ isa_def = true;
+ }
+
+ if (prev->flags.test(PCF_IN_PREPROC))
+ {
+ prev = chunk_get_prev_ncnnlnp(prev);
+ continue;
+ }
+
+ // Some code slips an attribute between the type and function
+ if ( chunk_is_token(prev, CT_FPAREN_CLOSE)
+ && get_chunk_parent_type(prev) == CT_ATTRIBUTE)
+ {
+ prev = skip_attribute_prev(prev);
+ continue;
+ }
+
+ // skip const(TYPE)
+ if ( chunk_is_token(prev, CT_PAREN_CLOSE)
+ && get_chunk_parent_type(prev) == CT_D_CAST)
+ {
+ LOG_FMT(LFCN, "%s(%d): --> For sure a prototype or definition\n",
+ __func__, __LINE__);
+ isa_def = true;
+ break;
+ }
+
+ if (get_chunk_parent_type(prev) == CT_DECLSPEC) // Issue 1289
+ {
+ prev = chunk_skip_to_match_rev(prev);
+ prev = chunk_get_prev(prev);
+
+ if (chunk_is_token(prev, CT_DECLSPEC))
+ {
+ prev = chunk_get_prev(prev);
+ }
+ }
+
+ // if it was determined that this could be a function definition
+ // but one of the preceding tokens is a CT_MEMBER than this is not a
+ // fcn def, issue #1466
+ if ( isa_def
+ && chunk_is_token(prev, CT_MEMBER))
+ {
+ isa_def = false;
+ }
+
+ // get first chunk before: A::B::pc | this.B.pc | this->B->pc
+ if ( chunk_is_token(prev, CT_DC_MEMBER)
+ || chunk_is_token(prev, CT_MEMBER))
+ {
+ while ( chunk_is_token(prev, CT_DC_MEMBER)
+ || chunk_is_token(prev, CT_MEMBER))
+ {
+ prev = chunk_get_prev_ncnnlnp(prev);
+
+ if ( prev == nullptr
+ || ( chunk_is_not_token(prev, CT_WORD)
+ && chunk_is_not_token(prev, CT_TYPE)
+ && chunk_is_not_token(prev, CT_THIS)))
+ {
+ LOG_FMT(LFCN, "%s(%d): --? skipped MEMBER and landed on %s\n",
+ __func__, __LINE__, (prev == nullptr) ? "<null>" : get_token_name(prev->type));
+ break;
+ }
+ LOG_FMT(LFCN, "%s(%d): <skip> '%s'\n",
+ __func__, __LINE__, prev->text());
+
+ // Issue #1112
+ // clarification: this will skip the CT_WORD, CT_TYPE or CT_THIS landing on either
+ // another CT_DC_MEMBER or CT_MEMBER or a token that indicates the context of the
+ // token in question; therefore, exit loop when not a CT_DC_MEMBER or CT_MEMBER
+ prev = chunk_get_prev_ncnnlnp(prev);
+
+ if (prev == nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): prev is nullptr\n",
+ __func__, __LINE__);
+ }
+ else
+ {
+ LOG_FMT(LFCN, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, prev->orig_line, prev->orig_col, prev->text());
+ }
+ }
+
+ if (prev == nullptr)
+ {
+ break;
+ }
+ }
+
+ // If we are on a TYPE or WORD, then this could be a proto or def
+ if ( chunk_is_token(prev, CT_TYPE)
+ || chunk_is_token(prev, CT_WORD))
+ {
+ if (!hit_star)
+ {
+ LOG_FMT(LFCN, "%s(%d): --> For sure a prototype or definition\n",
+ __func__, __LINE__);
+ isa_def = true;
+ break;
+ }
+ chunk_t *prev_prev = chunk_get_prev_ncnnlnp(prev);
+
+ if (!chunk_is_token(prev_prev, CT_QUESTION)) // Issue #1753
+ {
+ LOG_FMT(LFCN, "%s(%d): --> maybe a proto/def\n",
+ __func__, __LINE__);
+
+ LOG_FMT(LFCN, "%s(%d): prev is '%s', orig_line is %zu, orig_col is %zu, type is %s, parent_type is %s\n",
+ __func__, __LINE__, prev->text(), prev->orig_line, prev->orig_col,
+ get_token_name(prev->type), get_token_name(get_chunk_parent_type(prev)));
+ log_pcf_flags(LFCN, pc->flags);
+ isa_def = true;
+ }
+ }
+
+ if (chunk_is_ptr_operator(prev))
+ {
+ hit_star = true;
+ }
+
+ if ( chunk_is_not_token(prev, CT_OPERATOR)
+ && chunk_is_not_token(prev, CT_TSQUARE)
+ && chunk_is_not_token(prev, CT_ANGLE_CLOSE)
+ && chunk_is_not_token(prev, CT_QUALIFIER)
+ && chunk_is_not_token(prev, CT_TYPE)
+ && chunk_is_not_token(prev, CT_WORD)
+ && !chunk_is_ptr_operator(prev))
+ {
+ LOG_FMT(LFCN, "%s(%d): --> Stopping on prev is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, prev->text(), prev->orig_line, prev->orig_col, get_token_name(prev->type));
+
+ // certain tokens are unlikely to precede a prototype or definition
+ if ( chunk_is_token(prev, CT_ARITH)
+ || chunk_is_token(prev, CT_SHIFT)
+ || chunk_is_token(prev, CT_ASSIGN)
+ || chunk_is_token(prev, CT_COMMA)
+ || ( chunk_is_token(prev, CT_STRING)
+ && get_chunk_parent_type(prev) != CT_EXTERN) // fixes issue 1259
+ || chunk_is_token(prev, CT_STRING_MULTI)
+ || chunk_is_token(prev, CT_NUMBER)
+ || chunk_is_token(prev, CT_NUMBER_FP)
+ || chunk_is_token(prev, CT_FPAREN_OPEN)) // issue #1464
+ {
+ isa_def = false;
+ }
+ break;
+ }
+
+ // Skip over template and attribute stuff
+ if (chunk_is_token(prev, CT_ANGLE_CLOSE))
+ {
+ prev = skip_template_prev(prev);
+ }
+ else
+ {
+ prev = chunk_get_prev_ncnnlnp(prev);
+ }
+ }
+ //LOG_FMT(LFCN, " -- stopped on %s [%s]\n",
+ // prev->text(), get_token_name(prev->type));
+
+ // Fixes issue #1634
+ if (chunk_is_paren_close(prev))
+ {
+ chunk_t *preproc = chunk_get_next_ncnnl(prev);
+
+ if (chunk_is_token(preproc, CT_PREPROC))
+ {
+ size_t pp_level = preproc->pp_level;
+
+ if (chunk_is_token(chunk_get_next_ncnnl(preproc), CT_PP_ELSE))
+ {
+ do
+ {
+ preproc = chunk_get_prev_ncnnlni(preproc); // Issue #2279
+
+ if (chunk_is_token(preproc, CT_PP_IF))
+ {
+ preproc = chunk_get_prev_ncnnlni(preproc); // Issue #2279
+
+ if (preproc->pp_level == pp_level)
+ {
+ prev = chunk_get_prev_ncnnlnp(preproc);
+ break;
+ }
+ }
+ } while (preproc != nullptr);
+ }
+ }
+ }
+
+ if ( isa_def
+ && prev != nullptr
+ && ( ( chunk_is_paren_close(prev)
+ && get_chunk_parent_type(prev) != CT_D_CAST
+ && get_chunk_parent_type(prev) != CT_MACRO_OPEN // Issue #2726
+ && get_chunk_parent_type(prev) != CT_MACRO_CLOSE)
+ || chunk_is_token(prev, CT_ASSIGN)
+ || chunk_is_token(prev, CT_RETURN)))
+ {
+ LOG_FMT(LFCN, "%s(%d): -- overriding DEF due to prev is '%s', type is %s\n",
+ __func__, __LINE__, prev->text(), get_token_name(prev->type));
+ isa_def = false;
+ }
+
+ // Fixes issue #1266, identification of a tuple return type in CS.
+ if ( !isa_def
+ && chunk_is_token(prev, CT_PAREN_CLOSE)
+ && chunk_get_next_ncnnl(prev) == pc)
+ {
+ tmp = chunk_skip_to_match_rev(prev);
+
+ while ( tmp != nullptr // Issue #2315
+ && tmp != prev)
+ {
+ if ( chunk_is_token(tmp, CT_COMMA)
+ && tmp->level == prev->level + 1)
+ {
+ LOG_FMT(LFCN, "%s(%d): -- overriding call due to tuple return type -- prev is '%s', type is %s\n",
+ __func__, __LINE__, prev->text(), get_token_name(prev->type));
+ isa_def = true;
+ break;
+ }
+ tmp = chunk_get_next_ncnnl(tmp);
+ }
+ }
+
+ if (isa_def)
+ {
+ LOG_FMT(LFCN, "%s(%d): pc is '%s', orig_line is %zu, orig_col is %zu, type is %s\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col, get_token_name(pc->type));
+ LOG_FMT(LFCN, "%s(%d): (12) SET TO CT_FUNC_DEF: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_DEF);
+
+ if (prev == nullptr)
+ {
+ prev = chunk_get_head();
+ }
+
+ for ( tmp = prev; (tmp != nullptr)
+ && tmp != pc; tmp = chunk_get_next_ncnnlnp(tmp))
+ {
+ LOG_FMT(LFCN, "%s(%d): text() is '%s', type is %s\n",
+ __func__, __LINE__, tmp->text(), get_token_name(tmp->type));
+ make_type(tmp);
+ }
+ }
+ }
+
+ if (chunk_is_not_token(pc, CT_FUNC_DEF))
+ {
+ LOG_FMT(LFCN, "%s(%d): Detected type %s, text() is '%s', on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, get_token_name(pc->type),
+ pc->text(), pc->orig_line, pc->orig_col);
+
+ tmp = flag_parens(next, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_FUNC_CALL, false);
+
+ if ( chunk_is_token(tmp, CT_BRACE_OPEN)
+ && get_chunk_parent_type(tmp) != CT_DOUBLE_BRACE)
+ {
+ set_paren_parent(tmp, pc->type);
+ }
+ return;
+ }
+ /*
+ * We have a function definition or prototype
+ * Look for a semicolon or a brace open after the close parenthesis to figure
+ * out whether this is a prototype or definition
+ */
+
+ // See if this is a prototype or implementation
+
+ // FIXME: this doesn't take the old K&R parameter definitions into account
+
+ // Scan tokens until we hit a brace open (def) or semicolon (proto)
+ tmp = paren_close;
+
+ while ((tmp = chunk_get_next_ncnnl(tmp)) != nullptr)
+ {
+ // Only care about brace or semicolon on the same level
+ if (tmp->level < pc->level)
+ {
+ // No semicolon - guess that it is a prototype
+ chunk_flags_clr(pc, PCF_VAR_1ST_DEF);
+ set_chunk_type(pc, CT_FUNC_PROTO);
+ break;
+ }
+ else if (tmp->level == pc->level)
+ {
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ // its a function def for sure
+ break;
+ }
+ else if (chunk_is_semicolon(tmp))
+ {
+ // Set the parent for the semicolon for later
+ semi = tmp;
+ chunk_flags_clr(pc, PCF_VAR_1ST_DEF);
+ set_chunk_type(pc, CT_FUNC_PROTO);
+ LOG_FMT(LFCN, "%s(%d): 2) Marked text() is '%s', as FUNC_PROTO on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ break;
+ }
+ else if (chunk_is_token(pc, CT_COMMA))
+ {
+ set_chunk_type(pc, CT_FUNC_CTOR_VAR);
+ LOG_FMT(LFCN, "%s(%d): 2) Marked text() is '%s', as FUNC_CTOR_VAR on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ break;
+ }
+ }
+ }
+
+ /*
+ * C++ syntax is wacky. We need to check to see if a prototype is really a
+ * variable definition with parameters passed into the constructor.
+ * Unfortunately, without being able to accurately determine if an
+ * identifier is a type (which would require us to more or less be a full
+ * compiler), the only mostly reliable way to do so is to guess that it is
+ * a constructor variable if inside a function body and scan the 'parameter
+ * list' for items that are not allowed in a prototype. We search backwards
+ * and checking the parent of the containing open braces. If the parent is a
+ * class or namespace, then it probably is a prototype.
+ */
+ if ( language_is_set(LANG_CPP)
+ && chunk_is_token(pc, CT_FUNC_PROTO)
+ && get_chunk_parent_type(pc) != CT_OPERATOR)
+ {
+ LOG_FMT(LFPARAM, "%s(%d):", __func__, __LINE__);
+ LOG_FMT(LFPARAM, " checking '%s' for constructor variable %s %s\n",
+ pc->text(),
+ get_token_name(paren_open->type),
+ get_token_name(paren_close->type));
+
+ /*
+ * Check the token at the start of the statement. If it's 'extern', we
+ * definitely have a function prototype.
+ */
+ tmp = pc;
+
+ while ( tmp != nullptr
+ && !tmp->flags.test(PCF_STMT_START))
+ {
+ tmp = chunk_get_prev_ncnnlni(tmp); // Issue #2279
+ }
+ const bool is_extern = ( tmp != nullptr
+ && tmp->str.equals("extern"));
+
+ /*
+ * Scan the parameters looking for:
+ * - constant strings
+ * - numbers
+ * - non-type fields
+ * - function calls
+ */
+ chunk_t *ref = chunk_get_next_ncnnl(paren_open);
+ chunk_t *tmp2;
+ bool is_param = true;
+ tmp = ref;
+
+ while (tmp != paren_close)
+ {
+ tmp2 = chunk_get_next_ncnnl(tmp);
+
+ if ( chunk_is_token(tmp, CT_COMMA)
+ && (tmp->level == (paren_open->level + 1)))
+ {
+ if (!can_be_full_param(ref, tmp))
+ {
+ is_param = false;
+ break;
+ }
+ ref = tmp2;
+ }
+ tmp = tmp2;
+ }
+
+ if ( !is_extern
+ && is_param
+ && ref != tmp)
+ {
+ if (!can_be_full_param(ref, tmp))
+ {
+ is_param = false;
+ }
+ }
+
+ if ( !is_extern
+ && !is_param)
+ {
+ set_chunk_type(pc, CT_FUNC_CTOR_VAR);
+ LOG_FMT(LFCN, "%s(%d): 3) Marked text() '%s' as FUNC_CTOR_VAR on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ }
+ else if (pc->brace_level > 0)
+ {
+ chunk_t *br_open = chunk_get_prev_type(pc, CT_BRACE_OPEN, pc->brace_level - 1);
+
+ if ( br_open != nullptr
+ && get_chunk_parent_type(br_open) != CT_EXTERN
+ && get_chunk_parent_type(br_open) != CT_NAMESPACE)
+ {
+ // Do a check to see if the level is right
+ prev = chunk_get_prev_ncnnlni(pc); // Issue #2279
+
+ if ( !chunk_is_str(prev, "*", 1)
+ && !chunk_is_str(prev, "&", 1))
+ {
+ chunk_t *p_op = chunk_get_prev_type(pc, CT_BRACE_OPEN, pc->brace_level - 1);
+
+ if ( p_op != nullptr
+ && get_chunk_parent_type(p_op) != CT_CLASS
+ && get_chunk_parent_type(p_op) != CT_STRUCT
+ && get_chunk_parent_type(p_op) != CT_NAMESPACE)
+ {
+ set_chunk_type(pc, CT_FUNC_CTOR_VAR);
+ LOG_FMT(LFCN, "%s(%d): 4) Marked text() is'%s', as FUNC_CTOR_VAR on orig_line %zu, orig_col %zu\n",
+ __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col);
+ }
+ }
+ }
+ }
+ }
+
+ if (semi != nullptr)
+ {
+ set_chunk_parent(semi, pc->type);
+ }
+
+ // Issue # 1403, 2152
+ if (chunk_is_token(paren_open->prev, CT_FUNC_CTOR_VAR))
+ {
+ flag_parens(paren_open, PCF_IN_FCN_CTOR, CT_FPAREN_OPEN, pc->type, false);
+ }
+ else
+ {
+ flag_parens(paren_open, PCF_IN_FCN_DEF, CT_FPAREN_OPEN, pc->type, false);
+ }
+ //flag_parens(paren_open, PCF_IN_FCN_DEF, CT_FPAREN_OPEN, pc->type, true);
+
+ if (chunk_is_token(pc, CT_FUNC_CTOR_VAR))
+ {
+ chunk_flags_set(pc, PCF_VAR_1ST_DEF);
+ return;
+ }
+
+ if (chunk_is_token(next, CT_TSQUARE))
+ {
+ next = chunk_get_next_ncnnl(next);
+
+ if (next == nullptr)
+ {
+ return;
+ }
+ }
+ // Mark parameters and return type
+ fix_fcn_def_params(next);
+ mark_function_return_type(pc, chunk_get_prev_ncnnlni(pc), pc->type); // Issue #2279
+
+ /* mark C# where chunk */
+ if ( language_is_set(LANG_CS)
+ && ( (chunk_is_token(pc, CT_FUNC_DEF))
+ || (chunk_is_token(pc, CT_FUNC_PROTO))))
+ {
+ tmp = chunk_get_next_ncnnl(paren_close);
+ pcf_flags_t in_where_spec_flags = PCF_NONE;
+
+ while ( tmp != nullptr
+ && chunk_is_not_token(tmp, CT_BRACE_OPEN)
+ && chunk_is_not_token(tmp, CT_SEMICOLON))
+ {
+ mark_where_chunk(tmp, pc->type, tmp->flags | in_where_spec_flags);
+ in_where_spec_flags = tmp->flags & PCF_IN_WHERE_SPEC;
+
+ tmp = chunk_get_next_ncnnl(tmp);
+ }
+ }
+
+ // Find the brace pair and set the parent
+ if (chunk_is_token(pc, CT_FUNC_DEF))
+ {
+ tmp = chunk_get_next_ncnnl(paren_close);
+
+ while ( tmp != nullptr
+ && chunk_is_not_token(tmp, CT_BRACE_OPEN))
+ {
+ LOG_FMT(LFCN, "%s(%d): (13) SET TO CT_FUNC_DEF: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col, tmp->text());
+ set_chunk_parent(tmp, CT_FUNC_DEF);
+
+ if (!chunk_is_semicolon(tmp))
+ {
+ chunk_flags_set(tmp, PCF_OLD_FCN_PARAMS);
+ }
+ tmp = chunk_get_next_ncnnl(tmp);
+ }
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ LOG_FMT(LFCN, "%s(%d): (14) SET TO CT_FUNC_DEF: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col, tmp->text());
+ set_chunk_parent(tmp, CT_FUNC_DEF);
+ tmp = chunk_skip_to_match(tmp);
+
+ if (tmp != nullptr)
+ {
+ LOG_FMT(LFCN, "%s(%d): (15) SET TO CT_FUNC_DEF: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col, tmp->text());
+ set_chunk_parent(tmp, CT_FUNC_DEF);
+ }
+ }
+ }
+} // mark_function
+
+
+bool mark_function_type(chunk_t *pc)
+{
+ LOG_FUNC_ENTRY();
+ LOG_FMT(LFTYPE, "%s(%d): type is %s, text() '%s' @ orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, get_token_name(pc->type), pc->text(),
+ pc->orig_line, pc->orig_col);
+
+ size_t star_count = 0;
+ size_t word_count = 0;
+ chunk_t *ptrcnk = nullptr;
+ chunk_t *tmp;
+ chunk_t *apo;
+ chunk_t *apc;
+ chunk_t *aft;
+ bool anon = false;
+ c_token_t pt, ptp;
+
+ // Scan backwards across the name, which can only be a word and single star
+ chunk_t *varcnk = chunk_get_prev_ncnnlni(pc); // Issue #2279
+
+ varcnk = chunk_get_prev_ssq(varcnk);
+
+ if ( varcnk != nullptr
+ && !chunk_is_word(varcnk))
+ {
+ if ( language_is_set(LANG_OC)
+ && chunk_is_str(varcnk, "^", 1)
+ && chunk_is_paren_open(chunk_get_prev_ncnnlni(varcnk))) // Issue #2279
+ {
+ // anonymous ObjC block type -- RTYPE (^)(ARGS)
+ anon = true;
+ }
+ else
+ {
+ LOG_FMT(LFTYPE, "%s(%d): not a word: text() '%s', type is %s, @ orig_line is %zu:, orig_col is %zu\n",
+ __func__, __LINE__, varcnk->text(), get_token_name(varcnk->type),
+ varcnk->orig_line, varcnk->orig_col);
+ goto nogo_exit;
+ }
+ }
+ apo = chunk_get_next_ncnnl(pc);
+
+ if (apo == nullptr)
+ {
+ return(false);
+ }
+ apc = chunk_skip_to_match(apo);
+
+ if ( apc != nullptr
+ && ( !chunk_is_paren_open(apo)
+ || ((apc = chunk_skip_to_match(apo)) == nullptr)))
+ {
+ LOG_FMT(LFTYPE, "%s(%d): not followed by parens\n", __func__, __LINE__);
+ goto nogo_exit;
+ }
+ aft = chunk_get_next_ncnnl(apc);
+
+ if (chunk_is_token(aft, CT_BRACE_OPEN))
+ {
+ pt = CT_FUNC_DEF;
+ }
+ else if ( chunk_is_token(aft, CT_SEMICOLON)
+ || chunk_is_token(aft, CT_ASSIGN))
+ {
+ pt = CT_FUNC_PROTO;
+ }
+ else
+ {
+ LOG_FMT(LFTYPE, "%s(%d): not followed by '{' or ';'\n", __func__, __LINE__);
+ goto nogo_exit;
+ }
+ ptp = pc->flags.test(PCF_IN_TYPEDEF) ? CT_FUNC_TYPE : CT_FUNC_VAR;
+
+ tmp = pc;
+
+ while ((tmp = chunk_get_prev_ncnnlni(tmp)) != nullptr) // Issue #2279
+ {
+ tmp = chunk_get_prev_ssq(tmp);
+
+ LOG_FMT(LFTYPE, " -- type is %s, %s on orig_line %zu, orig_col is %zu",
+ get_token_name(tmp->type), tmp->text(),
+ tmp->orig_line, tmp->orig_col);
+
+ if ( chunk_is_star(tmp)
+ || chunk_is_token(tmp, CT_PTR_TYPE)
+ || chunk_is_token(tmp, CT_CARET))
+ {
+ star_count++;
+ ptrcnk = tmp;
+ LOG_FMT(LFTYPE, " -- PTR_TYPE\n");
+ }
+ else if ( chunk_is_word(tmp)
+ || chunk_is_token(tmp, CT_WORD)
+ || chunk_is_token(tmp, CT_TYPE))
+ {
+ word_count++;
+ LOG_FMT(LFTYPE, " -- TYPE(%s)\n", tmp->text());
+ }
+ else if (chunk_is_token(tmp, CT_DC_MEMBER))
+ {
+ word_count = 0;
+ LOG_FMT(LFTYPE, " -- :: reset word_count\n");
+ }
+ else if (chunk_is_str(tmp, "(", 1))
+ {
+ LOG_FMT(LFTYPE, " -- open paren (break)\n");
+ break;
+ }
+ else
+ {
+ LOG_FMT(LFTYPE, " -- unexpected token: type is %s, text() '%s', on orig_line %zu, orig_col %zu\n",
+ get_token_name(tmp->type), tmp->text(),
+ tmp->orig_line, tmp->orig_col);
+ goto nogo_exit;
+ }
+ }
+
+ // Fixes #issue 1577
+ // Allow word count 2 incase of function pointer declaration.
+ // Ex: bool (__stdcall* funcptr)(int, int);
+ if ( star_count > 1
+ || ( word_count > 1
+ && !( word_count == 2
+ && ptp == CT_FUNC_VAR))
+ || ((star_count + word_count) == 0))
+ {
+ LOG_FMT(LFTYPE, "%s(%d): bad counts word: %zu, star: %zu\n",
+ __func__, __LINE__, word_count, star_count);
+ goto nogo_exit;
+ }
+
+ // make sure what appears before the first open paren can be a return type
+ if (!chunk_ends_type(chunk_get_prev_ncnnlni(tmp))) // Issue #2279
+ {
+ goto nogo_exit;
+ }
+
+ if (ptrcnk)
+ {
+ set_chunk_type(ptrcnk, CT_PTR_TYPE);
+ }
+
+ if (!anon)
+ {
+ if (pc->flags.test(PCF_IN_TYPEDEF))
+ {
+ set_chunk_type(varcnk, CT_TYPE);
+ }
+ else
+ {
+ set_chunk_type(varcnk, CT_FUNC_VAR);
+ chunk_flags_set(varcnk, PCF_VAR_1ST_DEF);
+ }
+ }
+ set_chunk_type(pc, CT_TPAREN_CLOSE);
+ set_chunk_parent(pc, ptp);
+
+ set_chunk_type(apo, CT_FPAREN_OPEN);
+ set_chunk_parent(apo, pt);
+ set_chunk_type(apc, CT_FPAREN_CLOSE);
+ set_chunk_parent(apc, pt);
+ fix_fcn_def_params(apo);
+
+ if (chunk_is_semicolon(aft))
+ {
+ set_chunk_parent(aft, aft->flags.test(PCF_IN_TYPEDEF) ? CT_TYPEDEF : CT_FUNC_VAR);
+ }
+ else if (chunk_is_token(aft, CT_BRACE_OPEN))
+ {
+ flag_parens(aft, PCF_NONE, CT_NONE, pt, false);
+ }
+ // Step backwards to the previous open paren and mark everything a
+ tmp = pc;
+
+ while ((tmp = chunk_get_prev_ncnnlni(tmp)) != nullptr) // Issue #2279
+ {
+ LOG_FMT(LFTYPE, " ++ type is %s, text() '%s', on orig_line %zu, orig_col %zu\n",
+ get_token_name(tmp->type), tmp->text(),
+ tmp->orig_line, tmp->orig_col);
+
+ if (*tmp->str.c_str() == '(')
+ {
+ if (!pc->flags.test(PCF_IN_TYPEDEF))
+ {
+ chunk_flags_set(tmp, PCF_VAR_1ST_DEF);
+ }
+ set_chunk_type(tmp, CT_TPAREN_OPEN);
+ set_chunk_parent(tmp, ptp);
+
+ tmp = chunk_get_prev_ncnnlni(tmp); // Issue #2279
+
+ if ( chunk_is_token(tmp, CT_FUNCTION)
+ || chunk_is_token(tmp, CT_FUNC_CALL)
+ || chunk_is_token(tmp, CT_FUNC_CALL_USER)
+ || chunk_is_token(tmp, CT_FUNC_DEF)
+ || chunk_is_token(tmp, CT_FUNC_PROTO))
+ {
+ set_chunk_type(tmp, CT_TYPE);
+ chunk_flags_clr(tmp, PCF_VAR_1ST_DEF);
+ }
+ mark_function_return_type(varcnk, tmp, ptp);
+ break;
+ }
+ }
+ return(true);
+
+nogo_exit:
+ tmp = chunk_get_next_ncnnl(pc);
+
+ if (chunk_is_paren_open(tmp))
+ {
+ LOG_FMT(LFTYPE, "%s(%d): setting FUNC_CALL on orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col);
+ flag_parens(tmp, PCF_NONE, CT_FPAREN_OPEN, CT_FUNC_CALL, false);
+ }
+ return(false);
+} // mark_function_type
+
+
+void mark_lvalue(chunk_t *pc)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *prev;
+
+ if (pc->flags.test(PCF_IN_PREPROC))
+ {
+ return;
+ }
+
+ for (prev = chunk_get_prev_ncnnlni(pc); // Issue #2279
+ prev != nullptr;
+ prev = chunk_get_prev_ncnnlni(prev)) // Issue #2279
+ {
+ if ( prev->level < pc->level
+ || chunk_is_token(prev, CT_ACCESS_COLON)
+ || chunk_is_token(prev, CT_ASSIGN)
+ || chunk_is_token(prev, CT_BOOL)
+ || chunk_is_token(prev, CT_COMMA)
+ || chunk_is_cpp_inheritance_access_specifier(prev)
+ || chunk_is_semicolon(prev)
+ || chunk_is_str(prev, "(", 1)
+ || chunk_is_str(prev, "{", 1)
+ || chunk_is_str(prev, "[", 1)
+ || prev->flags.test(PCF_IN_PREPROC)
+ || get_chunk_parent_type(prev) == CT_NAMESPACE
+ || get_chunk_parent_type(prev) == CT_TEMPLATE)
+ {
+ break;
+ }
+ chunk_flags_set(prev, PCF_LVALUE);
+
+ if ( prev->level == pc->level
+ && chunk_is_str(prev, "&", 1))
+ {
+ make_type(prev);
+ }
+ }
+} // mark_lvalue
+
+
+void mark_struct_union_body(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+ chunk_t *pc = start;
+
+ while ( pc != nullptr
+ && pc->level >= start->level
+ && !( pc->level == start->level
+ && chunk_is_token(pc, CT_BRACE_CLOSE)))
+ {
+ if ( chunk_is_token(pc, CT_BRACE_OPEN)
+ || chunk_is_token(pc, CT_BRACE_CLOSE)
+ || chunk_is_token(pc, CT_SEMICOLON))
+ {
+ pc = chunk_get_next_ncnnl(pc);
+
+ if (pc == nullptr)
+ {
+ break;
+ }
+ }
+
+ if (chunk_is_token(pc, CT_ALIGN))
+ {
+ pc = skip_align(pc); // "align(x)" or "align(x):"
+
+ if (pc == nullptr)
+ {
+ break;
+ }
+ }
+ else if (chunk_is_token(pc, CT_AMP))
+ {
+ pc = skip_expression(pc);
+ }
+ else
+ {
+ pc = fix_variable_definition(pc);
+
+ if (pc == nullptr)
+ {
+ break;
+ }
+ }
+ }
+} // mark_struct_union_body
+
+
+void mark_template_func(chunk_t *pc, chunk_t *pc_next)
+{
+ LOG_FUNC_ENTRY();
+
+ // We know angle_close must be there...
+ chunk_t *angle_close = chunk_get_next_type(pc_next, CT_ANGLE_CLOSE, pc->level);
+ chunk_t *after = chunk_get_next_ncnnl(angle_close);
+
+ if (after != nullptr)
+ {
+ if (chunk_is_str(after, "(", 1))
+ {
+ if (angle_close->flags.test(PCF_IN_FCN_CALL))
+ {
+ LOG_FMT(LTEMPFUNC, "%s(%d): marking '%s' in line %zu as a FUNC_CALL\n",
+ __func__, __LINE__, pc->text(), pc->orig_line);
+ LOG_FMT(LFCN, "%s(%d): (16) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ flag_parens(after, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_FUNC_CALL, false);
+ }
+ else
+ {
+ /*
+ * Might be a function def. Must check what is before the template:
+ * Func call:
+ * BTree.Insert(std::pair<int, double>(*it, double(*it) + 1.0));
+ * a = Test<int>(j);
+ * std::pair<int, double>(*it, double(*it) + 1.0));
+ */
+
+ LOG_FMT(LTEMPFUNC, "%s(%d): marking '%s' in line %zu as a FUNC_CALL 2\n",
+ __func__, __LINE__, pc->text(), pc->orig_line);
+ // its a function!!!
+ LOG_FMT(LFCN, "%s(%d): (17) SET TO CT_FUNC_CALL: orig_line is %zu, orig_col is %zu, text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ mark_function(pc);
+ }
+ }
+ else if (chunk_is_token(after, CT_WORD))
+ {
+ // its a type!
+ set_chunk_type(pc, CT_TYPE);
+ chunk_flags_set(pc, PCF_VAR_TYPE);
+ chunk_flags_set(after, PCF_VAR_DEF);
+ }
+ }
+} // mark_template_func
+
+
+chunk_t *mark_variable_definition(chunk_t *start)
+{
+ LOG_FUNC_ENTRY();
+
+ if (start == nullptr)
+ {
+ return(nullptr);
+ }
+ chunk_t *pc = start;
+ pcf_flags_t flags = PCF_VAR_1ST_DEF;
+
+ LOG_FMT(LVARDEF, "%s(%d): orig_line %zu, orig_col %zu, text() '%s', type is %s\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text(),
+ get_token_name(pc->type));
+
+ // Issue #596
+ bool bit_field_colon_is_present = false;
+
+ while (go_on(pc, start))
+ {
+ if ( chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, CT_FUNC_CTOR_VAR))
+ {
+ auto const orig_flags = pc->flags;
+
+ if (!pc->flags.test(PCF_IN_ENUM))
+ {
+ chunk_flags_set(pc, flags);
+ }
+ flags &= ~PCF_VAR_1ST;
+ LOG_FMT(LVARDEF, "%s(%d): orig_line is %zu, orig_col is %zu, text() '%s', set PCF_VAR_1ST\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->text());
+
+ LOG_FMT(LVARDEF,
+ "%s(%d): orig_line is %zu, marked text() '%s'[%s]\n"
+ " in orig_col %zu, flags: %s -> %s\n",
+ __func__, __LINE__, pc->orig_line, pc->text(),
+ get_token_name(pc->type), pc->orig_col,
+ pcf_flags_str(orig_flags).c_str(),
+ pcf_flags_str(pc->flags).c_str());
+ }
+ else if ( !bit_field_colon_is_present // Issue #2689
+ && ( chunk_is_star(pc)
+ || chunk_is_msref(pc)))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if (chunk_is_addr(pc))
+ {
+ set_chunk_type(pc, CT_BYREF);
+ }
+ else if ( chunk_is_token(pc, CT_SQUARE_OPEN)
+ || chunk_is_token(pc, CT_ASSIGN))
+ {
+ pc = skip_expression(pc);
+ continue;
+ }
+ else if (chunk_is_token(pc, CT_COLON))
+ {
+ bit_field_colon_is_present = true; // Issue #2689
+ }
+ pc = chunk_get_next_ncnnl(pc);
+ }
+ return(pc);
+} // mark_variable_definition
+
+
+void mark_variable_stack(ChunkStack &cs, log_sev_t sev)
+{
+ UNUSED(sev);
+ LOG_FUNC_ENTRY();
+
+ // throw out the last word and mark the rest
+ chunk_t *var_name = cs.Pop_Back();
+
+ if ( var_name != nullptr
+ && var_name->prev != nullptr
+ && var_name->prev->type == CT_DC_MEMBER)
+ {
+ cs.Push_Back(var_name);
+ }
+
+ if (var_name != nullptr)
+ {
+ LOG_FMT(LFCNP, "%s(%d): parameter on orig_line %zu, orig_col %zu:\n",
+ __func__, __LINE__, var_name->orig_line, var_name->orig_col);
+
+ size_t word_cnt = 0;
+ chunk_t *word_type;
+
+ while ((word_type = cs.Pop_Back()) != nullptr)
+ {
+ if ( chunk_is_token(word_type, CT_WORD)
+ || chunk_is_token(word_type, CT_TYPE))
+ {
+ LOG_FMT(LFCNP, "%s(%d): parameter on orig_line %zu, orig_col %zu: <%s> as TYPE\n",
+ __func__, __LINE__, var_name->orig_line, var_name->orig_col, word_type->text());
+ set_chunk_type(word_type, CT_TYPE);
+ chunk_flags_set(word_type, PCF_VAR_TYPE);
+ }
+ word_cnt++;
+ }
+
+ if (chunk_is_token(var_name, CT_WORD))
+ {
+ if (word_cnt > 0)
+ {
+ LOG_FMT(LFCNP, "%s(%d): parameter on orig_line %zu, orig_col %zu: <%s> as VAR\n",
+ __func__, __LINE__, var_name->orig_line, var_name->orig_col, var_name->text());
+ chunk_flags_set(var_name, PCF_VAR_DEF);
+ }
+ else
+ {
+ LOG_FMT(LFCNP, "%s(%d): parameter on orig_line %zu, orig_col %zu: <%s> as TYPE\n",
+ __func__, __LINE__, var_name->orig_line, var_name->orig_col, var_name->text());
+ set_chunk_type(var_name, CT_TYPE);
+ chunk_flags_set(var_name, PCF_VAR_TYPE);
+ }
+ }
+ }
+} // mark_variable_stack
+
+
+pcf_flags_t mark_where_chunk(chunk_t *pc, c_token_t parent_type, pcf_flags_t flags)
+{
+ /* TODO: should have options to control spacing around the ':' as well as newline ability for the
+ * constraint clauses (should it break up a 'where A : B where C : D' on the same line? wrap? etc.) */
+
+ if (chunk_is_token(pc, CT_WHERE))
+ {
+ set_chunk_type(pc, CT_WHERE_SPEC);
+ set_chunk_parent(pc, parent_type);
+ flags |= PCF_IN_WHERE_SPEC;
+ LOG_FMT(LFTOR, "%s: where-spec on line %zu\n",
+ __func__, pc->orig_line);
+ }
+ else if (flags.test(PCF_IN_WHERE_SPEC))
+ {
+ if (chunk_is_str(pc, ":", 1))
+ {
+ set_chunk_type(pc, CT_WHERE_COLON);
+ LOG_FMT(LFTOR, "%s: where-spec colon on line %zu\n",
+ __func__, pc->orig_line);
+ }
+ else if ( (chunk_is_token(pc, CT_STRUCT))
+ || (chunk_is_token(pc, CT_CLASS)))
+ {
+ /* class/struct inside of a where-clause confuses parser for indentation; set it as a word so it looks like the rest */
+ set_chunk_type(pc, CT_WORD);
+ }
+ }
+
+ if (flags.test(PCF_IN_WHERE_SPEC))
+ {
+ chunk_flags_set(pc, PCF_IN_WHERE_SPEC);
+ }
+ return(flags);
+} // mark_where_chunk