diff options
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.73.0/src/EnumStructUnionParser.cpp')
-rw-r--r-- | debian/uncrustify-trinity/uncrustify-trinity-0.73.0/src/EnumStructUnionParser.cpp | 2858 |
1 files changed, 0 insertions, 2858 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/src/EnumStructUnionParser.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/src/EnumStructUnionParser.cpp deleted file mode 100644 index 48e1911d..00000000 --- a/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/src/EnumStructUnionParser.cpp +++ /dev/null @@ -1,2858 +0,0 @@ -/** - * @file EnumStructUnionParser.cpp - * - * @author - * @license GPL v2+ - */ - -#include "EnumStructUnionParser.h" - -#include "combine_fix_mark.h" -#include "combine_skip.h" -#include "combine_tools.h" -#include "flag_parens.h" -#include "lang_pawn.h" - - -/** - * Extern declarations - */ -extern const char *get_token_name(c_token_t); -extern void log_pcf_flags(log_sev_t, pcf_flags_t); - - -/** - * Forward declarations - */ -static std::pair<chunk_t *, chunk_t *> match_variable_end(chunk_t *, std::size_t); -static std::pair<chunk_t *, chunk_t *> match_variable_start(chunk_t *, std::size_t); -static chunk_t *skip_scope_resolution_and_nested_name_specifiers(chunk_t *); -static chunk_t *skip_scope_resolution_and_nested_name_specifiers_rev(chunk_t *); - - -/** - * Returns true if two adjacent chunks potentially match a pattern consistent - * with that of a qualified identifier - */ -static bool adj_tokens_match_qualified_identifier_pattern(chunk_t *prev, chunk_t *next) -{ - LOG_FUNC_ENTRY(); - - if ( prev != nullptr - && next != nullptr) - { - auto prev_token_type = prev->type; - auto next_token_type = next->type; - - switch (prev_token_type) - { - case CT_ANGLE_CLOSE: - /** - * assuming the previous token is possibly the closing angle of a - * templated type, the next token may be a scope resolution operator ("::") - */ - return(next_token_type == CT_DC_MEMBER); - - case CT_ANGLE_OPEN: - /** - * assuming the previous token is possibly the opening angle of a - * templated type, just check to see if there's a matching closing - * angle - */ - return(chunk_skip_to_match(prev, scope_e::PREPROC) != nullptr); - - case CT_DC_MEMBER: - /** - * if the previous token is a double colon ("::"), it is likely part - * of a chain of scope-resolution qualifications preceding a word or - * type - */ - return( next_token_type == CT_TYPE - || next_token_type == CT_WORD); - - case CT_TYPE: - case CT_WORD: - /** - * if the previous token is an identifier, the next token may be - * one of the following: - * - an opening angle, which may indicate a templated type as part of a - * scope resolution preceding the actual variable identifier - * - a double colon ("::") - */ - return( next_token_type == CT_ANGLE_OPEN - || next_token_type == CT_DC_MEMBER); - - default: - // do nothing - break; - } // switch - } - return(false); -} // adj_tokens_match_qualified_identifier_pattern - - -/** - * Returns true if two adjacent chunks potentially match a pattern consistent - * with that of a variable definition - */ -static bool adj_tokens_match_var_def_pattern(chunk_t *prev, chunk_t *next) -{ - LOG_FUNC_ENTRY(); - - if ( prev != nullptr - && next != nullptr) - { - auto prev_token_type = prev->type; - auto next_token_type = next->type; - - switch (prev_token_type) - { - case CT_ANGLE_CLOSE: - /** - * assuming the previous token is possibly the closing angle of a - * templated type, the next token may be one of the following: - * - a pointer symbol ('*', '^') - * - a double colon ("::") - * - a reference symbol ('&') - * - a qualifier (const, etc.) - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_DC_MEMBER - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD); - - - case CT_ANGLE_OPEN: - /** - * assuming the previous token is possibly the opening angle of a - * templated type, just check to see if there's a matching closing - * angle - */ - return(chunk_skip_to_match(prev, scope_e::PREPROC) != nullptr); - - case CT_BRACE_CLOSE: - /** - * assuming the previous token is possibly the closing brace of a - * class/enum/struct/union definition, one or more inline variable - * definitions may follow; in that case, the next token may be one of - * the following: - * - a pointer symbol ('*', '^') - * - a reference symbol ('&') - * - a qualifier (const, etc.) - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD); - - case CT_BRACE_OPEN: - /** - * if the previous token is an opening brace, it may indicate the - * start of a braced initializer list - skip ahead to find a matching - * closing brace - */ - return(chunk_skip_to_match(prev, scope_e::PREPROC) != nullptr); - - case CT_BYREF: - /** - * if the previous token is a reference symbol ('&'), the next token - * may be an identifier - */ - return(next_token_type == CT_WORD); - - case CT_CARET: - /** - * if the previous token is a managed C++/CLI pointer symbol ('^'), - * the next token may be one of the following: - * - a pointer symbol ('*', '^') - * - a reference symbol ('&') - * - a qualifier (const, etc.) - * - an identifier - */ - return( language_is_set(LANG_CPP) - && ( chunk_is_pointer_or_reference(next) - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD)); - - case CT_COMMA: - /** - * if the previous token is a comma, this may indicate a variable - * declaration trailing a prior declaration; in that case, the next - * token may be one of the following: - * - a pointer symbol ('*', '^') - * - a reference symbol ('&') - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_WORD); - - case CT_DC_MEMBER: - /** - * if the previous token is a double colon ("::"), it is likely part - * of a chain of scope-resolution qualifications preceding a word or - * type - */ - return( next_token_type == CT_TYPE - || next_token_type == CT_WORD); - - case CT_PAREN_OPEN: - /** - * if the previous token is an opening paren, it may indicate the - * start of a constructor call parameter list - skip ahead to find a - * matching closing paren - */ - next = chunk_skip_to_match(prev, scope_e::PREPROC); - - if (next != nullptr) - { - next_token_type = next->type; - } - return(next_token_type == CT_PAREN_CLOSE); - - case CT_PTR_TYPE: - /** - * if the previous token is a pointer type, ('*', '^'), the next token - * may be one of the following: - * - another pointer symbol ('*', '^') - * - a reference symbol ('&') - * - a qualifier (const, etc.) - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD); - - case CT_QUALIFIER: - /** - * if the previous token is a qualifier (const, etc.), the next token - * may be one of the following: - * - a pointer symbol ('*', '^') - * - a reference symbol ('&') - * - another qualifier - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD); - - case CT_SQUARE_CLOSE: - /** - * if the previous token is a closing bracket, the next token may be - * an assignment following an array variable declaration - */ - return(next_token_type == CT_ASSIGN); - - case CT_SQUARE_OPEN: - /** - * if the previous token is an opening bracket, it may indicate an - * array declaration - skip ahead to find a matching closing bracket - */ - return(chunk_skip_to_match(prev, scope_e::PREPROC) != nullptr); - - case CT_STAR: - /** - * if the previous token is a pointer symbol, ('*'), the next token - * may be one of the following: - * - another pointer symbol ('*', '^') - * - a reference symbol ('&') - * - a qualifier (const, etc.) - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD); - - case CT_TSQUARE: - /** - * if the previous token is a set of brackets, the next token may be - * an assignment following an array variable declaration - */ - return(next_token_type == CT_ASSIGN); - - case CT_TYPE: - /** - * if the previous token is marked as a type, the next token may be - * one of the following: - * - a pointer symbol ('*', '^') - * - a reference symbol ('&') - * - an opening angle, which may indicate a templated type as part of a - * scope resolution preceding the actual variable identifier - * - a double colon ("::") - * - a qualifier (const, etc.) - * - an identifier - */ - return( chunk_is_pointer_or_reference(next) - || next_token_type == CT_ANGLE_OPEN - || next_token_type == CT_DC_MEMBER - || next_token_type == CT_QUALIFIER - || next_token_type == CT_WORD); - - case CT_WORD: - /** - * if the previous token is an identifier, the next token may be one - * of the following: - * - an assignment symbol ('=') - * - an opening angle, which may indicate a templated type as part of a - * scope resolution preceding the actual variable identifier - * - an opening brace, which may indicate a braced-initializer list - * - a double colon ("::") - * - an opening paren, which may indicate a constructor call parameter - * list - * - an opening square bracket, which may indicate an array variable - * - an set of empty square brackets, which also may indicate an array - * variable - */ - return( next_token_type == CT_ANGLE_OPEN - || next_token_type == CT_ASSIGN - || next_token_type == CT_BRACE_OPEN - || next_token_type == CT_DC_MEMBER - || next_token_type == CT_PAREN_OPEN - || next_token_type == CT_SQUARE_OPEN - || next_token_type == CT_TSQUARE); - - default: - // do nothing - break; - } // switch - } - return(false); -} // adj_tokens_match_var_def_pattern - - -/** - * Returns true if the first chunk occurs AFTER the second chunk in the argument - * list - * @param pc points to the first chunk - * @param after points to the second chunk - * @param test_equal if true, returns true when both chunks refer to the same chunk - */ -static bool chunk_is_after(chunk_t *pc, chunk_t *after, bool test_equal = true) -{ - LOG_FUNC_ENTRY(); - - if (pc != nullptr) - { - if ( test_equal - && pc == after) - { - return(true); - } - else if (after != nullptr) - { - auto pc_column = pc->orig_col; - auto pc_line = pc->orig_line; - auto after_column = after->orig_col; - auto after_line = after->orig_line; - - return( pc_line > after_line - || ( pc_line == after_line - && pc_column > after_column)); - } - } - return(false); -} // chunk_is_after - - -/** - * Returns true if the first chunk occurs BEFORE the second chunk in the argument - * list - * @param pc points to the first chunk - * @param before points to the second chunk - * @param test_equal if true, returns true when both chunks refer to the same chunk - */ -static bool chunk_is_before(chunk_t *pc, chunk_t *before, bool test_equal = true) -{ - LOG_FUNC_ENTRY(); - - if (pc != nullptr) - { - if ( test_equal - && pc == before) - { - return(true); - } - else if (before != nullptr) - { - auto pc_column = pc->orig_col; - auto pc_line = pc->orig_line; - auto before_column = before->orig_col; - auto before_line = before->orig_line; - - return( pc_line < before_line - || ( pc_line == before_line - && pc_column < before_column)); - } - } - return(false); -} // chunk_is_before - - -/** - * Returns true if the first chunk occurs both AFTER and BEFORE - * the second and third chunks, respectively, in the argument list - * @param pc points to the first chunk - * @param after points to the second chunk - * @param before points to the third chunk - * @param test_equal if true, returns true when the first chunk tests equal to - * either the second or third chunk - */ -static bool chunk_is_between(chunk_t *pc, chunk_t *after, chunk_t *before, bool test_equal = true) -{ - LOG_FUNC_ENTRY(); - - return( chunk_is_before(pc, before, test_equal) - && chunk_is_after(pc, after, test_equal)); -} // chunk_is_between - - -/** - * Returns true if the chunk under test is a reference to a macro defined elsewhere in - * the source file currently being processed. Note that a macro may be defined in - * another source or header file, for which this function does not currently account - */ -static bool chunk_is_macro_reference(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - auto *next = chunk_get_head(); - - if ( ( language_is_set(LANG_CPP) - || language_is_set(LANG_C)) - && chunk_is_token(pc, CT_WORD) - && !pc->flags.test(PCF_IN_PREPROC)) - { - while (next != nullptr) - { - if ( next->flags.test(PCF_IN_PREPROC) - && std::strcmp(pc->str.c_str(), next->str.c_str()) == 0) - { - return(true); - } - next = chunk_search_next_cat(next, CT_MACRO); - } - } - return(false); -} // chunk_is_macro_reference - - -/** - * Returns true if the input chunk is a pointer/reference operator or a - * qualifier - */ -static bool chunk_is_pointer_reference_or_qualifier(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - return( chunk_is_pointer_or_reference(pc) - || ( chunk_is_token(pc, CT_QUALIFIER) - && !chunk_is_cpp_inheritance_access_specifier(pc))); -} // chunk_is_pointer_reference_or_qualifier - - -/** - * This function attempts to match the starting and ending chunks of a qualified - * identifier, which consists of one or more scope resolution operator(s) and - * zero or more nested name specifiers - * specifiers - * @param pc the starting chunk - * @return an std::pair, where the first chunk indicates the starting chunk of the - * match and second indicates the ending chunk. Upon finding a successful - * match, the starting chunk may consist of an identifier or a scope - * resolution operator, while the ending chunk may consist of identifier - * or the closing angle bracket of a template. If no match is found, a - * pair of null chunks is returned - */ -static std::pair<chunk_t *, chunk_t *> match_qualified_identifier(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - auto *end = skip_scope_resolution_and_nested_name_specifiers(pc); - auto *start = skip_scope_resolution_and_nested_name_specifiers_rev(pc); - - if ( end != nullptr - && start != nullptr) - { - auto *double_colon = chunk_search_next_cat(start, CT_DC_MEMBER); - - if ( double_colon != nullptr - && chunk_is_between(double_colon, start, end)) - { - return(std::make_pair(start, end)); - } - } - return(std::make_pair(nullptr, nullptr)); -} // match_qualified_identifier - - -/** - * Starting from the input chunk, this function attempts to match a variable - * declaration/definition in both the forward and reverse directions; each pair of - * consecutive chunks is tested to determine if a potential match is satisfied. - * @param pc the starting chunk - * @param level the brace level - * @return upon successful match, function returns an std::tuple, where the - * first chunk indicates the starting chunk, the second chunk indicates - * the identifier name, and the third chunk indicates the end associated - * with the variable declaration/definition - */ -static std::tuple<chunk_t *, chunk_t *, chunk_t *> match_variable(chunk_t *pc, std::size_t level) -{ - LOG_FUNC_ENTRY(); - - auto identifier_end_pair = match_variable_end(pc, level); - auto start_identifier_pair = match_variable_start(pc, level); - auto *end = identifier_end_pair.second; - auto *identifier = identifier_end_pair.first != nullptr ? identifier_end_pair.first : start_identifier_pair.second; - auto *start = start_identifier_pair.first; - - /** - * a forward search starting at the chunk under test will fail if two consecutive chunks marked as CT_WORD - * are encountered; in that case, it's likely that the preceding chunk indicates a type and the subsequent - * chunk indicates a variable declaration/definition - */ - - if ( identifier != nullptr - && start != nullptr - && ( end != nullptr - || chunk_is_token(chunk_get_prev_ncnnlni(identifier), CT_WORD))) - { - return(std::make_tuple(start, identifier, end)); - } - return(std::make_tuple(nullptr, nullptr, nullptr)); -} // match_variable - - -/** - * Starting from the input chunk, this function attempts to match a variable in the - * forward direction, and tests each pair of consecutive chunks to determine if a - * potential variable declaration/definition match is satisfied. Secondly, the - * function attempts to identify the end chunk associated with the candidate variable - * match. For scalar variables (simply declared and not defined), both the end chunk - * and identifier chunk should be one in the same - * @param pc the starting chunk - * @param level the brace level - * @return an std::pair, where the first chunk indicates the identifier - * (if non-null) and the second chunk indicates the end associated with - * the variable declaration/definition; assuming a valid match, the first - * chunk may be null if the function is called with a starting chunk - * that occurs after the identifier - */ -static std::pair<chunk_t *, chunk_t *> match_variable_end(chunk_t *pc, std::size_t level) -{ - LOG_FUNC_ENTRY(); - - chunk_t *identifier = nullptr; - - while (pc != nullptr) - { - /** - * skip any right-hand side assignments - */ - chunk_t *rhs_exp_end = nullptr; - - if (chunk_is_token(pc, CT_ASSIGN)) - { - /** - * store a pointer to the end chunk of the rhs expression; - * use it later to test against setting the identifier - */ - rhs_exp_end = skip_to_expression_end(pc); - pc = rhs_exp_end; - } - - /** - * skip current and preceding chunks if at a higher brace level - */ - while ( pc != nullptr - && pc->level > level) - { - pc = chunk_get_next_ncnnl(pc); - } - - /** - * skip to any following match for angle brackets, braces, parens, - * or square brackets - */ - if ( chunk_is_token(pc, CT_ANGLE_OPEN) - || chunk_is_token(pc, CT_BRACE_OPEN) - || chunk_is_paren_open(pc) - || chunk_is_token(pc, CT_SQUARE_OPEN)) - { - pc = chunk_skip_to_match(pc, scope_e::PREPROC); - } - /** - * call a separate function to validate adjacent tokens as potentially - * matching a variable declaration/definition - */ - - chunk_t *next = chunk_get_next_ncnnl(pc); - - if ( chunk_is_not_token(next, CT_COMMA) - && chunk_is_not_token(next, CT_FPAREN_CLOSE) - && !chunk_is_semicolon(next) - && !adj_tokens_match_var_def_pattern(pc, next)) - { - /** - * error, pattern is not consistent with a variable declaration/definition - */ - - break; - } - - if ( chunk_is_token(pc, CT_WORD) - && pc != rhs_exp_end) - { - /** - * we've encountered a candidate for the variable name - */ - - identifier = pc; - } - - /** - * we're done searching if we've previously identified a variable name - * and then encounter a comma or semicolon - */ - if ( chunk_is_token(next, CT_COMMA) - || chunk_is_token(next, CT_FPAREN_CLOSE) - || chunk_is_semicolon(next)) - { - return(std::make_pair(identifier, pc)); - } - pc = next; - } - return(std::make_pair(nullptr, nullptr)); -} // match_variable_end - - -/** - * Starting from the input chunk, this function attempts to match a variable in the - * reverse direction, and tests each pair of consecutive chunks to determine if a - * potential variable declaration/definition match is satisfied. Secondly, the - * function attempts to identify the starting chunk associated with the candidate - * variable match. The start and identifier chunks may refer to each other in cases - * where the identifier is not preceded by pointer or reference operators or qualifiers, - * etc. - * @param pc the starting chunk - * @param level the brace level - * @return an std::pair, where the first chunk indicates the starting chunk and - * the second chunk indicates the identifier associated with the variable - * match; assuming a valid match, the second chunk may be null if the - * function is called with a starting chunk that occurs before the - * identifier - */ -static std::pair<chunk_t *, chunk_t *> match_variable_start(chunk_t *pc, std::size_t level) -{ - LOG_FUNC_ENTRY(); - - chunk_t *identifier = nullptr; - - while (pc != nullptr) - { - /** - * skip any right-hand side assignments - */ - chunk_t *before_rhs_exp_start = skip_expression_rev(pc); - chunk_t *prev = nullptr; - chunk_t *next = pc; - - while ( chunk_is_after(next, before_rhs_exp_start) - && pc != prev) - { - next = prev; - prev = chunk_get_prev_ncnnlni(next); - - if (chunk_is_token(next, CT_ASSIGN)) - { - pc = prev; - } - } - /** - * skip current and preceding chunks if at a higher brace level - */ - - while ( pc != nullptr - && pc->level > level) - { - pc = chunk_get_prev_ncnnlni(pc); - } - - /** - * skip to any preceding match for angle brackets, braces, parens, - * or square brackets - */ - if ( chunk_is_token(pc, CT_ANGLE_CLOSE) - || chunk_is_token(pc, CT_BRACE_CLOSE) - || chunk_is_paren_close(pc) - || chunk_is_token(pc, CT_SQUARE_CLOSE)) - { - pc = chunk_skip_to_match_rev(pc, scope_e::PREPROC); - } - /** - * call a separate function to validate adjacent tokens as potentially - * matching a variable declaration/definition - */ - - prev = chunk_get_prev_ncnnlni(pc); - - if (!adj_tokens_match_var_def_pattern(prev, pc)) - { - /** - * perhaps the previous chunk possibly indicates a type that yet to be - * marked? if not, then break - */ - if ( chunk_is_not_token(prev, CT_WORD) - || ( !chunk_is_pointer_or_reference(pc) - && chunk_is_not_token(pc, CT_WORD))) - { - /** - * error, pattern is not consistent with a variable declaration/definition - */ - - break; - } - } - - if ( identifier == nullptr - && chunk_is_token(pc, CT_WORD)) - { - /** - * we've encountered a candidate for the variable name - */ - - identifier = pc; - } - - /** - * we're done searching if we've previously identified a variable name - * and then encounter another identifier, or we encounter a closing - * brace (which would likely indicate an inline variable definition) - */ - if ( chunk_is_token(prev, CT_ANGLE_CLOSE) - || chunk_is_token(prev, CT_BRACE_CLOSE) - || chunk_is_token(prev, CT_COMMA) - || chunk_is_token(prev, CT_TYPE) - || chunk_is_token(prev, CT_WORD)) - { - return(std::make_pair(pc, identifier)); - } - pc = prev; - } - return(std::make_pair(nullptr, nullptr)); -} // match_variable_start - - -/** - * Skip forward past any scope resolution operators and nested name specifiers and return - * just the qualified identifier name; while similar to the existing skip_dc_member() - * function, this function also takes into account templates that may comprise any - * nested name specifiers - */ -static chunk_t *skip_scope_resolution_and_nested_name_specifiers(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - if ( ( pc != nullptr - && pc->flags.test(PCF_IN_TEMPLATE)) - || chunk_is_token(pc, CT_DC_MEMBER) - || chunk_is_token(pc, CT_TYPE) - || chunk_is_token(pc, CT_WORD)) - { - while (pc != nullptr) - { - /** - * skip to any following match for angle brackets - */ - if (chunk_is_token(pc, CT_ANGLE_OPEN)) - { - pc = chunk_skip_to_match(pc, scope_e::PREPROC); - } - auto *next = chunk_get_next_ncnnl(pc); - - /** - * call a separate function to validate adjacent tokens as potentially - * matching a qualified identifier - */ - if (!adj_tokens_match_qualified_identifier_pattern(pc, next)) - { - break; - } - pc = next; - } - } - return(pc); -} // skip_scope_resolution_and_nested_name_specifiers - - -/** - * Skip in reverse to the beginning chunk of a qualified identifier; while similar to - * the existing skip_dc_member_rev() function, this function also takes into account - * templates that may comprise any nested name specifiers - */ -static chunk_t *skip_scope_resolution_and_nested_name_specifiers_rev(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - if ( ( pc != nullptr - && pc->flags.test(PCF_IN_TEMPLATE)) - || chunk_is_token(pc, CT_DC_MEMBER) - || chunk_is_token(pc, CT_TYPE) - || chunk_is_token(pc, CT_WORD)) - { - while (pc != nullptr) - { - /** - * skip to any preceding match for angle brackets - */ - if (chunk_is_token(pc, CT_ANGLE_CLOSE)) - { - pc = chunk_skip_to_match_rev(pc, scope_e::PREPROC); - } - auto *prev = chunk_get_prev_ncnnlni(pc); - - /** - * call a separate function to validate adjacent tokens as potentially - * matching a qualified identifier - */ - if (!adj_tokens_match_qualified_identifier_pattern(prev, pc)) - { - break; - } - pc = prev; - } - } - return(pc); -} // skip_scope_resolution_and_nested_name_specifiers_rev - - -EnumStructUnionParser::EnumStructUnionParser() - : m_end(nullptr) - , m_parse_error(false) - , m_start(nullptr) - , m_type(nullptr) -{ -} // EnumStructUnionParser::EnumStructUnionParser - - -EnumStructUnionParser::~EnumStructUnionParser() -{ -} // EnumStructUnionParser::~EnumStructUnionParser - - -void EnumStructUnionParser::analyze_identifiers() -{ - LOG_FUNC_ENTRY(); - - /** - * the enum (and variable declarations thereof) could be of - * the following forms: - * - * "enum type [: integral_type] { ... } [x, ...]" - * "enum type : integral_type" - * "enum type x, ..." - * "enum class type [: integral_type] { ... } [x, ...]" - * "enum class type [: integral_type]" - * "enum [: integral_type] { ... } x, ..." - */ - - /** - * the class/struct (and variable declarations thereof) could be of - * the following forms: - * - * "template<...> class/struct[<...>] [macros/attributes ...] type [: bases ...] { }" - * "template<...> class/struct[<...>] [macros/attributes ...] type" - * "class/struct [macros/attributes ...] type [: bases ...] { } [x, ...]" - * "class/struct [macros/attributes ...] type [x, ...]" - * "class/struct [macros/attributes ...] [: bases] { } x, ..." - */ - - chunk_t *template_end = get_template_end(); - auto *body_end = get_body_end(); - auto *body_start = get_body_start(); - pcf_flags_t flags = PCF_VAR_1ST_DEF; - auto *inheritance_start = get_inheritance_start(); - chunk_t *pc = body_end ? body_end : m_start; - - /** - * first, try a simple approach to identify any associated type - */ - if (try_pre_identify_type()) - { - /** - * a type was identified, meaning a pair of braces, angle brackets, or - * a colon was found; if a colon was found, then there should be a - * balanced set of braces that follow; therefore, start the search for - * variable identifiers after the closing brace or close angle bracket - */ - - if (body_end != nullptr) - { - pc = body_end; - } - else if (template_end != nullptr) - { - pc = template_end; - } - } - - if (chunk_get_next_ncnnl(pc) == m_end) - { - /** - * we're likely at the end of a class/enum/struct/union body which lacks - * any trailing inline definitions - */ - - pc = chunk_get_next_ncnnl(m_end); - } - - if ( type_identified() - || chunk_is_class_enum_struct_union(pc) - || pc == m_end) - { - /** - * in case we're pointing at the end chunk, advance the chunk pointer - * by one more so that we don't perform a variable identifier search - * below - */ - pc = chunk_get_next_ncnnl(pc); - } - - if (body_end != nullptr) - { - /** - * a closing brace was found, so any identifiers trailing the closing - * brace are probably inline variable declarations following a - * class/enum/struct/union definition - */ - flags |= PCF_VAR_INLINE; - } - else if (!type_identified()) - { - /** - * skip any chain of one or more function-like macro calls, - * declspecs, and attributes - */ - - chunk_t *tmp = pc; - - do - { - pc = tmp; - tmp = skip_attribute_next(tmp); - tmp = skip_declspec_next(tmp); - } while (tmp != pc); - } - /** - * try to match some variable identifiers in the loop below - */ - - while (chunk_is_between(pc, m_start, m_end, false)) - { - auto match = match_variable(pc, m_start->level); - auto *start = std::get<0>(match); - auto *identifier = std::get<1>(match); - auto *end = std::get<2>(match); - - if ( start != nullptr - && identifier != nullptr) - { - if (end != nullptr) - { - mark_variable(identifier, flags); - - if (flags & PCF_VAR_1ST) - { - flags &= ~PCF_VAR_1ST; // clear the first flag for the next items - } - } - } - - if (end != nullptr) - { - pc = end; - } - pc = chunk_get_next_ncnnl(pc); - - /** - * skip any right-hand side assignments - */ - if (chunk_is_token(pc, CT_ASSIGN)) - { - pc = skip_to_expression_end(pc); - } - - /** - * if we're sitting at a comma or semicolon, skip it - */ - if ( chunk_is_semicolon(pc) - || ( chunk_is_token(pc, CT_COMMA) - && !pc->flags.test_any(PCF_IN_FCN_DEF | PCF_IN_FCN_CALL | PCF_IN_TEMPLATE) - && !chunk_is_between(pc, inheritance_start, body_start))) - { - pc = chunk_get_next_ncnnl(pc); - } - } - /** - * if we still haven't identified a type, try doing so now that the - * variables, if any, have been marked - */ - try_post_identify_type(); - - /** - * identify possible macros preceding the type name - */ - try_post_identify_macro_calls(); - - if ( chunk_is_class_or_struct(m_start) - && ( chunk_is_not_token(m_start, CT_STRUCT) - || !language_is_set(LANG_C))) - { - /** - * if a type has been identifies, mark any constructor matching constructor - * declarations/definitions - */ - mark_constructors(); - } - - if (type_identified()) - { - if (~flags & PCF_VAR_1ST) - { - /** - * PCF_VAR_1ST was cleared and a type was identified; therefore, set - * PCF_VAR_TYPE for the identified type - */ - chunk_flags_set(m_type, PCF_VAR_TYPE); - } - else if (~flags & PCF_VAR_INLINE) - { - /** - * if a type was identified but no braced-enclosed body was found and no - * identifiers were marked as variables, then we're likely we're likely - * dealing with a forward declaration - */ - flag_series(m_start, m_type, PCF_INCOMPLETE); - } - } -} // EnumStructUnionParser::analyze_identifiers - - -bool EnumStructUnionParser::body_detected() const -{ - LOG_FUNC_ENTRY(); - - auto *body_end = get_body_end(); - auto *body_start = get_body_start(); - - return( body_end != nullptr - && body_start != nullptr); -} // EnumStructUnionParser::body_detected - - -bool EnumStructUnionParser::comma_separated_values_detected() const -{ - LOG_FUNC_ENTRY(); - - return(!get_top_level_commas().empty()); -} // EnumStructUnionParser::comma_separated_values_detected - - -bool EnumStructUnionParser::enum_base_detected() const -{ - LOG_FUNC_ENTRY(); - - return(m_chunk_map.find(CT_BIT_COLON) != m_chunk_map.cend()); -} // EnumStructUnionParser::enum_base_detected - - -chunk_t *EnumStructUnionParser::get_body_end() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_BRACE_CLOSE); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_body_end - - -chunk_t *EnumStructUnionParser::get_body_start() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_BRACE_OPEN); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_body_start - - -chunk_t *EnumStructUnionParser::get_enum_base_start() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_BIT_COLON); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_enum_base_start - - -chunk_t *EnumStructUnionParser::get_first_top_level_comma() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_COMMA); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_first_top_level_comma - - -chunk_t *EnumStructUnionParser::get_inheritance_end() const -{ - LOG_FUNC_ENTRY(); - - chunk_t *brace_open = nullptr; - auto *inheritance_start = get_inheritance_start(); - - if (inheritance_start != nullptr) - { - brace_open = get_body_start(); - - if (brace_open == nullptr) - { - brace_open = chunk_get_next_type(inheritance_start, - CT_BRACE_OPEN, - m_start->level, - scope_e::ALL); - } - } - return(brace_open); -} // EnumStructUnionParser::get_inheritance_end - - -chunk_t *EnumStructUnionParser::get_inheritance_start() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_COLON); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_inheritance_start - - -std::map<std::size_t, chunk_t *> EnumStructUnionParser::get_question_operators() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_QUESTION); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second); - } - return(std::map<std::size_t, chunk_t *>()); -} // EnumStructUnionParser::get_question_operators - - -chunk_t *EnumStructUnionParser::get_template_end() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_ANGLE_CLOSE); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_template_end - - -chunk_t *EnumStructUnionParser::get_template_start() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_ANGLE_OPEN); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_template_start - - -std::map<std::size_t, chunk_t *> EnumStructUnionParser::get_top_level_commas() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_COMMA); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second); - } - return(std::map<std::size_t, chunk_t *>()); -} // EnumStructUnionParser::get_top_level_commas - - -chunk_t *EnumStructUnionParser::get_where_end() const -{ - LOG_FUNC_ENTRY(); - - chunk_t *brace_open = nullptr; - auto *where_start = get_where_start(); - - if (where_start != nullptr) - { - brace_open = get_body_start(); - - if (brace_open == nullptr) - { - brace_open = chunk_get_next_type(where_start, - CT_BRACE_OPEN, - m_start->level, - scope_e::ALL); - } - } - return(brace_open); -} // EnumStructUnionParser::get_where_end - - -chunk_t *EnumStructUnionParser::get_where_start() const -{ - LOG_FUNC_ENTRY(); - - auto &&it_token_chunk_map_pair = m_chunk_map.find(CT_WHERE); - - if (it_token_chunk_map_pair != m_chunk_map.cend()) - { - return(it_token_chunk_map_pair->second.at(0)); - } - return(nullptr); -} // EnumStructUnionParser::get_where_start - - -bool EnumStructUnionParser::inheritance_detected() const -{ - LOG_FUNC_ENTRY(); - - return(m_chunk_map.find(CT_COLON) != m_chunk_map.cend()); -} // EnumStructUnionParser::inheritance_detected - - -void EnumStructUnionParser::initialize(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - parse_error_detected(false); - m_chunk_map.clear(); - - m_start = pc; - m_type = nullptr; - pc = try_find_end_chunk(pc); - m_end = refine_end_chunk(pc); -} // EnumStructUnionParser::initialize - - -bool EnumStructUnionParser::is_potential_end_chunk(chunk_t *pc) const -{ - LOG_FUNC_ENTRY(); - - /** - * test for a semicolon or closing brace at the level of the starting chunk - */ - if ( pc == nullptr - || parse_error_detected() - || ( ( chunk_is_semicolon(pc) - || chunk_is_token(pc, CT_BRACE_CLOSE)) - && pc->level == m_start->level)) - { - return(true); - } - /** - * check for the following: - * 1) did we encounter a closing paren, which may indicate the end of cast? - * 2) did we cross a preprocessor boundary? - * 3) did we cross the closing paren of a function signature? - */ - - auto const pc_in_funcdef = pc->flags & PCF_IN_FCN_DEF; - auto const pc_in_preproc = pc->flags & PCF_IN_PREPROC; - auto const start_in_funcdef = m_start->flags & PCF_IN_FCN_DEF; - auto const start_in_preproc = m_start->flags & PCF_IN_PREPROC; - - /** - * the following may identify cases where we've reached the - * end of a cast terminated by a closing paren - */ - if ( ( chunk_is_token(pc, CT_PAREN_CLOSE) - && pc->level < m_start->level) - || (start_in_funcdef ^ pc_in_funcdef).test_any() - || (start_in_preproc ^ pc_in_preproc).test_any()) - { - return(true); - } - /** - * check whether the current chunk's nest level is less than that - * of the starting chunk - */ - - std::size_t pc_template_nest = get_cpp_template_angle_nest_level(pc); - std::size_t start_template_nest = get_cpp_template_angle_nest_level(m_start); - - if (start_template_nest > pc_template_nest) - { - return(true); - } - /** - * assuming the chunk is within a function call/definition, check the following: - * 1) chunk is a closing function paren at a lower level than the starting chunk - * 2) chunk is an assignment ('=') or comma at the level of the starting chunk - */ - - auto const pc_in_funccall = pc->flags & PCF_IN_FCN_CALL; - auto const start_in_funccall = m_start->flags & PCF_IN_FCN_CALL; - - if ( ( pc_in_funccall.test_any() - && start_in_funccall.test_any() - && chunk_is_token(pc, CT_COMMA) - && pc->level == m_start->level) - || ( pc_in_funcdef.test_any() - && ( ( chunk_is_token(pc, CT_FPAREN_CLOSE) - && pc->level < m_start->level) - || ( ( chunk_is_token(pc, CT_ASSIGN) - || chunk_is_token(pc, CT_COMMA)) - && pc->level == m_start->level)))) - { - return(true); - } - return(false); -} // EnumStructUnionParser::is_potential_end_chunk - - -bool EnumStructUnionParser::is_within_conditional(chunk_t *pc) const -{ - LOG_FUNC_ENTRY(); - - auto question_operators = get_question_operators(); - - if (!question_operators.empty()) - { - auto &&it_token_chunk_pair = question_operators.cbegin(); - - while (it_token_chunk_pair != question_operators.cend()) - { - auto *question = it_token_chunk_pair->second; - auto *end = skip_to_expression_end(question); - auto *start = skip_to_expression_start(question); - - if (chunk_is_between(pc, start, end)) - { - return(true); - } - ++it_token_chunk_pair; - } - } - return(false); -} // EnumStructUnionParser::is_within_conditional - - -bool EnumStructUnionParser::is_within_inheritance_list(chunk_t *pc) const -{ - LOG_FUNC_ENTRY(); - - if ( pc != nullptr - && pc->flags.test(PCF_IN_CLASS_BASE)) - { - return(true); - } - auto *inheritance_end = get_inheritance_end(); - auto *inheritance_start = get_inheritance_start(); - - if ( inheritance_end != nullptr - && inheritance_start != nullptr) - { - return(chunk_is_between(pc, inheritance_start, inheritance_end)); - } - return(false); -} // EnumStructUnionParser::is_within_inheritance_list - - -bool EnumStructUnionParser::is_within_where_clause(chunk_t *pc) const -{ - LOG_FUNC_ENTRY(); - - if ( pc != nullptr - && pc->flags.test(PCF_IN_WHERE_SPEC)) - { - return(true); - } - auto *where_end = get_where_end(); - auto *where_start = get_where_start(); - - if ( where_end != nullptr - && where_start != nullptr) - { - return(chunk_is_between(pc, where_start, where_end)); - } - return(false); -} // EnumStructUnionParser::is_within_where_clause - - -void EnumStructUnionParser::mark_base_classes(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - pcf_flags_t flags = PCF_VAR_1ST_DEF; - - while (pc != nullptr) - { - chunk_flags_set(pc, PCF_IN_CLASS_BASE); - /** - * clear the PCF_VAR_TYPE flag for all chunks within the inheritance list - * TODO: this may not be necessary in the future once code outside this - * class is improved such that PCF_VAR_TYPE is not set for these chunks - */ - pc->flags &= ~PCF_VAR_TYPE; - - chunk_t *next = chunk_get_next_ncnnl(pc, scope_e::PREPROC); - - if (chunk_is_token(next, CT_DC_MEMBER)) - { - /** - * just in case it's a templated type - */ - pc = skip_template_prev(pc); - - if (chunk_is_token(pc, CT_WORD)) - { - /** - * TODO: - * To comply with conventions used elsewhere in the code, we're going - * to change chunks marked CT_WORD to CT_TYPE if followed by a scope- - * resolution operator; if a chunk marked CT_WORD is followed by a set - * of angle brackets, then it's obviously a templated type. However, - * in the absence of a pair trailing angle brackets, the chunk may be - * a namespace rather than a type. Need to revisit this! - */ - set_chunk_type(pc, CT_TYPE); - } - } - else if ( ( chunk_is_token(next, CT_BRACE_OPEN) - || ( chunk_is_token(next, CT_COMMA) - && !is_within_where_clause(next))) - && next->level == m_start->level) - { - /** - * just in case it's a templated type - */ - pc = skip_template_prev(pc); - - if (chunk_is_token(pc, CT_WORD)) - { - chunk_flags_set(pc, flags); - - if (flags & PCF_VAR_1ST) - { - flags &= ~PCF_VAR_1ST; // clear the first flag for the next items - } - } - - if (chunk_is_token(next, CT_BRACE_OPEN)) - { - break; - } - } - pc = next; - } - chunk_flags_set(pc, PCF_IN_CLASS_BASE); -} // EnumStructUnionParser::mark_base_classes - - -void EnumStructUnionParser::mark_braces(chunk_t *brace_open) -{ - LOG_FUNC_ENTRY(); - - pcf_flags_t flags = PCF_NONE; - - if (chunk_is_token(m_start, CT_CLASS)) - { - flags = PCF_IN_CLASS; - } - else if (chunk_is_enum(m_start)) - { - flags = PCF_IN_ENUM; - } - else if (chunk_is_token(m_start, CT_STRUCT)) - { - flags = PCF_IN_STRUCT; - } - /** - * TODO: why does flag_parens() flag the closing paren, - * but it doesn't flag the opening paren? - */ - - flag_parens(brace_open, - flags, - CT_NONE, - CT_NONE, - false); - - if (chunk_is_class_struct_union(m_start)) - { - mark_struct_union_body(brace_open); - - auto *inheritance_start = get_inheritance_start(); - - if (inheritance_start != nullptr) - { - /** - * the class/struct/union is a derived class; mark the base - * classes between the colon/java "implements" keyword and the - * opening brace - */ - - mark_base_classes(inheritance_start); - } - } - set_chunk_parent(brace_open, m_start->type); - - auto *brace_close = chunk_skip_to_match(brace_open, scope_e::PREPROC); - - if (brace_close != nullptr) - { - set_chunk_parent(brace_close, m_start->type); - } -} // EnumStructUnionParser::mark_braces - - -void EnumStructUnionParser::mark_class_colon(chunk_t *colon) -{ - LOG_FUNC_ENTRY(); - - LOG_FMT(LFTOR, - "%s(%d): Class colon detected: orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - colon->orig_line, - colon->orig_col); - - set_chunk_type(colon, CT_CLASS_COLON); - set_chunk_parent(colon, m_start->type); -} // EnumStructUnionParser::mark_class_colon - - -void EnumStructUnionParser::mark_conditional_colon(chunk_t *colon) -{ - set_chunk_type(colon, CT_COND_COLON); -} // EnumStructUnionParser::mark_conditional_colon - - -void EnumStructUnionParser::mark_constructors() -{ - LOG_FUNC_ENTRY(); - - /** - * if a type was previously identified, then look for - * class/struct constructors in the body - */ - if ( body_detected() - && type_identified() - && chunk_is_class_or_struct(m_start)) - { - LOG_FMT(LFTOR, - "%s(%d): orig_line is %zu, orig_col is %zu, start is '%s', parent_type is %s\n", - __unqualified_func__, - __LINE__, - m_start->orig_line, - m_start->orig_col, - m_start->text(), - get_token_name(get_chunk_parent_type(m_start))); - - log_pcf_flags(LFTOR, m_start->flags); - - /** - * get the name of the type - */ - auto *body_end = get_body_end(); - auto *body_start = get_body_start(); - auto *name = m_type->text(); - - LOG_FMT(LFTOR, - "%s(%d): Name of type is '%s'\n", - __unqualified_func__, - __LINE__, - name); - log_pcf_flags(LFTOR, m_type->flags); - - chunk_t *next = nullptr; - std::size_t level = m_type->brace_level + 1; - - for (auto *prev = body_start; next != body_end; prev = next) - { - chunk_flags_set(prev, PCF_IN_CLASS); - - next = chunk_get_next_ncnnl(prev, scope_e::PREPROC); - - /** - * find a chunk within the class/struct body that - */ - if ( prev != nullptr - && std::strcmp(prev->text(), name) == 0 - && prev->level == level - && chunk_is_paren_open(next)) - { - set_chunk_type(prev, CT_FUNC_CLASS_DEF); - - LOG_FMT(LFTOR, - "%s(%d): Constructor/destructor detected: '%s' at orig_line is %zu, orig_col is %zu, type is %s\n", - __unqualified_func__, - __LINE__, - name, - prev->orig_line, - prev->orig_col, - get_token_name(prev->type)); - - mark_cpp_constructor(prev); - } - } - - chunk_flags_set(next, PCF_IN_CLASS); - } -} // EnumStructUnionParser::mark_constructor - - -void EnumStructUnionParser::mark_enum_integral_type(chunk_t *colon) -{ - LOG_FUNC_ENTRY(); - - set_chunk_type(colon, CT_BIT_COLON); - set_chunk_parent(colon, m_start->type); - - auto *body_start = get_body_start(); - auto *pc = chunk_get_next_ncnnl(colon); - - /** - * the chunk(s) between the colon and opening - * brace (if present) should specify the enum's - * integral type - */ - - while ( chunk_is_between(pc, m_start, m_end) - && pc != body_start - && chunk_is_not_token(pc, CT_BRACE_OPEN) - && !chunk_is_semicolon(pc)) - { - /** - * clear the PCF_VAR_TYPE flag for all chunks within the enum integral base - * TODO: this may not be necessary in the future once code outside this - * class is improved such that PCF_VAR_TYPE is not set for these chunks - */ - pc->flags &= ~PCF_VAR_TYPE; - - set_chunk_type(pc, CT_TYPE); - set_chunk_parent(pc, colon->type); - - pc = chunk_get_next_ncnnl(pc); - } -} // EnumStructUnionParser::mark_enum_integral_type - - -void EnumStructUnionParser::mark_extracorporeal_lvalues() -{ - /** - * clear the PCF_LVALUE flag for all chunks outside the body definition, - * as this flag may have been set elsewhere by code outside this class - * TODO: the mark_lvalue() function needs some improvement so that the - * following isn't necessary - */ - chunk_t *next = m_start; - chunk_t *prev = nullptr; - - /** - * if the class is a template, go the extra step and correct the - * erroneously marked chunks - as previously mentioned, this likely - * won't be necessary with improvements to the mark_lvalue() function - */ - if (get_chunk_parent_type(next) == CT_TEMPLATE) - { - while (true) - { - prev = chunk_get_prev_ncnnlni(next); - - if ( prev == nullptr - || ( !prev->flags.test(PCF_IN_TEMPLATE) - && chunk_is_not_token(prev, CT_TEMPLATE))) - { - break; - } - next = prev; - } - } - auto *body_end = get_body_end(); - auto *body_start = get_body_start(); - - while (next != m_end) - { - if ( !chunk_is_between(next, body_start, body_end) - && next->flags.test(PCF_LVALUE)) - { - next->flags &= ~PCF_LVALUE; - } - else if ( ( chunk_is_token(next, CT_ASSIGN) - || chunk_is_token(next, CT_BRACE_OPEN)) - && chunk_is_token(prev, CT_WORD) - && prev->flags.test_any(PCF_VAR_DEF | PCF_VAR_1ST | PCF_VAR_INLINE)) - { - chunk_flags_set(prev, PCF_LVALUE); - } - prev = next; - next = chunk_get_next_ncnnl(next); - } -} // EnumStructUnionParser::mark_extracorporeal_lavlues - - -void EnumStructUnionParser::mark_nested_name_specifiers(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - auto start_end_pair = match_qualified_identifier(pc); - auto start = start_end_pair.first; - auto end = start_end_pair.second; - - for (pc = start; chunk_is_between(pc, start, end); pc = chunk_get_next_ncnnl(pc)) - { - if (chunk_is_token(pc, CT_WORD)) - { - /** - * if the next token is an opening angle, then we can safely - * mark the current identifier as a type - */ - auto *next = chunk_get_next_ncnnl(pc); - - if (chunk_is_token(next, CT_ANGLE_OPEN)) - { - /** - * the template may have already been previously marked elsewhere... - */ - auto *angle_open = next; - auto *angle_close = chunk_skip_to_match(angle_open, scope_e::PREPROC); - - if (angle_close == nullptr) - { - // parse error - parse_error_detected(true); - - // TODO: should this be just a warning or an error (with exit condition?) - LOG_FMT(LWARN, - "%s(%d): Unmatched '<' at orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - angle_open->orig_line, - angle_open->orig_col); - - break; - } - set_chunk_type(pc, CT_TYPE); - mark_template(next); - pc = angle_close; - } - else if ( is_within_inheritance_list(pc) - && ( chunk_is_token(next, CT_COMMA) - || chunk_is_token(next, CT_BRACE_OPEN))) - { - set_chunk_type(pc, CT_TYPE); - } - } - } -} // EnumStructUnionParser::mark_nested_name_specifiers - - -void EnumStructUnionParser::mark_pointer_types(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(pc, CT_WORD)) - { - do - { - // TODO: should there be a CT_BYREF_TYPE? - pc = chunk_get_prev_ncnnlni(pc); - - if (chunk_is_ptr_operator(pc)) - { - set_chunk_parent(pc, m_start->type); - set_chunk_type(pc, CT_PTR_TYPE); - } - } while (chunk_is_pointer_reference_or_qualifier(pc)); - } -} // EnumStructUnionParser::mark_pointer_types - - -void EnumStructUnionParser::mark_template(chunk_t *start) const -{ - LOG_FUNC_ENTRY(); - - if (start != nullptr) - { - LOG_FMT(LTEMPL, - "%s(%d): Template detected: '%s' at orig_line %zu, orig_col %zu\n", - __unqualified_func__, - __LINE__, - start->text(), - start->orig_line, - start->orig_col); - } - set_chunk_parent(start, CT_TEMPLATE); - - auto *end = chunk_skip_to_match(start, scope_e::PREPROC); - - if (end != nullptr) - { - set_chunk_parent(end, CT_TEMPLATE); - - mark_template_args(start, end); - } -} // EnumStructUnionParser::mark_template - - -void EnumStructUnionParser::mark_template_args(chunk_t *start, chunk_t *end) const -{ - LOG_FUNC_ENTRY(); - - if ( end != nullptr - && start != nullptr) - { - LOG_FMT(LTEMPL, - "%s(%d): Start of template detected: '%s' at orig_line %zu, orig_col %zu\n", - __unqualified_func__, - __LINE__, - start->text(), - start->orig_line, - start->orig_col); - - pcf_flags_t flags = PCF_IN_TEMPLATE; - chunk_t *next = start; - - /** - * TODO: for now, just mark the chunks within the template as PCF_IN_TEMPLATE; - * we probably need to create a TemplateParser class to handle all - * things template-related - */ - - while (true) - { - next = chunk_get_next_ncnnl(next); - - if (next == end) - { - break; - } - chunk_flags_set(next, flags); - } - LOG_FMT(LTEMPL, - "%s(%d): End of template detected: '%s' at orig_line %zu, orig_col %zu\n", - __unqualified_func__, - __LINE__, - end->text(), - end->orig_line, - end->orig_col); - } -} // EnumStructUnionParser::mark_template_args - - -void EnumStructUnionParser::mark_type(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - if (pc != nullptr) - { - m_type = pc; - - do - { - make_type(pc); - set_chunk_parent(pc, m_start->type); - pc = chunk_get_next_ncnnl(pc, scope_e::PREPROC); - } while (chunk_is_pointer_or_reference(pc)); - } -} // EnumStructUnionParser::mark_type - - -void EnumStructUnionParser::mark_variable(chunk_t *variable, pcf_flags_t flags) -{ - LOG_FUNC_ENTRY(); - - if (variable != nullptr) - { - LOG_FMT(LVARDEF, - "%s(%d): Variable definition detected: '%s' at orig_line is %zu, orig_col is %zu, set %s\n", - __unqualified_func__, - __LINE__, - variable->text(), - variable->orig_line, - variable->orig_col, - flags & PCF_VAR_1ST_DEF ? "PCF_VAR_1ST_DEF" : "PCF_VAR_1ST"); - - chunk_flags_set(variable, flags); - set_chunk_type(variable, CT_WORD); - mark_pointer_types(variable); - } -} // EnumStructUnionParser::mark_variable - - -void EnumStructUnionParser::mark_where_clause(chunk_t *where) -{ - LOG_FUNC_ENTRY(); - - if (where != nullptr) - { - LOG_FMT(LFTOR, - "%s(%d): Where clause detected: orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - where->orig_line, - where->orig_col); - } - set_where_start(where); - - auto *where_end = get_where_end(); - auto *where_start = get_where_start(); - - set_where_end(where_end); - - pcf_flags_t flags; - - for (auto *pc = where_start; pc != where_end; pc = chunk_get_next_ncnnl(pc)) - { - flags = mark_where_chunk(pc, m_start->type, flags); - } -} // EnumStructUnionParser::mark_where_clause - - -void EnumStructUnionParser::mark_where_colon(chunk_t *colon) -{ - LOG_FUNC_ENTRY(); - - if (colon != nullptr) - { - LOG_FMT(LFTOR, - "%s(%d): Where colon detected: orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - colon->orig_line, - colon->orig_col); - } - set_chunk_type(colon, CT_WHERE_COLON); - set_chunk_parent(colon, m_start->type); -} // EnumStructUnionParser::mark_where_colon - - -void EnumStructUnionParser::parse(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - initialize(pc); - - /** - * make sure this wasn't a cast, and also make sure we're - * actually dealing with a class/enum/struct/union type - */ - if ( get_chunk_parent_type(m_start) == CT_C_CAST - || !chunk_is_class_enum_struct_union(m_start)) - { - return; - } - chunk_t *prev = m_start; - chunk_t *next = chunk_get_next_ncnnl(prev); - - /** - * the enum-key might be enum, enum class or enum struct - */ - if (chunk_is_enum(next)) - { - prev = next; - next = chunk_get_next_ncnnl(prev); - } - else if (chunk_is_enum(prev)) - { - auto *prev_prev = chunk_get_prev_ncnnlni(prev); - - if ( chunk_is_enum(prev_prev) - && chunk_is_enum(prev)) - { - m_start = prev_prev; - } - } - /** - * pre-process all chunks between the starting and ending chunks identified - * in the initial pass - */ - - while (chunk_is_between(next, m_start, m_end)) - { - /** - * skip attributes - */ - next = skip_attribute(next); - - /** - * skip declspec - */ - next = skip_declspec(next); - - /** - * skip any right-hand side assignments - */ - if (chunk_is_token(next, CT_ASSIGN)) - { - next = skip_to_expression_end(next); - } - - if ( chunk_is_token(next, CT_ANGLE_OPEN) - && !template_detected()) - { - next = parse_angles(next); - } - else if ( chunk_is_token(next, CT_BRACE_OPEN) - && !body_detected()) - { - next = parse_braces(next); - } - else if (chunk_is_colon(next)) - { - parse_colon(next); - } - else if (chunk_is_token(next, CT_COMMA)) - { - record_top_level_comma(next); - } - else if (chunk_is_token(next, CT_DC_MEMBER)) - { - next = parse_double_colon(next); - } - else if ( chunk_is_paren_open(next) - && ( language_is_set(LANG_D) - || ( language_is_set(LANG_PAWN) - && chunk_is_enum(m_start)))) - { - set_paren_parent(next, m_start->type); - - if ( chunk_is_token(prev, CT_WORD) - && language_is_set(LANG_D)) - { - mark_template(next); - } - next = chunk_skip_to_match(next, scope_e::PREPROC); - } - else if ( chunk_is_token(next, CT_QUALIFIER) - && language_is_set(LANG_JAVA) - && std::strncmp(next->str.c_str(), "implements", 10) == 0) - { - mark_base_classes(next); - } - else if (chunk_is_token(next, CT_QUESTION)) - { - record_question_operator(next); - } - else if ( chunk_is_token(next, CT_WHERE) - && !where_clause_detected()) - { - mark_where_clause(next); - } - prev = next; - - do - { - next = chunk_get_next_ncnnl(next); - } while ( next != nullptr - && next->level > m_start->level); - } - /** - * identify the type and/or variable(s) - */ - analyze_identifiers(); - - /** - * identify and mark lvalues occurring outside the body definition - */ - mark_extracorporeal_lvalues(); - - if ( prev != nullptr - && chunk_is_semicolon(prev) - && prev->level == m_start->level - && !prev->flags.test(PCF_IN_FOR)) - { - set_chunk_parent(prev, m_start->type); - } -} // EnumStructUnionParser::parse - - -chunk_t *EnumStructUnionParser::parse_angles(chunk_t *angle_open) -{ - LOG_FUNC_ENTRY(); - - /** - * first check to see if the open angle occurs within an inheritance list - */ - auto *pc = angle_open; - - if (!is_within_inheritance_list(pc)) - { - /** - * check to see if there's a matching closing angle bracket - */ - auto *angle_close = chunk_skip_to_match(angle_open, scope_e::PREPROC); - - if (angle_close == nullptr) - { - // parse error - parse_error_detected(true); - - // TODO: should this be just a warning or an error (with exit condition?) - LOG_FMT(LWARN, - "%s(%d): Unmatched '<' at orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - angle_open->orig_line, - angle_open->orig_col); - } - else - { - /** - * check to make sure that the template is the final chunk in a list - * of scope-resolution qualifications - */ - auto *next = chunk_get_next_ncnnl(angle_close); - - if (chunk_is_not_token(next, CT_DC_MEMBER)) - { - set_template_start(angle_open); - - /** - * we could be dealing with a template type; if so, the opening angle - * bracket should be preceded by a CT_WORD token and we should have - * found a closing angle bracket - */ - auto *prev = chunk_get_prev_ncnnlni(angle_open); - - if (chunk_is_not_token(prev, CT_WORD)) - { - // parse error - parse_error_detected(true); - - // TODO: should this be just a warning or an error (with exit condition?) - LOG_FMT(LWARN, - "%s(%d): Identifier missing before '<' at orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - angle_open->orig_line, - angle_open->orig_col); - } - else - { - set_template_end(angle_close); - mark_template(angle_open); - } - } - /** - * update input argument to point to the closing angle bracket - */ - pc = angle_close; - } - } - return(pc); -} // EnumStructUnionParser::parse_angles - - -chunk_t *EnumStructUnionParser::parse_braces(chunk_t *brace_open) -{ - LOG_FUNC_ENTRY(); - - /** - * check to see if there's a matching closing brace - */ - - auto *pc = brace_open; - auto *brace_close = chunk_skip_to_match(pc, scope_e::PREPROC); - - if (brace_close != nullptr) - { - /** - * we could be dealing with a variable definition preceded by - * the class/struct keyword. It's possible that the variable is - * assigned via direct-list initialization, hence the open brace - * is NOT part of a class/struct type definition. - */ - auto *first_comma = get_first_top_level_comma(); - - if (chunk_is_after(pc, first_comma)) - { - /** - * the open brace occurs after a top-level comma was encountered, which - * likely implies a direct-initialization or braced initializer list in - * the midst of a list of variable definitions - */ - - return(pc); - } - set_body_end(brace_close); - set_body_start(brace_open); - - auto *enum_base_start = get_enum_base_start(); - auto *inheritance_start = get_inheritance_start(); - auto *prev = chunk_get_prev_ncnnlni(pc); - - /** - * check to see if the open brace was preceded by a closing paren; - * it could possibly be a function-like macro call preceding the - * open brace, but it's more likely that we're dealing with a - * signature associated with a function definition - */ - - if ( language_is_set(LANG_D) - || language_is_set(LANG_PAWN) - || !chunk_is_paren_close(prev) - || chunk_is_between(prev, enum_base_start, brace_open) - || chunk_is_between(prev, inheritance_start, brace_open)) - { - mark_braces(brace_open); - - /** - * D does not require a semicolon after an enum, but we add one to make - * other code happy. - */ - if ( language_is_set(LANG_D) - && chunk_is_enum(m_start)) - { - pawn_add_vsemi_after(brace_close); // Issue #2279 - } - pc = brace_close; - } - else - { - // TODO: should this be just a warning or an error (with exit condition?) - LOG_FMT(LWARN, - "%s(%d): Parsing error precedes start of body '{' at orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - brace_open->orig_line, - brace_open->orig_col); - - // parse error - parse_error_detected(true); - } - } - return(pc); -} // EnumStructUnionParser::parse_braces - - -void EnumStructUnionParser::parse_colon(chunk_t *colon) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(m_start, CT_UNION)) - { - /** - * unions do not implement inheritance - */ - - // TODO: should this be just a warning or an error (with exit condition?) - LOG_FMT(LWARN, - "%s(%d): Colon follows union declaration at orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - colon->orig_line, - colon->orig_col); - - // parse error - parse_error_detected(true); - } - else if (is_within_conditional(colon)) - { - mark_conditional_colon(colon); - } - else if (is_within_where_clause(colon)) - { - mark_where_colon(colon); - } - else if (!inheritance_detected()) - { - if (chunk_is_class_or_struct(m_start)) - { - /** - * the colon likely specifies an inheritance list for a struct - * or class type - */ - - set_inheritance_start(colon); - mark_class_colon(colon); - } - else if (chunk_is_enum(m_start)) - { - set_enum_base_start(colon); - mark_enum_integral_type(colon); - } - } -} // EnumStructUnionParser::parse_colon - - -chunk_t *EnumStructUnionParser::parse_double_colon(chunk_t *double_colon) -{ - LOG_FUNC_ENTRY(); - - auto *pc = double_colon; - - if ( language_is_set(LANG_CPP) - && chunk_is_token(pc, CT_DC_MEMBER)) - { - mark_nested_name_specifiers(pc); - pc = skip_scope_resolution_and_nested_name_specifiers(pc); - } - return(pc); -} // EnumStructUnionParser::parse_double_colon - - -bool EnumStructUnionParser::parse_error_detected() const -{ - LOG_FUNC_ENTRY(); - - return(m_parse_error); -} // EnumStructUnionParser::parse_error_detected - - -void EnumStructUnionParser::parse_error_detected(bool status) -{ - LOG_FUNC_ENTRY(); - - m_parse_error = status; -} // EnumStructUnionParser::parse_error_detected - - -void EnumStructUnionParser::record_question_operator(chunk_t *question) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(question, CT_QUESTION)) - { - std::size_t index = m_chunk_map[CT_QUESTION].size(); - - m_chunk_map[CT_QUESTION][index] = question; - } -} // EnumStructUnionParser::record_question_operator - - -void EnumStructUnionParser::record_top_level_comma(chunk_t *comma) -{ - if ( comma != nullptr - && comma->level == m_start->level - && !is_within_conditional(comma) - && !is_within_inheritance_list(comma)) - { - std::size_t index = m_chunk_map[CT_COMMA].size(); - - m_chunk_map[CT_COMMA][index] = comma; - } -} // EnumStructUnionParser::record_top_level_comma - - -chunk_t *EnumStructUnionParser::refine_end_chunk(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - if ( ( language_is_set(LANG_C) - || language_is_set(LANG_CPP)) - && chunk_is_token(pc, CT_BRACE_CLOSE)) - { - /** - * if dealing with C/C++, one or more trailing variable definitions may - * follow the closing brace; a semi-colon should've been good enough to - * indicate the terminating condition, however some of the classes defined - * in the input tests cases for Continuous Integration DO NOT correctly - * terminate classes/struct with a semicolon (which is compilation error). - * As a consequence, more checks must be performed to determine where - * the terminating chunk is located. For instance, see operator.cpp and - * enum_comma.h for examples of offenders - */ - auto *next = chunk_get_next_ncnnl(pc); - - while (true) - { - if (chunk_is_semicolon(next)) - { - pc = next; - - break; - } - else - { - /** - * if we're sitting at a comma, skip it - */ - if (chunk_is_token(next, CT_COMMA)) - { - next = chunk_get_next_ncnnl(next); - } - auto match = match_variable(next, m_start->level); - auto *start = std::get<0>(match); - auto *identifier = std::get<1>(match); - auto *end = std::get<2>(match); - - if ( end == nullptr - || identifier == nullptr - || start == nullptr) - { - break; - } - else - { - pc = chunk_get_next_ncnnl(end); - - /** - * skip any right-hand side assignments - */ - if (chunk_is_token(pc, CT_ASSIGN)) - { - pc = skip_to_expression_end(pc); - } - next = pc; - } - } - } - } - return(pc); -} // EnumStructUnionParser::refine_end_chunk - - -void EnumStructUnionParser::set_body_end(chunk_t *body_end) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(body_end, CT_BRACE_CLOSE)) - { - m_chunk_map[CT_BRACE_CLOSE][0] = body_end; - } -} // EnumStructUnionParser::set_body_end - - -void EnumStructUnionParser::set_body_start(chunk_t *body_start) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(body_start, CT_BRACE_OPEN)) - { - m_chunk_map[CT_BRACE_OPEN][0] = body_start; - } -} // EnumStructUnionParser::set_body_start - - -void EnumStructUnionParser::set_enum_base_start(chunk_t *enum_base_start) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_colon(enum_base_start)) - { - m_chunk_map[CT_BIT_COLON][0] = enum_base_start; - } -} // EnumStructUnionParser::set_enum_base_start - - -void EnumStructUnionParser::set_inheritance_start(chunk_t *inheritance_start) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_colon(inheritance_start)) - { - m_chunk_map[CT_COLON][0] = inheritance_start; - } -} // EnumStructUnionParser::set_inheritance_start - - -void EnumStructUnionParser::set_template_end(chunk_t *template_end) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(template_end, CT_ANGLE_CLOSE)) - { - m_chunk_map[CT_ANGLE_CLOSE][0] = template_end; - } -} // EnumStructUnionParser::set_template_end - - -void EnumStructUnionParser::set_template_start(chunk_t *template_start) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(template_start, CT_ANGLE_OPEN)) - { - m_chunk_map[CT_ANGLE_OPEN][0] = template_start; - } -} // EnumStructUnionParser::set_template_start - - -void EnumStructUnionParser::set_where_end(chunk_t *where_end) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(where_end, CT_BRACE_OPEN)) - { - m_chunk_map[CT_WHERE][0] = where_end; - } -} // EnumStructUnionParser::set_where_end - - -void EnumStructUnionParser::set_where_start(chunk_t *where_start) -{ - LOG_FUNC_ENTRY(); - - if (chunk_is_token(where_start, CT_WHERE)) - { - m_chunk_map[CT_WHERE][0] = where_start; - } -} // EnumStructUnionParser::set_where_start - - -bool EnumStructUnionParser::template_detected() const -{ - LOG_FUNC_ENTRY(); - - auto *template_end = get_template_end(); - auto *template_start = get_template_start(); - - return( template_end != nullptr - && template_start != nullptr); -} // EnumStructUnionParser::template_detected - - -chunk_t *EnumStructUnionParser::try_find_end_chunk(chunk_t *pc) -{ - LOG_FUNC_ENTRY(); - - do - { - /** - * clear some previously marked token types, some of which have likely - * been erroneously marked up to this point; a good example of this - * arises when macro variables and/or macro function calls follow the - * class/enum/struct/union keyword and precede the actual type name - */ - if ( chunk_is_token(pc, CT_TYPE) - || chunk_is_token(pc, CT_WORD)) - { - set_chunk_type(pc, CT_WORD); - set_chunk_parent(pc, CT_NONE); - } - - do - { - pc = chunk_get_next_ncnnl(pc, scope_e::PREPROC); - } while ( pc != nullptr - && pc->level > m_start->level); - } while (!is_potential_end_chunk(pc)); - - /** - * perform a second pass for c++ that - */ - pc = refine_end_chunk(pc); - - return(pc); -} // EnumStructUnionParser::try_find_end_chunk - - -void EnumStructUnionParser::try_post_identify_macro_calls() -{ - LOG_FUNC_ENTRY(); - - if ( language_is_set(LANG_CPP) - && type_identified()) - { - /** - * for all chunks at class/enum/struct/union level, identify function-like - * macro calls and mark them as CT_MACRO_FUNC_CALL. The reason for doing - * so is to avoid mis-interpretation by code executed at a later time - */ - - auto *body_start = get_body_start(); - auto *inheritance_start = get_inheritance_start(); - chunk_t *pc = m_start; - chunk_t *prev = nullptr; - - do - { - if ( !chunk_is_between(prev, inheritance_start, body_start) - && ( chunk_is_token(prev, CT_WORD) - || chunk_is_token(prev, CT_FUNCTION) - || chunk_is_token(prev, CT_FUNC_DEF)) - && !prev->flags.test_any(PCF_VAR_DEF | PCF_VAR_1ST | PCF_VAR_INLINE) - && prev->level == m_start->level) - { - if (chunk_is_paren_open(pc)) - { - auto *paren_open = pc; - auto *paren_close = chunk_skip_to_match(paren_open, scope_e::PREPROC); - - if (paren_close != nullptr) - { - set_chunk_type(paren_open, CT_FPAREN_OPEN); - set_chunk_parent(paren_open, CT_MACRO_FUNC_CALL); - set_chunk_type(paren_close, CT_FPAREN_CLOSE); - set_chunk_parent(paren_close, CT_MACRO_FUNC_CALL); - set_chunk_type(prev, CT_MACRO_FUNC_CALL); - } - } - } - prev = pc; - pc = chunk_get_next_ncnnl(prev); - } while (chunk_is_between(pc, m_start, m_end)); - } -} // EnumStructUnionParser::try_post_identify_macro_calls - - -void EnumStructUnionParser::try_post_identify_type() -{ - LOG_FUNC_ENTRY(); - - chunk_t *body_end = get_body_end(); - - if ( !type_identified() - && body_end == nullptr) - { - /** - * a type wasn't identified and no closing brace is present; we're - * likely not dealing with an anonymous enum/class/struct - */ - - /** - * a type has yet to be identified, so search for the last word - * that hasn't been marked as a variable - */ - chunk_t *type = nullptr; - chunk_t *pc = m_start; - - do - { - /** - * in case it's a qualified identifier, skip scope-resolution and - * nested name specifiers and return just the qualified identifier name - */ - pc = skip_scope_resolution_and_nested_name_specifiers(pc); - - if (pc->flags.test_any(PCF_VAR_DEF | PCF_VAR_1ST | PCF_VAR_INLINE)) - { - break; - } - else if ( chunk_is_token(pc, CT_WORD) - || chunk_is_token(pc, CT_ANGLE_CLOSE)) - { - type = skip_template_prev(pc); - } - pc = chunk_get_next_ncnnl(pc); - } while (chunk_is_between(pc, m_start, m_end)); - - if (type != nullptr) - { - mark_type(type); - } - } -} // EnumStructUnionParser::try_post_identify_type - - -bool EnumStructUnionParser::try_pre_identify_type() -{ - LOG_FUNC_ENTRY(); - - chunk_t *pc = get_body_start(); - - if ( language_is_set(LANG_PAWN) - && chunk_is_enum(m_start)) - { - set_paren_parent(pc, m_start->type); - } - else if (template_detected()) - { - pc = get_template_start(); - } - else if (enum_base_detected()) - { - pc = get_enum_base_start(); - } - else if (inheritance_detected()) - { - pc = get_inheritance_start(); - - if (chunk_is_token(m_start, CT_UNION)) - { - /** - * unions do not implement inheritance - */ - - // TODO: should this be just a warning or an error (with exit condition?) - LOG_FMT(LWARN, - "%s(%d): Bad union declaration detected at orig_line is %zu, orig_col is %zu\n", - __unqualified_func__, - __LINE__, - m_start->orig_line, - m_start->orig_col); - - parse_error_detected(true); - - return(false); - } - } - - if (pc == nullptr) - { - chunk_t *next = chunk_get_next_ncnnl(m_start); - - /** - * in case it's a qualified identifier, skip scope-resolution and - * nested name specifiers and return just the qualified identifier name - */ - next = skip_scope_resolution_and_nested_name_specifiers(next); - - chunk_t *next_next = chunk_get_next_ncnnl(next); - - /** - * in case it's a qualified identifier, skip scope-resolution and - * nested name specifiers and return just the qualified identifier name - */ - next_next = skip_scope_resolution_and_nested_name_specifiers(next_next); - - /** - * if there is one word between the start and end chunks, then we've likely - * identified the type; if there are two words, then the first is likely a - * type and the second is an instantiation thereof; however, it is possible - * that the first word is actually a reference to a macro definition, in which - * the second word would be the type - */ - if (next_next == m_end) - { - pc = next_next; - } - else if ( next != nullptr - && chunk_is_token(next, CT_WORD) - && chunk_is_token(next_next, CT_WORD) - && chunk_get_prev_ncnnlni(m_end) == next_next) - { - /** - * check to see if we've got a macro reference preceding the last word chunk; - * this won't work in all cases, because a macro may be defined in another header - * file, but this is an attempt to increase the chances of identifying the correct - * chunk as the type - */ - if ( chunk_is_macro_reference(next) - || get_chunk_parent_type(m_start) == CT_TEMPLATE) - { - pc = m_end; - } - else - { - pc = next_next; - } - } - else - { - /** - * search for some common patterns that may indicate a type - */ - chunk_t *prev = m_start; - - while ( chunk_is_between(next, m_start, m_end) - && ( ( chunk_is_not_token(next, CT_ASSIGN) - && chunk_is_not_token(next, CT_COMMA)) - || next->level != m_start->level) - && !chunk_is_semicolon(next)) - { - prev = next; - next = chunk_get_next_ncnnl(next); - - /** - * in case it's a qualified identifier, skip scope-resolution and - * nested name specifiers and return just the qualified identifier name - */ - next = skip_scope_resolution_and_nested_name_specifiers(next); - - if ( chunk_is_token(prev, CT_WORD) - && chunk_is_pointer_or_reference(next)) - { - pc = next; - - break; - } - } - } - } - - if (pc != nullptr) - { - /** - * the chunk preceding the previously selected chunk should indicate the type - */ - - pc = chunk_get_prev_ncnnlni(pc, scope_e::PREPROC); - - if ( chunk_is_token(pc, CT_QUALIFIER) - && std::strncmp(pc->str.c_str(), "final", 5) == 0) - { - pc = chunk_get_prev_ncnnlni(pc, scope_e::PREPROC); - } - - if ( language_is_set(LANG_D) - && chunk_is_paren_close(pc)) - { - pc = chunk_skip_to_match_rev(pc); - pc = chunk_get_prev_ncnnlni(pc); - } - - if (chunk_is_token(pc, CT_WORD)) - { - mark_type(pc); - - return(true); - } - } - return(false); -} // EnumStructUnionParser::try_pre_identify_type - - -bool EnumStructUnionParser::type_identified() const -{ - LOG_FUNC_ENTRY(); - - return(m_type != nullptr); -} // EnumStructUnionParser::type_identified - - -/** - * Returns true if a where clause was detected during parsing - */ -bool EnumStructUnionParser::where_clause_detected() const -{ - LOG_FUNC_ENTRY(); - - auto *where_end = get_where_end(); - auto *where_start = get_where_start(); - - return( where_end != nullptr - && where_start != nullptr); -} // EnumStructUnionParser::where_clause_detected |