diff options
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/check_template.cpp')
-rw-r--r-- | debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/check_template.cpp | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/check_template.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/check_template.cpp new file mode 100644 index 00000000..870b3316 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/check_template.cpp @@ -0,0 +1,536 @@ +/** + * @file check_template.cpp + * + * splitted from tokenize_cleanup.cpp + * + * @author Guy Maurel 2022 + * @license GPL v2+ + */ + +#include "tokenize_cleanup.h" + +#include "check_template.h" +#include "chunk.h" +#include "combine.h" +#include "flag_braced_init_list.h" +#include "flag_decltype.h" +#include "prototypes.h" + + +using namespace uncrustify; + + +bool invalid_open_angle_template(Chunk *prev) +{ + if (prev->IsNullChunk()) + { + return(false); + } + // A template requires a word/type right before the open angle + return( prev->IsNot(CT_WORD) + && prev->IsNot(CT_TYPE) + && prev->IsNot(CT_COMMA) + && prev->IsNot(CT_QUALIFIER) + && prev->IsNot(CT_OPERATOR_VAL) + && prev->GetParentType() != CT_OPERATOR); +} + + +Chunk *handle_double_angle_close(Chunk *pc) +{ + Chunk *next = pc->GetNext(); + + if (next->IsNotNullChunk()) + { + if ( pc->Is(CT_ANGLE_CLOSE) + && next->Is(CT_ANGLE_CLOSE) + && pc->GetParentType() == CT_NONE + && (pc->GetOrigColEnd() + 1) == next->GetOrigCol() + && next->GetParentType() == CT_NONE) + { + pc->Str().append('>'); + pc->SetType(CT_SHIFT); + pc->SetOrigColEnd(next->GetOrigColEnd()); + + Chunk *tmp = next->GetNextNcNnl(); + Chunk::Delete(next); + next = tmp; + } + else + { + // bug #663 + pc->SetType(CT_COMPARE); + } + } + return(next); +} + + +void check_template(Chunk *start, bool in_type_cast) +{ + LOG_FMT(LTEMPL, "%s(%d): orig line %zu, orig col %zu:\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol()); + + Chunk *prev = start->GetPrevNcNnl(E_Scope::PREPROC); + + if (prev->IsNullChunk()) + { + return; + } + Chunk *end; + Chunk *pc; + + if (prev->Is(CT_TEMPLATE)) + { + LOG_FMT(LTEMPL, "%s(%d): CT_TEMPLATE:\n", __func__, __LINE__); + + // We have: "template< ... >", which is a template declaration + size_t level = 1; + size_t parens = 0; + + for (pc = start->GetNextNcNnl(E_Scope::PREPROC); + pc->IsNotNullChunk(); + pc = pc->GetNextNcNnl(E_Scope::PREPROC)) + { + LOG_FMT(LTEMPL, "%s(%d): type is %s, level is %zu\n", + __func__, __LINE__, get_token_name(pc->GetType()), level); + + if ( (pc->GetStr()[0] == '>') + && (pc->Len() > 1)) + { + if (pc->GetStr()[1] == '=') // Issue #1462 and #2565 + { + LOG_FMT(LTEMPL, "%s(%d): do not split '%s' at orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + LOG_FMT(LTEMPL, "%s(%d): {split '%s' at orig line %zu, orig col %zu}\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + split_off_angle_close(pc); + } + } + + if (pc->Is(CT_DECLTYPE)) + { + flag_cpp_decltype(pc); + } + else if (pc->Is(CT_PAREN_OPEN)) + { + ++parens; + } + else if (pc->Is(CT_PAREN_CLOSE)) + { + --parens; + } + + if (parens == 0) + { + if (pc->IsString("<")) + { + level++; + } + else if (pc->IsString(">")) + { + if (level == 0) + { + fprintf(stderr, "%s(%d): level is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + level--; + + if (level == 0) + { + break; + } + } + } + } + + end = pc; + } + else + { + /* + * We may have something like "a< ... >", which is a template where + * '...' may consist of anything except a semicolon, unbalanced + * parens, or braces (with one exception being braced initializers + * embedded within decltypes). + * + * For example, braces may be encountered as such in the following + * snippet of valid C++ code: + * + * template<typename T, + * typename = enable_if_t<is_same<typename decay<T>::type, + * decltype (make_index_sequence<5> { })>::value>> + * void foo(T &&arg) + * { + * + * } + * + * Finally, if we are inside an 'if' statement and hit a CT_BOOL, + * then it isn't a template. + */ + + if (invalid_open_angle_template(prev)) + { + LOG_FMT(LTEMPL, "%s(%d): - after type %s + ( - Not a template\n", + __func__, __LINE__, get_token_name(prev->GetType())); + start->SetType(CT_COMPARE); + return; + } + LOG_FMT(LTEMPL, "%s(%d): - prev->GetType() is %s -\n", + __func__, __LINE__, get_token_name(prev->GetType())); + + // Scan back and make sure we aren't inside square parenthesis + bool in_if = false; + bool hit_semicolon = false; + pc = start->GetPrevNcNnl(E_Scope::PREPROC); + + while (pc->IsNotNullChunk()) + { + if ( ( pc->Is(CT_SEMICOLON) + && hit_semicolon) + || pc->Is(CT_SQUARE_CLOSE)) + { + break; + } + + if (pc->Is(CT_DECLTYPE)) + { + flag_cpp_decltype(pc); + } + + if (pc->Is(CT_BRACE_OPEN)) + { + if ( !pc->TestFlags(PCF_IN_DECLTYPE) + || !detect_cpp_braced_init_list(pc->GetPrev(), pc)) + { + break; + } + flag_cpp_braced_init_list(pc->GetPrev(), pc); + } + + if ( pc->Is(CT_BRACE_CLOSE) + && pc->GetParentType() != CT_BRACED_INIT_LIST + && !pc->TestFlags(PCF_IN_DECLTYPE)) + { + break; + } + + if ( pc->Is(CT_SEMICOLON) + && !hit_semicolon) + { + hit_semicolon = true; + } + + if ( ( ( pc->Is(CT_IF) + || pc->Is(CT_RETURN) + || pc->Is(CT_WHILE) + || pc->Is(CT_WHILE_OF_DO)) + && !hit_semicolon) + || ( pc->Is(CT_FOR) + && hit_semicolon)) + { + in_if = true; + break; + } + pc = pc->GetPrevNcNnl(E_Scope::PREPROC); + } + /* + * Scan forward to the angle close + * If we have a comparison in there, then it can't be a template. + */ + const int max_token_count = 1024; + E_Token tokens[max_token_count]; + size_t num_tokens = 1; + + tokens[0] = CT_ANGLE_OPEN; + + for (pc = start->GetNextNcNnl(E_Scope::PREPROC); + pc->IsNotNullChunk(); + pc = pc->GetNextNcNnl(E_Scope::PREPROC)) + { + constexpr static auto LCURRENT = LTEMPL; + + LOG_FMT(LTEMPL, "%s(%d): pc orig line is %zu, orig col is %zu, type is %s, num_tokens is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), num_tokens); + + log_rule_B("tok_split_gte"); + + if (pc->Is(CT_BRACE_OPEN)) // Issue #2886 + { + // look for the closing brace + Chunk *A = pc->GetClosingParen(); + LOG_FMT(LTEMPL, "%s(%d): A orig line is %zu, orig col is %zu, type is %s\n", + __func__, __LINE__, A->GetOrigLine(), A->GetOrigCol(), get_token_name(A->GetType())); + pc = A->GetNext(); + } + + if ( (tokens[num_tokens - 1] == CT_ANGLE_OPEN) + && (pc->GetStr()[0] == '>') + && (pc->Len() > 1) + && ( options::tok_split_gte() + || ( ( pc->IsString(">>") + || pc->IsString(">>>")) + && ( num_tokens >= 2 + || ( num_tokens >= 1 + && in_type_cast))))) + { + LOG_FMT(LTEMPL, "%s(%d): {split '%s' at orig line %zu, orig col %zu}\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + split_off_angle_close(pc); + } + + if (pc->IsString("<")) + { + if ( num_tokens > 0 && (tokens[num_tokens - 1] == CT_PAREN_OPEN) + && invalid_open_angle_template(pc->GetPrev())) + { + pc->SetType(CT_COMPARE); // Issue #3127 + } + else + { + tokens[num_tokens] = CT_ANGLE_OPEN; + num_tokens++; + } + } + else if (pc->IsString(">")) + { + if (num_tokens > 0 && (tokens[num_tokens - 1] == CT_PAREN_OPEN)) + { + handle_double_angle_close(pc); + } + else if (--num_tokens <= 0) + { + break; + } + else if (tokens[num_tokens] != CT_ANGLE_OPEN) + { + break; // unbalanced parentheses + } + } + else if ( in_if + && ( pc->Is(CT_BOOL) + || pc->Is(CT_COMPARE))) + { + break; + } + else if (pc->Is(CT_BRACE_OPEN)) + { + if ( !pc->TestFlags(PCF_IN_DECLTYPE) + || !detect_cpp_braced_init_list(pc->GetPrev(), pc)) + { + break; + } + auto brace_open = pc->GetNextNcNnl(); + auto brace_close = brace_open->GetClosingParen(); + + brace_open->SetParentType(CT_BRACED_INIT_LIST); + brace_close->SetParentType(CT_BRACED_INIT_LIST); + } + else if ( pc->Is(CT_BRACE_CLOSE) + && pc->GetParentType() != CT_BRACED_INIT_LIST + && !pc->TestFlags(PCF_IN_DECLTYPE)) + { + break; + } + else if (pc->Is(CT_SEMICOLON)) + { + break; + } + else if (pc->Is(CT_PAREN_OPEN)) + { + if (num_tokens >= max_token_count - 1) + { + break; + } + tokens[num_tokens] = CT_PAREN_OPEN; + num_tokens++; + } + else if ( pc->Is(CT_QUESTION) // Issue #2949 + && language_is_set(LANG_CPP)) + { + break; + } + else if (pc->Is(CT_PAREN_CLOSE)) + { + if (num_tokens == 0) + { + fprintf(stderr, "%s(%d): num_tokens is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + num_tokens--; + + if (tokens[num_tokens] != CT_PAREN_OPEN) + { + break; // unbalanced parentheses + } + } + } + + end = pc; + } + + if (end->Is(CT_ANGLE_CLOSE)) + { + pc = end->GetNextNcNnl(E_Scope::PREPROC); + + if ( pc->IsNullChunk() + || pc->IsNot(CT_NUMBER)) + { + LOG_FMT(LTEMPL, "%s(%d): Template detected\n", __func__, __LINE__); + LOG_FMT(LTEMPL, "%s(%d): from orig line %zu, orig col %zu\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol()); + LOG_FMT(LTEMPL, "%s(%d): to orig line %zu, orig col %zu\n", + __func__, __LINE__, end->GetOrigLine(), end->GetOrigCol()); + start->SetParentType(CT_TEMPLATE); + + check_template_args(start, end); + + end->SetParentType(CT_TEMPLATE); + end->SetFlagBits(PCF_IN_TEMPLATE); + return; + } + } + LOG_FMT(LTEMPL, "%s(%d): - Not a template: end = %s\n", + __func__, __LINE__, (end->IsNotNullChunk() ? get_token_name(end->GetType()) : "<null>")); + start->SetType(CT_COMPARE); +} // check_template + + +void check_template_arg(Chunk *start, Chunk *end) +{ + LOG_FMT(LTEMPL, "%s(%d): Template argument detected\n", __func__, __LINE__); + LOG_FMT(LTEMPL, "%s(%d): from orig line %zu, orig col %zu\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol()); + LOG_FMT(LTEMPL, "%s(%d): to orig line %zu, orig col %zu\n", + __func__, __LINE__, end->GetOrigLine(), end->GetOrigCol()); + + // Issue #1127 + // MyFoo<mySize * 2> foo1; + // MyFoo<2*mySize * 2> foo1; + // Issue #1346 + // use it as ONE line: + // typename std::enable_if<!std::is_void<T>::value, + // QVector<T> >::type dummy(const std::function<T*(const S&)>& + // pFunc, const QVector<S>& pItems) + // we need two runs + // 1. run to test if expression is numeric + bool expressionIsNumeric = false; + Chunk *pc = start; + + while (pc != end) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + pc->SetFlagBits(PCF_IN_TEMPLATE); + + if ( pc->Is(CT_DECLTYPE) + || pc->Is(CT_SIZEOF)) + { + expressionIsNumeric = true; + break; + } + + if (next->IsNot(CT_PAREN_OPEN)) + { + if ( pc->Is(CT_NUMBER) + || pc->Is(CT_ARITH) + || pc->Is(CT_SHIFT)) + { + expressionIsNumeric = true; + break; + } + } + pc = next; + } + LOG_FMT(LTEMPL, "%s(%d): expressionIsNumeric is %s\n", + __func__, __LINE__, expressionIsNumeric ? "TRUE" : "FALSE"); + + // 2. run to do the work + if (!expressionIsNumeric) + { + pc = start; + + while (pc != end) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + pc->SetFlagBits(PCF_IN_TEMPLATE); + + Chunk *prev = pc->GetPrevNcNnl(E_Scope::PREPROC); + Chunk *prev2 = prev->GetPrevNcNnl(E_Scope::PREPROC); + + if ( prev->Is(CT_ELLIPSIS) // Issue #3309 + && prev2->Is(CT_TYPENAME)) + { + pc->SetType(CT_PARAMETER_PACK); + } + else + { + make_type(pc); + } + pc = next; + } + } +} // check_template_arg + + +void check_template_args(Chunk *start, Chunk *end) +{ + std::vector<E_Token> tokens; + + // Scan for commas + Chunk *pc; + + for (pc = start->GetNextNcNnl(E_Scope::PREPROC); + pc->IsNotNullChunk() && pc != end; + pc = pc->GetNextNcNnl(E_Scope::PREPROC)) + { + switch (pc->GetType()) + { + case CT_COMMA: + + if (tokens.empty()) + { + // Check current argument + check_template_args(start, pc); + start = pc; + } + break; + + case CT_ANGLE_OPEN: + case CT_PAREN_OPEN: + tokens.push_back(pc->GetType()); + break; + + case CT_ANGLE_CLOSE: + + if ( !tokens.empty() + && tokens.back() == CT_ANGLE_OPEN) + { + tokens.pop_back(); + } + break; + + case CT_PAREN_CLOSE: + + if ( !tokens.empty() + && tokens.back() == CT_PAREN_OPEN) + { + tokens.pop_back(); + } + break; + + default: + break; + } + } + + // Check whatever is left + check_template_arg(start, end); +} // check_template_args |